From 5e4257f5c6ee7c35e24be466aaaf193e5a01bd8f Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Thu, 23 Jan 2025 13:35:31 -0800 Subject: [PATCH 01/28] add get rule api logic Signed-off-by: Ruirui Zhang --- .../action/CreateWorkloadGroupAction.java | 2 +- .../action/CreateWorkloadGroupRequest.java | 2 +- .../action/CreateWorkloadGroupResponse.java | 2 +- .../action/DeleteWorkloadGroupAction.java | 2 +- .../action/DeleteWorkloadGroupRequest.java | 2 +- .../action/GetWorkloadGroupAction.java | 2 +- .../action/GetWorkloadGroupRequest.java | 2 +- .../action/GetWorkloadGroupResponse.java | 2 +- .../TransportCreateWorkloadGroupAction.java | 6 +- .../TransportDeleteWorkloadGroupAction.java | 6 +- .../TransportGetWorkloadGroupAction.java | 6 +- .../TransportUpdateWorkloadGroupAction.java | 6 +- .../action/UpdateWorkloadGroupAction.java | 2 +- .../action/UpdateWorkloadGroupRequest.java | 0 .../action/UpdateWorkloadGroupResponse.java | 2 +- .../wlm/querygroup/action/package-info.java | 12 + .../rest/RestCreateWorkloadGroupAction.java | 8 +- .../rest/RestDeleteWorkloadGroupAction.java | 2 +- .../rest/RestGetWorkloadGroupAction.java | 8 +- .../rest/RestUpdateWorkloadGroupAction.java | 8 +- .../wlm/querygroup/rest/package-info.java | 12 + .../wlm/querygroup/service/package-info.java | 12 + .../plugin/wlm/rule/action/GetRuleAction.java | 35 ++ .../wlm/rule/action/GetRuleRequest.java | 75 ++++ .../wlm/rule/action/GetRuleResponse.java | 83 ++++ .../rule/action/TransportGetRuleAction.java | 47 +++ .../{rest => rule/action}/package-info.java | 4 +- .../wlm/rule/rest/RestGetRuleAction.java | 82 ++++ .../{action => rule/rest}/package-info.java | 4 +- .../rule/service/RulePersistenceService.java | 196 ++++++++++ .../wlm/{ => rule}/service/package-info.java | 4 +- .../WorkloadGroupPersistenceService.java | 10 +- .../opensearch/plugin/wlm/RuleTestUtils.java | 83 ++++ .../CreateWorkloadGroupRequestTests.java | 2 +- .../CreateWorkloadGroupResponseTests.java | 2 +- .../DeleteWorkloadGroupRequestTests.java | 2 +- .../action/GetWorkloadGroupRequestTests.java | 2 +- .../action/GetWorkloadGroupResponseTests.java | 2 +- ...ansportDeleteWorkloadGroupActionTests.java | 6 +- .../TransportGetWorkloadGroupActionTests.java | 2 +- .../UpdateWorkloadGroupRequestTests.java | 2 +- .../UpdateWorkloadGroupResponseTests.java | 2 +- .../action/WorkloadGroupActionTestUtils.java | 0 .../RestDeleteWorkloadGroupActionTests.java | 7 +- .../WorkloadGroupPersistenceServiceTests.java | 0 .../wlm/rule/action/GetRuleRequestTests.java | 53 +++ .../wlm/rule/action/GetRuleResponseTests.java | 118 ++++++ .../wlm/rule/rest/RestGetRuleActionTests.java | 35 ++ .../service/RulePersistenceServiceTests.java | 101 +++++ .../main/java/org/opensearch/wlm/Rule.java | 359 ++++++++++++++++++ .../java/org/opensearch/wlm/RuleTests.java | 163 ++++++++ 51 files changed, 1552 insertions(+), 35 deletions(-) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/CreateWorkloadGroupAction.java (94%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/CreateWorkloadGroupRequest.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/CreateWorkloadGroupResponse.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/DeleteWorkloadGroupAction.java (94%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/DeleteWorkloadGroupRequest.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/GetWorkloadGroupAction.java (94%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/GetWorkloadGroupRequest.java (96%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/GetWorkloadGroupResponse.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/TransportCreateWorkloadGroupAction.java (87%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/TransportDeleteWorkloadGroupAction.java (88%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/TransportGetWorkloadGroupAction.java (89%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/TransportUpdateWorkloadGroupAction.java (87%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/UpdateWorkloadGroupAction.java (94%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/UpdateWorkloadGroupRequest.java (100%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/action/UpdateWorkloadGroupResponse.java (97%) create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/package-info.java rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/rest/RestCreateWorkloadGroupAction.java (82%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/rest/RestDeleteWorkloadGroupAction.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/rest/RestGetWorkloadGroupAction.java (80%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => querygroup}/rest/RestUpdateWorkloadGroupAction.java (82%) create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/package-info.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/package-info.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{rest => rule/action}/package-info.java (62%) create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{action => rule/rest}/package-info.java (63%) create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{ => rule}/service/package-info.java (62%) create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/CreateWorkloadGroupRequestTests.java (96%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/CreateWorkloadGroupResponseTests.java (98%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/DeleteWorkloadGroupRequestTests.java (96%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/GetWorkloadGroupRequestTests.java (97%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/GetWorkloadGroupResponseTests.java (99%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/TransportDeleteWorkloadGroupActionTests.java (84%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/TransportGetWorkloadGroupActionTests.java (97%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/UpdateWorkloadGroupRequestTests.java (98%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/UpdateWorkloadGroupResponseTests.java (98%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/action/WorkloadGroupActionTestUtils.java (100%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/rest/RestDeleteWorkloadGroupActionTests.java (88%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{ => querygroup}/service/WorkloadGroupPersistenceServiceTests.java (100%) create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleActionTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java create mode 100644 server/src/main/java/org/opensearch/wlm/Rule.java create mode 100644 server/src/test/java/org/opensearch/wlm/RuleTests.java diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupAction.java index ca9784ebc7e4b..433305f7e9bf6 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.ActionType; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequest.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequest.java index ad932667b25e8..b31cc6f0fb1d2 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponse.java index b33214e042398..d765b3ed14b65 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.core.action.ActionResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupAction.java index 39b47d69776f4..54755758a15a3 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.ActionType; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequest.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequest.java index 940a3815b1662..73a6cc0e1dcd7 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.action.support.clustermanager.AcknowledgedRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupAction.java index ee1b40a2f9bbc..28f35ba2f18b4 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.ActionType; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequest.java similarity index 96% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequest.java index 4b8a5f85fd236..28ab53849824e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.action.support.clustermanager.ClusterManagerNodeReadRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponse.java index ab8f773088a37..22b66bca9ae56 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.core.action.ActionResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java similarity index 87% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java index 2039f1cb590ff..ae401af9769ee 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; @@ -17,7 +17,11 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java similarity index 88% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java index 2bfbadba4d51d..40c82b9c0a56f 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; @@ -19,7 +19,11 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java similarity index 89% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java index bb2fbab047343..ce64e737337cd 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -23,7 +23,11 @@ import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.rest.RestStatus; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.java import org.opensearch.search.pipeline.SearchPipelineService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java similarity index 87% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java index ef639d44b4155..b29896c0a0b1f 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; @@ -17,7 +17,11 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupAction.java index b4f8e1ce90126..6e49008ff2fae 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.ActionType; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequest.java similarity index 100% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequest.java diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponse.java index 9b8fccbdb5346..2f9d543d5b1f9 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.core.action.ActionResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/package-info.java new file mode 100644 index 0000000000000..472b41716b44d --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * Package for the action classes related to query groups in WorkloadManagementPlugin + */ +package org.opensearch.plugin.wlm.querygroup.action; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java similarity index 82% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java index 5ef59602f7893..94d4d82cfbb8e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java @@ -6,14 +6,20 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java index d0d82f43679fa..e3b5b8c30ea3b 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java similarity index 80% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java index 818531352f4d3..50dd7e0ea50db 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java @@ -6,13 +6,19 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.GetWorkloadGroupAction; import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupResponse; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java similarity index 82% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java index db77dc5963037..1294529d857cb 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java @@ -6,14 +6,20 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/package-info.java new file mode 100644 index 0000000000000..a51d67a6cb3b7 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * Package for the rest classes related to query groups in WorkloadManagementPlugin + */ +package org.opensearch.plugin.wlm.querygroup.rest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/package-info.java new file mode 100644 index 0000000000000..3758c9fcd9b81 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * Package for the service classes related to query groups in WorkloadManagementPlugin + */ +package org.opensearch.plugin.wlm.querygroup.service; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java new file mode 100644 index 0000000000000..f334b064acc62 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.action.ActionType; + +/** + * Transport action to get Rule + * @opensearch.experimental + */ +public class GetRuleAction extends ActionType { + + /** + * An instance of GetRuleAction + */ + public static final GetRuleAction INSTANCE = new GetRuleAction(); + + /** + * Name for GetRuleAction + */ + public static final String NAME = "cluster:admin/opensearch/wlm/rule/_get"; + + /** + * Default constructor + */ + private GetRuleAction() { + super(NAME, GetRuleResponse::new); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java new file mode 100644 index 0000000000000..e821007b1d13b --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java @@ -0,0 +1,75 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.wlm.Rule.RuleAttribute; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A request for get Rule + * @opensearch.experimental + */ +public class GetRuleRequest extends ClusterManagerNodeRequest { + private final String _id; + private final Map> attributeFilters; + + /** + * Constructor for GetRuleRequest + * @param _id - Rule _id that we want to get + * @param attributeFilters - Attributes that we want to filter on + */ + public GetRuleRequest(String _id, Map> attributeFilters) { + this._id = _id; + this.attributeFilters = attributeFilters; + } + + /** + * Constructor for GetRuleRequest + * @param in - A {@link StreamInput} object + */ + public GetRuleRequest(StreamInput in) throws IOException { + super(in); + _id = in.readOptionalString(); + attributeFilters = in.readMap((i) -> RuleAttribute.fromName(i.readString()), i -> new HashSet<>(i.readStringList())); + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeOptionalString(_id); + out.writeMap(attributeFilters, RuleAttribute::writeTo, StreamOutput::writeStringCollection); + } + + /** + * _id getter + */ + public String get_id() { + return _id; + } + + /** + * attributeFilters getter + */ + public Map> getAttributeFilters() { + return attributeFilters; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java new file mode 100644 index 0000000000000..b8be558c7e567 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java @@ -0,0 +1,83 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.core.action.ActionResponse; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.ToXContentObject; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.wlm.Rule; + +import java.io.IOException; +import java.util.Map; + +import static org.opensearch.wlm.Rule._ID_STRING; + +/** + * Response for the get API for Rule + * @opensearch.experimental + */ +public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { + private final Map rules; + private final RestStatus restStatus; + + /** + * Constructor for GetRuleResponse + * @param rules - The Map of Rules to be included in the response + * @param restStatus - The restStatus for the response + */ + public GetRuleResponse(final Map rules, RestStatus restStatus) { + this.rules = rules; + this.restStatus = restStatus; + } + + /** + * Constructor for GetRuleResponse + * @param in - A {@link StreamInput} object + */ + public GetRuleResponse(StreamInput in) throws IOException { + this.rules = in.readMap(StreamInput::readString, Rule::new); + this.restStatus = RestStatus.readFrom(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeMap(rules, StreamOutput::writeString, (outStream, rule) -> rule.writeTo(outStream)); + RestStatus.writeTo(out, restStatus); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.startArray("rules"); + for (Map.Entry entry : rules.entrySet()) { + entry.getValue().toXContent(builder, new MapParams(Map.of(_ID_STRING, entry.getKey()))); + } + builder.endArray(); + builder.endObject(); + return builder; + } + + /** + * rules getter + */ + public Map getRules() { + return rules; + } + + /** + * restStatus getter + */ + public RestStatus getRestStatus() { + return restStatus; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java new file mode 100644 index 0000000000000..66b243ff30e64 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.HandledTransportAction; +import org.opensearch.common.inject.Inject; +import org.opensearch.core.action.ActionListener; +import org.opensearch.plugin.wlm.rule.service.RulePersistenceService; +import org.opensearch.tasks.Task; +import org.opensearch.transport.TransportService; + +/** + * Transport action to get Rule + * @opensearch.experimental + */ +public class TransportGetRuleAction extends HandledTransportAction { + + private final RulePersistenceService rulePersistenceService; + + /** + * Constructor for TransportGetRuleAction + * @param transportService - a {@link TransportService} object + * @param actionFilters - a {@link ActionFilters} object + * @param rulePersistenceService - a {@link RulePersistenceService} object + */ + @Inject + public TransportGetRuleAction( + TransportService transportService, + ActionFilters actionFilters, + RulePersistenceService rulePersistenceService + ) { + super(GetRuleAction.NAME, transportService, actionFilters, GetRuleRequest::new); + this.rulePersistenceService = rulePersistenceService; + } + + @Override + protected void doExecute(Task task, GetRuleRequest request, ActionListener listener) { + rulePersistenceService.getRule(request.get_id(), request.getAttributeFilters(), listener); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java similarity index 62% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/package-info.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java index 7d7cb9028fdb8..b9fb278dae5b0 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/package-info.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java @@ -7,6 +7,6 @@ */ /** - * Package for the rest classes of WorkloadManagementPlugin + * Package for the action classes related to rules in WorkloadManagementPlugin */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.rule.action; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java new file mode 100644 index 0000000000000..685fd01f200d5 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java @@ -0,0 +1,82 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.rest; + +import org.opensearch.client.node.NodeClient; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.plugin.wlm.rule.action.GetRuleAction; +import org.opensearch.plugin.wlm.rule.action.GetRuleRequest; +import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestResponse; +import org.opensearch.rest.action.RestResponseListener; +import org.opensearch.wlm.Rule.RuleAttribute; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.rest.RestRequest.Method.GET; +import static org.opensearch.wlm.Rule._ID_STRING; + +/** + * Rest action to get a Rule + * @opensearch.experimental + */ +public class RestGetRuleAction extends BaseRestHandler { + + /** + * Constructor for RestGetRuleAction + */ + public RestGetRuleAction() {} + + @Override + public String getName() { + return "get_rule"; + } + + /** + * The list of {@link Route}s that this RestHandler is responsible for handling. + */ + @Override + public List routes() { + return List.of(new Route(GET, "_wlm/rule/"), new Route(GET, "_wlm/rule/{_id}")); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + final Map> attributeFilters = new HashMap<>(); + for (String attributeName : request.params().keySet()) { + if (attributeName.equals(_ID_STRING)) { + continue; + } + String[] valuesArray = request.param(attributeName).split(","); + attributeFilters.put(RuleAttribute.fromName(attributeName), new HashSet<>(Arrays.asList(valuesArray))); + } + final GetRuleRequest getRuleRequest = new GetRuleRequest(request.param(_ID_STRING), attributeFilters); + return channel -> client.execute(GetRuleAction.INSTANCE, getRuleRequest, getRuleResponse(channel)); + } + + private RestResponseListener getRuleResponse(final RestChannel channel) { + return new RestResponseListener<>(channel) { + @Override + public RestResponse buildResponse(final GetRuleResponse response) throws Exception { + return new BytesRestResponse(RestStatus.OK, response.toXContent(channel.newBuilder(), ToXContent.EMPTY_PARAMS)); + } + }; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java similarity index 63% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/package-info.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java index 9921500df8a81..1d82e4fea71e5 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/package-info.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java @@ -7,6 +7,6 @@ */ /** - * Package for the action classes of WorkloadManagementPlugin + * Package for the rest classes related to rules in WorkloadManagementPlugin */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.rule.rest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java new file mode 100644 index 0000000000000..4d00cb0decd27 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java @@ -0,0 +1,196 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.service; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.get.GetResponse; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.client.Client; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.DeprecationHandler; +import org.opensearch.core.xcontent.MediaTypeRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; +import org.opensearch.wlm.Rule; +import org.opensearch.wlm.Rule.Builder; +import org.opensearch.wlm.Rule.RuleAttribute; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * This class defines the functions for Rule persistence + * @opensearch.experimental + */ +public class RulePersistenceService { + public static final String RULE_INDEX = ".rule"; + private final Client client; + private static final Logger logger = LogManager.getLogger(RulePersistenceService.class); + private static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; + + /** + * Constructor for RulePersistenceService + * @param client {@link Client} - The client to be used by RulePersistenceService + */ + @Inject + public RulePersistenceService(final Client client) { + this.client = client; + } + + /** + * Entry point for the get rule api logic in persistence service. + * @param id - The id of the rule to get. Get all matching rules when id is null + * @param attributeFilters - A map containing the attributes that user want to filter on + * @param listener - ActionListener for GetRuleResponse + */ + public void getRule(String id, Map> attributeFilters, ActionListener listener) { + if (id != null) { + fetchRuleById(id, listener); + } else { + fetchAllRules(attributeFilters, listener); + } + } + + /** + * Fetch a single rule from system index using id + * @param id - The id of the rule to get. + * @param listener - ActionListener for GetRuleResponse + */ + private void fetchRuleById(String id, ActionListener listener) { + ThreadContext.StoredContext storedContext = client.threadPool().getThreadContext().stashContext(); + client.prepareGet(RULE_INDEX, id) + .execute(ActionListener.wrap( + getResponse -> { + try (ThreadContext.StoredContext context = storedContext) { + handleGetOneRuleResponse(id, getResponse, listener); + } + }, + e -> { + try (ThreadContext.StoredContext context = storedContext) { + logger.error("Failed to fetch rule with ID {}: {}", id, e.getMessage()); + listener.onFailure(e); + } + } + )); + } + + /** + * Process getResponse from index and send a GetRuleResponse + * @param id - The id of the rule to get + * @param getResponse - Response received from index + * @param listener - ActionListener for GetRuleResponse + */ + private void handleGetOneRuleResponse(String id, GetResponse getResponse, ActionListener listener) { + if (getResponse.isExists()) { + try (ThreadContext.StoredContext context = client.threadPool().getThreadContext().stashContext()) { + XContentParser parser = MediaTypeRegistry.JSON.xContent() + .createParser( + NamedXContentRegistry.EMPTY, + DeprecationHandler.THROW_UNSUPPORTED_OPERATION, + getResponse.getSourceAsString() + ); + listener.onResponse(new GetRuleResponse(Map.of(id, Builder.fromXContent(parser).build()), RestStatus.OK)); + } catch (IOException e) { + logger.error("Error parsing rule with ID {}: {}", id, e.getMessage()); + listener.onFailure(e); + } + } else { + listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " not found.")); + } + } + + /** + * Fetch all rule from system index based on attributeFilters + * @param attributeFilters - A map containing the attributes that user want to filter on + * @param listener - ActionListener for GetRuleResponse + */ + private void fetchAllRules(Map> attributeFilters, ActionListener listener) { + ThreadContext.StoredContext storedContext = client.threadPool().getThreadContext().stashContext(); + client.prepareSearch(RULE_INDEX) + .setQuery(QueryBuilders.matchAllQuery()) + .setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST) + .execute(ActionListener.wrap( + searchResponse -> { + try (ThreadContext.StoredContext context = storedContext) { + handleGetAllRuleResponse(searchResponse, attributeFilters, listener); + } + }, + e -> { + try (ThreadContext.StoredContext context = storedContext) { + logger.error("Failed to fetch all rules: {}", e.getMessage()); + listener.onFailure(e); + } + } + )); + } + + /** + * Process searchResponse from index and send a GetRuleResponse + * @param searchResponse - Response received from index + * @param attributeFilters - A map containing the attributes that user want to filter on + * @param listener - ActionListener for GetRuleResponse + */ + private void handleGetAllRuleResponse( + SearchResponse searchResponse, + Map> attributeFilters, + ActionListener listener + ) { + Map ruleMap = Arrays.stream(searchResponse.getHits().getHits()).map(hit -> { + try (ThreadContext.StoredContext context = client.threadPool().getThreadContext().stashContext()) { + XContentParser parser = MediaTypeRegistry.JSON.xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, hit.getSourceAsString()); + Rule currRule = Rule.Builder.fromXContent(parser).build(); + if (matchesFilters(currRule, attributeFilters)) { + return Map.entry(hit.getId(), currRule); + } + return null; + } catch (IOException e) { + logger.error("Failed to parse rule from hit: {}", e.getMessage()); + listener.onFailure(e); + return null; + } + }).filter(Objects::nonNull).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + listener.onResponse(new GetRuleResponse(ruleMap, RestStatus.OK)); + } + + /** + * Returns true if the rule matches the attributeFilters and should be included in the response + * @param rule - the rule to be checked against the attribute filters + * @param attributeFilters - A map containing the attributes that user want to filter on + */ + private boolean matchesFilters(Rule rule, Map> attributeFilters) { + for (Map.Entry> entry : attributeFilters.entrySet()) { + RuleAttribute attribute = entry.getKey(); + Set expectedValues = entry.getValue(); + Set ruleValues = rule.getAttributeMap().get(attribute); + if (ruleValues == null || ruleValues.stream().noneMatch(expectedValues::contains)) { + return false; + } + } + return true; + } + + /** + * client getter + */ + public Client getClient() { + return client; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/package-info.java similarity index 62% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/package-info.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/package-info.java index 5848e9c936623..a10b1758d0a58 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/package-info.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/package-info.java @@ -7,6 +7,6 @@ */ /** - * Package for the service classes of WorkloadManagementPlugin + * Package for the service classes related to rules in WorkloadManagementPlugin */ -package org.opensearch.plugin.wlm.service; +package org.opensearch.plugin.wlm.rule.service; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java index 35a7dc7f3219f..acd9fa93b3143 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.service; +package org.opensearch.plugin.wlm.querygroup.service; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -27,11 +27,19 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.action.ActionListener; import org.opensearch.core.rest.RestStatus; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; import org.opensearch.wlm.MutableWorkloadGroupFragment; +======== +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; +import org.opensearch.wlm.MutableQueryGroupFragment; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.java import org.opensearch.wlm.ResourceType; import java.util.Collection; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java new file mode 100644 index 0000000000000..d7ccb01e32e59 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java @@ -0,0 +1,83 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm; + +import org.opensearch.client.Client; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.plugin.wlm.rule.service.RulePersistenceService; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.wlm.Rule; +import org.opensearch.wlm.Rule.RuleAttribute; + +import java.util.Map; +import java.util.Set; + +import static org.opensearch.wlm.Rule.builder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class RuleTestUtils { + public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; + public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; + public static final String LABEL_ONE = "label_one"; + public static final String LABEL_TWO = "label_two"; + public static final String PATTERN_ONE = "pattern_1"; + public static final String PATTERN_TWO = "pattern_2"; + public static final String QUERY_GROUP = "query_group"; + public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; + public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; + public static final Rule ruleOne = builder().feature(QUERY_GROUP) + .label(LABEL_ONE) + .attributeMap(Map.of(RuleAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE))) + .updatedAt(TIMESTAMP_ONE) + .build(); + + public static final Rule ruleTwo = builder().feature(QUERY_GROUP) + .label(LABEL_TWO) + .attributeMap(Map.of(RuleAttribute.INDEX_PATTERN, Set.of(PATTERN_TWO))) + .updatedAt(TIMESTAMP_TWO) + .build(); + + public static Map ruleMap() { + return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); + } + + public static RulePersistenceService setUpRulePersistenceService() { + Client client = mock(Client.class); + ThreadPool threadPool = mock(ThreadPool.class); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + when(client.threadPool()).thenReturn(threadPool); + when(threadPool.getThreadContext()).thenReturn(threadContext); + return new RulePersistenceService(client); + } + + public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { + assertEquals(mapOne.size(), mapTwo.size()); + for (Map.Entry entry : mapOne.entrySet()) { + String id = entry.getKey(); + assertTrue(mapTwo.containsKey(id)); + Rule one = mapOne.get(id); + Rule two = mapTwo.get(id); + assertEqualRule(one, two, ruleUpdated); + } + } + + public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { + if (ruleUpdated) { + assertEquals(one.getFeature(), two.getFeature()); + assertEquals(one.getLabel(), two.getLabel()); + assertEquals(one.getAttributeMap(), two.getAttributeMap()); + } else { + assertEquals(one, two); + } + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java similarity index 96% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java index 31d3ea00b7bda..272f4db09109e 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java index d25050341f997..033e1a67cc012 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java similarity index 96% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java index a7fa0939583c5..2df70252f9f55 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java similarity index 97% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java index 832761d5084bb..52e1880cf9a4a 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java similarity index 99% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java index dc0aeabc7a033..f9d77de883e73 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java similarity index 84% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java index 7ffa33aa8a80a..00aa957371e74 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; @@ -14,7 +14,11 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.action.ActionListener; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.java import org.opensearch.test.OpenSearchTestCase; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java similarity index 97% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java index cf12d9f6408cf..b3aa0dceee78e 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.ResourceNotFoundException; import org.opensearch.action.support.ActionFilters; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java index e8d883da5c6eb..c982d5837d8eb 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java index 97b9b9029373f..ff27c74becc5b 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/WorkloadGroupActionTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/WorkloadGroupActionTestUtils.java similarity index 100% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/WorkloadGroupActionTestUtils.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/WorkloadGroupActionTestUtils.java diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java similarity index 88% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java index 8ce5c869f4481..4269c6d64ab97 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java @@ -6,13 +6,18 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; import org.opensearch.common.CheckedConsumer; import org.opensearch.common.unit.TimeValue; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +======== +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +>>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestHandler; import org.opensearch.rest.RestRequest; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/service/WorkloadGroupPersistenceServiceTests.java similarity index 100% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceServiceTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/service/WorkloadGroupPersistenceServiceTests.java diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java new file mode 100644 index 0000000000000..e9abb281df8b2 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.wlm.Rule; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.plugin.wlm.RuleTestUtils.PATTERN_ONE; +import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; + +public class GetRuleRequestTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of GetRuleRequest + */ + public void testSerialization() throws IOException { + GetRuleRequest request = new GetRuleRequest(_ID_ONE, Map.of(Rule.RuleAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE))); + assertEquals(_ID_ONE, request.get_id()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + GetRuleRequest otherRequest = new GetRuleRequest(streamInput); + assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); + } + + /** + * Test case to verify the serialization and deserialization of GetRuleRequest when name is null + */ + public void testSerializationWithNull() throws IOException { + GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>()); + assertNull(request.get_id()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + GetRuleRequest otherRequest = new GetRuleRequest(streamInput); + assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java new file mode 100644 index 0000000000000..47545e554803e --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java @@ -0,0 +1,118 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.common.xcontent.json.JsonXContent; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.wlm.Rule; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; +import static org.opensearch.plugin.wlm.RuleTestUtils.assertEqualRules; +import static org.opensearch.plugin.wlm.RuleTestUtils.ruleMap; +import static org.opensearch.plugin.wlm.RuleTestUtils.ruleOne; +import static org.mockito.Mockito.mock; + +public class GetRuleResponseTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of GetRuleResponse + */ + public void testSerializationSingleRule() throws IOException { + Map map = new HashMap<>(); + map.put(_ID_ONE, ruleOne); + GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), RestStatus.OK); + assertEquals(response.getRules(), map); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + assertEqualRules(response.getRules(), otherResponse.getRules(), false); + } + + /** + * Test case to verify the serialization and deserialization of GetRuleResponse when the result contains multiple rules + */ + public void testSerializationMultipleRule() throws IOException { + GetRuleResponse response = new GetRuleResponse(ruleMap(), RestStatus.OK); + assertEquals(response.getRules(), ruleMap()); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + assertEquals(2, otherResponse.getRules().size()); + assertEqualRules(response.getRules(), otherResponse.getRules(), false); + } + + /** + * Test case to verify the serialization and deserialization of GetRuleResponse when the result is empty + */ + public void testSerializationNull() throws IOException { + Map map = new HashMap<>(); + GetRuleResponse response = new GetRuleResponse(map, RestStatus.OK); + assertEquals(response.getRules(), map); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + assertEquals(0, otherResponse.getRules().size()); + } + + /** + * Test case to verify the toXContent of GetRuleResponse + */ + public void testToXContentGetSingleRule() throws IOException { + Map map = new HashMap<>(); + map.put(_ID_ONE, ruleOne); + GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), RestStatus.OK); + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + + " \"rules\" : [\n" + + " {\n" + + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + + " \"index_pattern\" : [\n" + + " \"pattern_1\"\n" + + " ],\n" + + " \"query_group\" : \"label_one\",\n" + + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + + " }\n" + + " ]\n" + + "}"; + assertEquals(expected, actual); + } + + /** + * Test case to verify toXContent of GetRuleResponse when the result contains zero Rule + */ + public void testToXContentGetZeroRule() throws IOException { + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + GetRuleResponse otherResponse = new GetRuleResponse(new HashMap<>(), RestStatus.OK); + String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + " \"rules\" : [ ]\n" + "}"; + assertEquals(expected, actual); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleActionTests.java new file mode 100644 index 0000000000000..c09600be6fc6e --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleActionTests.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.rest; + +import org.opensearch.rest.RestHandler; +import org.opensearch.test.OpenSearchTestCase; + +import java.util.List; + +import static org.opensearch.rest.RestRequest.Method.GET; + +public class RestGetRuleActionTests extends OpenSearchTestCase { + /** + * Test case to validate the construction for RestGetRuleAction + */ + public void testConstruction() { + RestGetRuleAction action = new RestGetRuleAction(); + assertNotNull(action); + assertEquals("get_rule", action.getName()); + List routes = action.routes(); + assertEquals(2, routes.size()); + RestHandler.Route route = routes.get(0); + assertEquals(GET, route.getMethod()); + assertEquals("_wlm/rule/", route.getPath()); + route = routes.get(1); + assertEquals(GET, route.getMethod()); + assertEquals("_wlm/rule/{_id}", route.getPath()); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java new file mode 100644 index 0000000000000..fa8225cf3552e --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java @@ -0,0 +1,101 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.service; + +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.get.GetRequestBuilder; +import org.opensearch.action.get.GetResponse; +import org.opensearch.client.Client; +import org.opensearch.common.xcontent.XContentFactory; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.mockito.ArgumentCaptor; + +import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; +import static org.opensearch.plugin.wlm.RuleTestUtils.assertEqualRules; +import static org.opensearch.plugin.wlm.RuleTestUtils.ruleOne; +import static org.opensearch.plugin.wlm.RuleTestUtils.setUpRulePersistenceService; +import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.RULE_INDEX; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@SuppressWarnings("unchecked") +public class RulePersistenceServiceTests extends OpenSearchTestCase { + + /** + * Test case to validate the logic for get Rule by id + */ + public void testGetRuleById() throws IOException { + String ruleSource = ruleOne.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS).toString(); + ActionListener listener = mock(ActionListener.class); + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); + Client client = rulePersistenceService.getClient(); + GetRequestBuilder getRequestBuilder = mock(GetRequestBuilder.class); + GetResponse getResponse = mock(GetResponse.class); + + when(getResponse.isExists()).thenReturn(true); + when(getResponse.getSourceAsString()).thenReturn(ruleSource); + when(client.prepareGet(eq(RULE_INDEX), eq(_ID_ONE))).thenReturn(getRequestBuilder); + doAnswer(invocation -> { + ActionListener actionListener = invocation.getArgument(0); + actionListener.onResponse(getResponse); + return null; + }).when(getRequestBuilder).execute(any(ActionListener.class)); + + rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), listener); + + ArgumentCaptor captor = ArgumentCaptor.forClass(GetRuleResponse.class); + verify(listener).onResponse(captor.capture()); + GetRuleResponse response = captor.getValue(); + assertNotNull(response); + assertEqualRules(Map.of(_ID_ONE, ruleOne), response.getRules(), false); + clearInvocations(client, getRequestBuilder, getResponse, listener); + } + + /** + * Test case to validate the get rule for an invalid id + */ + public void testGetRuleByIdNotFound() { + String nonExistentRuleId = "non-existent-rule"; + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); + Client client = rulePersistenceService.getClient(); + GetRequestBuilder getRequestBuilder = mock(GetRequestBuilder.class); + GetResponse getResponse = mock(GetResponse.class); + ActionListener listener = mock(ActionListener.class); + + when(client.prepareGet(RULE_INDEX, nonExistentRuleId)).thenReturn(getRequestBuilder); + when(getResponse.isExists()).thenReturn(false); + + doAnswer(invocation -> { + ActionListener actionListener = invocation.getArgument(0); + actionListener.onResponse(getResponse); + return null; + }).when(getRequestBuilder).execute(any(ActionListener.class)); + + rulePersistenceService.getRule(nonExistentRuleId, new HashMap<>(), listener); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Exception.class); + verify(listener).onFailure(captor.capture()); + Exception exception = captor.getValue(); + assertTrue(exception instanceof ResourceNotFoundException); + clearInvocations(client, getRequestBuilder, getResponse, listener); + } +} diff --git a/server/src/main/java/org/opensearch/wlm/Rule.java b/server/src/main/java/org/opensearch/wlm/Rule.java new file mode 100644 index 0000000000000..273abc455c7e3 --- /dev/null +++ b/server/src/main/java/org/opensearch/wlm/Rule.java @@ -0,0 +1,359 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.wlm; + +import org.opensearch.common.ValidationException; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.core.common.io.stream.Writeable; +import org.opensearch.core.xcontent.ToXContentObject; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.core.xcontent.XContentParseException; +import org.opensearch.core.xcontent.XContentParser; +import org.joda.time.Instant; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static org.opensearch.cluster.metadata.QueryGroup.isValid; + +/** + * Represents a rule schema used for automatic query tagging in the system. + * This class encapsulates the criteria (defined through attributes) for automatically applying relevant + * tags to queries based on matching attribute patterns. This class provides an in-memory representation + * of a rule. The indexed view may differ in representation. + * { + * "_id": "fwehf8302582mglfio349==", + * "index_pattern": ["logs123", "user*"], + * "query_group": "dev_query_group_id", + * "updated_at": "01-10-2025T21:23:21.456Z" + * } + * @opensearch.experimental + */ +public class Rule implements Writeable, ToXContentObject { + private final Map> attributeMap; + private final Feature feature; + private final String label; + private final String updatedAt; + public static final String _ID_STRING = "_id"; + public static final String UPDATED_AT_STRING = "updated_at"; + public static final int MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE = 10; + public static final int MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING = 100; + + public Rule(Map> attributeMap, String label, String updatedAt, Feature feature) { + ValidationException validationException = new ValidationException(); + validateRuleInputs(attributeMap, label, updatedAt, feature, validationException); + if (!validationException.validationErrors().isEmpty()) { + throw new IllegalArgumentException(validationException); + } + + this.attributeMap = attributeMap; + this.feature = feature; + this.label = label; + this.updatedAt = updatedAt; + } + + public Rule(StreamInput in) throws IOException { + this( + in.readMap((i) -> RuleAttribute.fromName(i.readString()), i -> new HashSet<>(i.readStringList())), + in.readString(), + in.readString(), + Feature.fromName(in.readString()) + ); + } + + public static void requireNonNullOrEmpty(String value, String message, ValidationException validationException) { + if (value == null || value.isEmpty()) { + validationException.addValidationError(message); + } + } + + public static void validateRuleInputs( + Map> attributeMap, + String label, + String updatedAt, + Feature feature, + ValidationException validationException + ) { + if (feature == null) { + validationException.addValidationError("Couldn't identify which feature the rule belongs to. Rule feature name can't be null."); + } + requireNonNullOrEmpty(label, "Rule label can't be null or empty", validationException); + requireNonNullOrEmpty(updatedAt, "Rule update time can't be null or empty", validationException); + if (attributeMap == null || attributeMap.isEmpty()) { + validationException.addValidationError("Rule should have at least 1 attribute requirement"); + } + if (updatedAt != null && !isValid(Instant.parse(updatedAt).getMillis())) { + validationException.addValidationError("Rule update time is not a valid epoch"); + } + if (attributeMap != null && feature != null) { + validateAttributeMap(attributeMap, feature, validationException); + } + } + + public static void validateAttributeMap( + Map> attributeMap, + Feature feature, + ValidationException validationException + ) { + for (Map.Entry> entry : attributeMap.entrySet()) { + RuleAttribute ruleAttribute = entry.getKey(); + Set attributeValues = entry.getValue(); + if (!feature.isValidAttribute(ruleAttribute)) { + validationException.addValidationError( + ruleAttribute.getName() + " is not a valid attribute name under the feature: " + feature.getName() + ); + } + if (attributeValues.size() > MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE) { + validationException.addValidationError( + "Each attribute can only have a maximum of 10 values. The input attribute " + ruleAttribute + " exceeds this limit." + ); + } + for (String attributeValue : attributeValues) { + if (attributeValue.isEmpty() || attributeValue.length() > MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING) { + validationException.addValidationError( + "Attribute value [" + attributeValue + "] is invalid (empty or exceeds 100 characters)" + ); + } + } + } + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeMap(attributeMap, RuleAttribute::writeTo, StreamOutput::writeStringCollection); + out.writeString(label); + out.writeString(updatedAt); + out.writeString(feature.getName()); + } + + public static Rule fromXContent(final XContentParser parser) throws IOException { + return Builder.fromXContent(parser).build(); + } + + public String getLabel() { + return label; + } + + public String getUpdatedAt() { + return updatedAt; + } + + public Feature getFeature() { + return feature; + } + + public Map> getAttributeMap() { + return attributeMap; + } + + /** + * This enum enumerates the features that can use the Rule Based Auto-tagging + * @opensearch.experimental + */ + public enum Feature { + QUERY_GROUP("query_group", Set.of(RuleAttribute.INDEX_PATTERN)); + + private final String name; + private final Set allowedAttributes; + + Feature(String name, Set allowedAttributes) { + this.name = name; + this.allowedAttributes = allowedAttributes; + } + + public String getName() { + return name; + } + + public Set getAllowedAttributes() { + return allowedAttributes; + } + + public boolean isValidAttribute(RuleAttribute attribute) { + return allowedAttributes.contains(attribute); + } + + public static boolean isValidFeature(String s) { + return Arrays.stream(values()).anyMatch(feature -> feature.getName().equalsIgnoreCase(s)); + } + + public static Feature fromName(String s) { + return Arrays.stream(values()) + .filter(feature -> feature.getName().equalsIgnoreCase(s)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Invalid value for Feature: " + s)); + } + } + + /** + * This RuleAttribute enum contains the attribute names for a rule. + * @opensearch.experimental + */ + public enum RuleAttribute { + INDEX_PATTERN("index_pattern"); + + private final String name; + + RuleAttribute(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public static void writeTo(StreamOutput out, RuleAttribute ruleAttribute) throws IOException { + out.writeString(ruleAttribute.getName()); + } + + public static RuleAttribute fromName(String s) { + for (RuleAttribute attribute : values()) { + if (attribute.getName().equalsIgnoreCase(s)) return attribute; + + } + throw new IllegalArgumentException("Invalid value for RuleAttribute: " + s); + } + } + + @Override + public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException { + builder.startObject(); + String id = params.param(_ID_STRING); + if (id != null) { + builder.field(_ID_STRING, id); + } + for (Map.Entry> entry : attributeMap.entrySet()) { + builder.array(entry.getKey().getName(), entry.getValue().toArray(new String[0])); + } + builder.field(feature.getName(), label); + builder.field(UPDATED_AT_STRING, updatedAt); + builder.endObject(); + return builder; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Rule that = (Rule) o; + return Objects.equals(label, that.label) + && Objects.equals(feature, that.feature) + && Objects.equals(attributeMap, that.attributeMap) + && Objects.equals(updatedAt, that.updatedAt); + } + + @Override + public int hashCode() { + return Objects.hash(label, feature, attributeMap, updatedAt); + } + + /** + * builder method for the {@link Rule} + * @return Builder object + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for {@link Rule} + * @opensearch.experimental + */ + public static class Builder { + private Map> attributeMap; + private Feature feature; + private String label; + private String updatedAt; + + private Builder() {} + + public static Builder fromXContent(XContentParser parser) throws IOException { + if (parser.currentToken() == null) { + parser.nextToken(); + } + Builder builder = builder(); + XContentParser.Token token = parser.currentToken(); + + if (token != XContentParser.Token.START_OBJECT) { + throw new IllegalArgumentException("Expected START_OBJECT token but found [" + parser.currentName() + "]"); + } + Map> attributeMap1 = new HashMap<>(); + String fieldName = ""; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + fieldName = parser.currentName(); + } else if (token.isValue()) { + if (Feature.isValidFeature(fieldName)) { + builder.feature(fieldName); + builder.label(parser.text()); + } else if (fieldName.equals(UPDATED_AT_STRING)) { + builder.updatedAt(parser.text()); + } else { + throw new IllegalArgumentException(fieldName + " is not a valid field in Rule"); + } + } else if (token == XContentParser.Token.START_ARRAY) { + fromXContentParseArray(parser, fieldName, attributeMap1); + } + } + return builder.attributeMap(attributeMap1); + } + + public static void fromXContentParseArray(XContentParser parser, String fieldName, Map> attributeMap) + throws IOException { + RuleAttribute ruleAttribute = RuleAttribute.fromName(fieldName); + Set attributeValueSet = new HashSet<>(); + while (parser.nextToken() != XContentParser.Token.END_ARRAY) { + if (parser.currentToken() == XContentParser.Token.VALUE_STRING) { + attributeValueSet.add(parser.text()); + } else { + throw new XContentParseException("Unexpected token in array: " + parser.currentToken()); + } + } + attributeMap.put(ruleAttribute, attributeValueSet); + } + + public Builder label(String label) { + this.label = label; + return this; + } + + public Builder attributeMap(Map> attributeMap) { + this.attributeMap = attributeMap; + return this; + } + + public Builder feature(String feature) { + this.feature = Feature.fromName(feature); + return this; + } + + public Builder updatedAt(String updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + public Rule build() { + return new Rule(attributeMap, label, updatedAt, feature); + } + + public String getLabel() { + return label; + } + + public Map> getAttributeMap() { + return attributeMap; + } + } +} diff --git a/server/src/test/java/org/opensearch/wlm/RuleTests.java b/server/src/test/java/org/opensearch/wlm/RuleTests.java new file mode 100644 index 0000000000000..72a4abf1f3877 --- /dev/null +++ b/server/src/test/java/org/opensearch/wlm/RuleTests.java @@ -0,0 +1,163 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.wlm; + +import org.opensearch.common.xcontent.json.JsonXContent; +import org.opensearch.core.common.io.stream.Writeable; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.test.AbstractSerializingTestCase; +import org.opensearch.wlm.Rule.Feature; +import org.opensearch.wlm.Rule.RuleAttribute; +import org.joda.time.Instant; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.wlm.Rule.MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING; +import static org.opensearch.wlm.Rule.MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE; +import static org.opensearch.wlm.Rule._ID_STRING; + +public class RuleTests extends AbstractSerializingTestCase { + public static final String _ID = "AgfUfjw039vhdONlYi3TQ=="; + public static final String LABEL = "label"; + + static Rule createRandomRule(String label) { + Feature feature = randomFeature(); + return Rule.builder() + .label(label) + .feature(feature.getName()) + .attributeMap(randomAttributeMaps(feature)) + .updatedAt(Instant.now().toString()) + .build(); + } + + private static Feature randomFeature() { + return Feature.values()[randomIntBetween(0, Feature.values().length - 1)]; + } + + private static Map> randomAttributeMaps(Feature feature) { + Map> attributeMap = new HashMap<>(); + if (feature == null) { + return attributeMap; + } + List allowedAttributes = new ArrayList<>(feature.getAllowedAttributes()); + do { + attributeMap.clear(); + for (RuleAttribute currAttribute : allowedAttributes) { + if (randomBoolean()) { + attributeMap.put(currAttribute, randomAttributeValues()); + } + } + } while (attributeMap.isEmpty()); + return attributeMap; + } + + private static Set randomAttributeValues() { + Set res = new HashSet<>(); + int numberOfValues = randomIntBetween(1, MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE); + for (int i = 0; i < numberOfValues; i++) { + res.add(randomAlphaOfLength(randomIntBetween(1, MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING))); + } + return res; + } + + @Override + protected Rule doParseInstance(XContentParser parser) throws IOException { + return Rule.fromXContent(parser); + } + + @Override + protected Writeable.Reader instanceReader() { + return Rule::new; + } + + @Override + protected Rule createTestInstance() { + return createRandomRule(LABEL); + } + + static Rule buildRule(String label, String feature, Map> attributeListMap, String updatedAt) { + return Rule.builder().label(label).feature(feature).attributeMap(attributeListMap).updatedAt(updatedAt).build(); + } + + public void testInvalidFeature() { + assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, null, randomAttributeMaps(null), Instant.now().toString())); + assertThrows( + IllegalArgumentException.class, + () -> buildRule(LABEL, "invalid", randomAttributeMaps(null), Instant.now().toString()) + ); + } + + public void testInvalidLabel() { + assertThrows(IllegalArgumentException.class, () -> createRandomRule(null)); + assertThrows(IllegalArgumentException.class, () -> createRandomRule("")); + } + + public void testInvalidUpdateTime() { + Feature feature = randomFeature(); + assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, feature.toString(), randomAttributeMaps(feature), null)); + } + + public void testNullOrEmptyAttributeMap() { + Feature feature = randomFeature(); + assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, feature.toString(), new HashMap<>(), Instant.now().toString())); + assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, feature.toString(), null, Instant.now().toString())); + } + + public void testInvalidAttributeMap() { + Map> map = new HashMap<>(); + map.put(RuleAttribute.INDEX_PATTERN, Set.of("")); + assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, randomFeature().getName(), map, Instant.now().toString())); + + map.put(RuleAttribute.INDEX_PATTERN, Set.of(randomAlphaOfLength(MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING + 1))); + assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, randomFeature().getName(), map, Instant.now().toString())); + + map.put(RuleAttribute.INDEX_PATTERN, new HashSet<>()); + for (int i = 0; i < MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE + 1; i++) { + map.get(RuleAttribute.INDEX_PATTERN).add(String.valueOf(i)); + } + assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, randomFeature().getName(), map, Instant.now().toString())); + } + + public void testValidRule() { + Map> map = Map.of(RuleAttribute.INDEX_PATTERN, Set.of("index*", "log*")); + String updatedAt = Instant.now().toString(); + Rule rule = buildRule(LABEL, Feature.QUERY_GROUP.getName(), map, updatedAt); + assertNotNull(rule.getLabel()); + assertEquals(LABEL, rule.getLabel()); + assertNotNull(updatedAt); + assertEquals(updatedAt, rule.getUpdatedAt()); + Map> resultMap = rule.getAttributeMap(); + assertNotNull(resultMap); + assertFalse(resultMap.isEmpty()); + assertNotNull(rule.getFeature()); + assertEquals(Feature.QUERY_GROUP, rule.getFeature()); + } + + public void testToXContent() throws IOException { + Map> map = Map.of(RuleAttribute.INDEX_PATTERN, Set.of("log*")); + String updatedAt = Instant.now().toString(); + Rule rule = buildRule(LABEL, Feature.QUERY_GROUP.getName(), map, updatedAt); + + XContentBuilder builder = JsonXContent.contentBuilder(); + rule.toXContent(builder, new ToXContent.MapParams(Map.of(_ID_STRING, _ID))); + + assertEquals( + "{\"_id\":\"" + _ID + "\",\"index_pattern\":[\"log*\"],\"query_group\":\"label\",\"updated_at\":\"" + updatedAt + "\"}", + builder.toString() + ); + } +} From e57f7648dc94f271822a53c53479f78326ced38d Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Tue, 18 Feb 2025 16:58:03 -0800 Subject: [PATCH 02/28] modify based on comments Signed-off-by: Ruirui Zhang --- .../plugin/wlm/WorkloadManagementPlugin.java | 20 +- .../plugin/wlm/rule/QueryGroupAttribute.java | 51 +++ .../wlm/rule/QueryGroupFeatureType.java | 58 +++ .../plugin/wlm/rule/action/GetRuleAction.java | 11 +- .../wlm/rule/action/GetRuleRequest.java | 32 +- .../wlm/rule/action/GetRuleResponse.java | 47 ++- .../rule/action/TransportGetRuleAction.java | 2 +- .../wlm/rule/rest/RestGetRuleAction.java | 18 +- .../rule/service/RulePersistenceService.java | 174 +++++---- .../opensearch/plugin/wlm/RuleTestUtils.java | 47 ++- .../wlm/rule/action/GetRuleRequestTests.java | 7 +- .../wlm/rule/action/GetRuleResponseTests.java | 24 +- .../service/RulePersistenceServiceTests.java | 53 ++- .../main/java/org/opensearch/wlm/Rule.java | 359 ------------------ .../java/org/opensearch/wlm/RuleTests.java | 163 -------- 15 files changed, 393 insertions(+), 673 deletions(-) create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java delete mode 100644 server/src/main/java/org/opensearch/wlm/Rule.java delete mode 100644 server/src/test/java/org/opensearch/wlm/RuleTests.java diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index 85c8cc8409c0f..f92c8a4df80e0 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -18,6 +18,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; import org.opensearch.core.action.ActionResponse; +import org.opensearch.indices.SystemIndexDescriptor; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.GetWorkloadGroupAction; @@ -30,9 +31,13 @@ import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.rest.RestGetWorkloadGroupAction; import org.opensearch.plugin.wlm.rest.RestUpdateWorkloadGroupAction; +import org.opensearch.plugin.wlm.rule.action.GetRuleAction; +import org.opensearch.plugin.wlm.rule.action.TransportGetRuleAction; +import org.opensearch.plugin.wlm.rule.rest.RestGetRuleAction; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; import org.opensearch.plugins.ActionPlugin; import org.opensearch.plugins.Plugin; +import org.opensearch.plugins.SystemIndexPlugin; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; @@ -40,10 +45,12 @@ import java.util.List; import java.util.function.Supplier; +import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.RULES_INDEX; + /** * Plugin class for WorkloadManagement */ -public class WorkloadManagementPlugin extends Plugin implements ActionPlugin { +public class WorkloadManagementPlugin extends Plugin implements ActionPlugin, SystemIndexPlugin { /** * Default constructor @@ -56,10 +63,16 @@ public WorkloadManagementPlugin() {} new ActionPlugin.ActionHandler<>(CreateWorkloadGroupAction.INSTANCE, TransportCreateWorkloadGroupAction.class), new ActionPlugin.ActionHandler<>(GetWorkloadGroupAction.INSTANCE, TransportGetWorkloadGroupAction.class), new ActionPlugin.ActionHandler<>(DeleteWorkloadGroupAction.INSTANCE, TransportDeleteWorkloadGroupAction.class), - new ActionPlugin.ActionHandler<>(UpdateWorkloadGroupAction.INSTANCE, TransportUpdateWorkloadGroupAction.class) + new ActionPlugin.ActionHandler<>(UpdateWorkloadGroupAction.INSTANCE, TransportUpdateWorkloadGroupAction.class), + new ActionPlugin.ActionHandler<>(GetRuleAction.INSTANCE, TransportGetRuleAction.class) ); } + @Override + public Collection getSystemIndexDescriptors(Settings settings) { + return List.of(new SystemIndexDescriptor(RULES_INDEX, "System index used for storing rules")); + } + @Override public List getRestHandlers( Settings settings, @@ -74,7 +87,8 @@ public List getRestHandlers( new RestCreateWorkloadGroupAction(), new RestGetWorkloadGroupAction(), new RestDeleteWorkloadGroupAction(), - new RestUpdateWorkloadGroupAction() + new RestUpdateWorkloadGroupAction(), + new RestGetRuleAction() ); } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java new file mode 100644 index 0000000000000..906b68e37efff --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.AutoTaggingRegistry; + +/** + * Attributes specific to the query group feature. + * @opensearch.experimental + */ +public enum QueryGroupAttribute implements Attribute { + INDEX_PATTERN("index_pattern"); + + private final String name; + + QueryGroupAttribute(String name) { + this.name = name; + } + + static { + for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { + attr.registerAttribute(); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public void registerAttribute() { + AutoTaggingRegistry.registerAttribute(this); + } + + public static QueryGroupAttribute fromName(String name) { + for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { + if (attr.getName().equals(name)) { + return attr; + } + } + throw new IllegalArgumentException("Unknown QueryGroupAttribute: " + name); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java new file mode 100644 index 0000000000000..18e227d23e888 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.AutoTaggingRegistry; +import org.opensearch.autotagging.FeatureType; + +import java.util.Set; + +/** + * Represents the feature type for "query_group" in the OpenSearch workload management plugin. + * @opensearch.experimental + */ +public class QueryGroupFeatureType implements FeatureType { + public static final QueryGroupFeatureType INSTANCE = new QueryGroupFeatureType(); + public static final String NAME = "query_group"; + private static final int MAX_ATTRIBUTE_VALUES = 10; + private static final int MAX_ATTRIBUTE_VALUE_LENGTH = 100; + private static final Set ALLOWED_ATTRIBUTES = Set.of(QueryGroupAttribute.values()); + + private QueryGroupFeatureType() {} + + static { + INSTANCE.registerFeatureType(); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public int getMaxNumberOfValuesPerAttribute() { + return MAX_ATTRIBUTE_VALUES; + } + + @Override + public int getMaxCharLengthPerAttributeValue() { + return MAX_ATTRIBUTE_VALUE_LENGTH; + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + + @Override + public void registerFeatureType() { + AutoTaggingRegistry.registerFeatureType(INSTANCE); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java index f334b064acc62..2ee030576c18e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java @@ -11,24 +11,15 @@ import org.opensearch.action.ActionType; /** - * Transport action to get Rule + * Action type for getting Rules in workload management * @opensearch.experimental */ public class GetRuleAction extends ActionType { - /** - * An instance of GetRuleAction - */ public static final GetRuleAction INSTANCE = new GetRuleAction(); - /** - * Name for GetRuleAction - */ public static final String NAME = "cluster:admin/opensearch/wlm/rule/_get"; - /** - * Default constructor - */ private GetRuleAction() { super(NAME, GetRuleResponse::new); } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java index e821007b1d13b..0f9b4cef43925 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java @@ -8,11 +8,11 @@ package org.opensearch.plugin.wlm.rule.action; +import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; +import org.opensearch.autotagging.Attribute; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.wlm.Rule.RuleAttribute; import java.io.IOException; import java.util.HashSet; @@ -21,20 +21,27 @@ /** * A request for get Rule + * Example Request: + * curl -X GET "localhost:9200/_wlm/rule" - get all rules + * curl -X GET "localhost:9200/_wlm/rule/{_id}" - get single rule by id + * curl -X GET "localhost:9200/_wlm/rule?index_pattern=a,b" - get all rules containing index_pattern as a or b * @opensearch.experimental */ -public class GetRuleRequest extends ClusterManagerNodeRequest { +public class GetRuleRequest extends ActionRequest { private final String _id; - private final Map> attributeFilters; + private final Map> attributeFilters; + private final String searchAfter; /** * Constructor for GetRuleRequest * @param _id - Rule _id that we want to get * @param attributeFilters - Attributes that we want to filter on + * @param searchAfter - The sort values from the last document of the previous page, used for pagination */ - public GetRuleRequest(String _id, Map> attributeFilters) { + public GetRuleRequest(String _id, Map> attributeFilters, String searchAfter) { this._id = _id; this.attributeFilters = attributeFilters; + this.searchAfter = searchAfter; } /** @@ -44,7 +51,8 @@ public GetRuleRequest(String _id, Map> attributeFilte public GetRuleRequest(StreamInput in) throws IOException { super(in); _id = in.readOptionalString(); - attributeFilters = in.readMap((i) -> RuleAttribute.fromName(i.readString()), i -> new HashSet<>(i.readStringList())); + attributeFilters = in.readMap(Attribute::from, i -> new HashSet<>(i.readStringList())); + searchAfter = in.readOptionalString(); } @Override @@ -56,7 +64,8 @@ public ActionRequestValidationException validate() { public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeOptionalString(_id); - out.writeMap(attributeFilters, RuleAttribute::writeTo, StreamOutput::writeStringCollection); + out.writeMap(attributeFilters, (output, attribute) -> attribute.writeTo(output), StreamOutput::writeStringCollection); + out.writeOptionalString(searchAfter); } /** @@ -69,7 +78,14 @@ public String get_id() { /** * attributeFilters getter */ - public Map> getAttributeFilters() { + public Map> getAttributeFilters() { return attributeFilters; } + + /** + * searchAfter getter + */ + public String getSearchAfter() { + return searchAfter; + } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java index b8be558c7e567..2b4ffd6b4f431 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java @@ -8,6 +8,7 @@ package org.opensearch.plugin.wlm.rule.action; +import org.opensearch.autotagging.Rule; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; @@ -15,28 +16,46 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.wlm.Rule; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import java.io.IOException; import java.util.Map; -import static org.opensearch.wlm.Rule._ID_STRING; +import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.plugin.wlm.rule.rest.RestGetRuleAction.SEARCH_AFTER_STRING; /** - * Response for the get API for Rule + * Response for the get API for Rule. + * Example response: + * { + * "rules": [ + * { + * "_id": "z1MJApUB0zgMcDmz-UQq", + * "description": "Rule for tagging query_group_id to index123" + * "index_pattern": ["index123"], + * "query_group": "query_group_id", + * "updated_at": "2025-02-14T01:19:22.589Z" + * }, + * ... + * ], + * "search_after": ["z1MJApUB0zgMcDmz-UQq"] + * } * @opensearch.experimental */ public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final Map rules; + private final Map> rules; + private final String searchAfter; private final RestStatus restStatus; /** * Constructor for GetRuleResponse * @param rules - The Map of Rules to be included in the response + * @param searchAfter - The searchAfter field for the response * @param restStatus - The restStatus for the response */ - public GetRuleResponse(final Map rules, RestStatus restStatus) { + public GetRuleResponse(final Map> rules, String searchAfter, RestStatus restStatus) { this.rules = rules; + this.searchAfter = searchAfter; this.restStatus = restStatus; } @@ -45,13 +64,13 @@ public GetRuleResponse(final Map rules, RestStatus restStatus) { * @param in - A {@link StreamInput} object */ public GetRuleResponse(StreamInput in) throws IOException { - this.rules = in.readMap(StreamInput::readString, Rule::new); - this.restStatus = RestStatus.readFrom(in); + this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString(), RestStatus.readFrom(in)); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeMap(rules, StreamOutput::writeString, (outStream, rule) -> rule.writeTo(outStream)); + out.writeOptionalString(searchAfter); RestStatus.writeTo(out, restStatus); } @@ -59,10 +78,13 @@ public void writeTo(StreamOutput out) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); builder.startArray("rules"); - for (Map.Entry entry : rules.entrySet()) { + for (Map.Entry> entry : rules.entrySet()) { entry.getValue().toXContent(builder, new MapParams(Map.of(_ID_STRING, entry.getKey()))); } builder.endArray(); + if (searchAfter != null && !searchAfter.isEmpty()) { + builder.field(SEARCH_AFTER_STRING, new Object[] { searchAfter }); + } builder.endObject(); return builder; } @@ -70,7 +92,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws /** * rules getter */ - public Map getRules() { + public Map> getRules() { return rules; } @@ -80,4 +102,11 @@ public Map getRules() { public RestStatus getRestStatus() { return restStatus; } + + /** + * searchAfter getter + */ + public String getSearchAfter() { + return searchAfter; + } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java index 66b243ff30e64..a7c2e4cac2e04 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java @@ -42,6 +42,6 @@ public TransportGetRuleAction( @Override protected void doExecute(Task task, GetRuleRequest request, ActionListener listener) { - rulePersistenceService.getRule(request.get_id(), request.getAttributeFilters(), listener); + rulePersistenceService.getRule(request.get_id(), request.getAttributeFilters(), request.getSearchAfter(), listener); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java index 685fd01f200d5..01f734e12d91e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java @@ -8,9 +8,11 @@ package org.opensearch.plugin.wlm.rule.rest; +import org.opensearch.autotagging.Attribute; import org.opensearch.client.node.NodeClient; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; import org.opensearch.plugin.wlm.rule.action.GetRuleAction; import org.opensearch.plugin.wlm.rule.action.GetRuleRequest; import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; @@ -20,7 +22,6 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.wlm.Rule.RuleAttribute; import java.io.IOException; import java.util.Arrays; @@ -30,14 +31,15 @@ import java.util.Map; import java.util.Set; +import static org.opensearch.autotagging.Rule._ID_STRING; import static org.opensearch.rest.RestRequest.Method.GET; -import static org.opensearch.wlm.Rule._ID_STRING; /** * Rest action to get a Rule * @opensearch.experimental */ public class RestGetRuleAction extends BaseRestHandler { + public static final String SEARCH_AFTER_STRING = "search_after"; /** * Constructor for RestGetRuleAction @@ -59,15 +61,19 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - final Map> attributeFilters = new HashMap<>(); + final Map> attributeFilters = new HashMap<>(); for (String attributeName : request.params().keySet()) { - if (attributeName.equals(_ID_STRING)) { + if (attributeName.equals(_ID_STRING) || attributeName.equals(SEARCH_AFTER_STRING)) { continue; } String[] valuesArray = request.param(attributeName).split(","); - attributeFilters.put(RuleAttribute.fromName(attributeName), new HashSet<>(Arrays.asList(valuesArray))); + attributeFilters.put(QueryGroupAttribute.fromName(attributeName), new HashSet<>(Arrays.asList(valuesArray))); } - final GetRuleRequest getRuleRequest = new GetRuleRequest(request.param(_ID_STRING), attributeFilters); + final GetRuleRequest getRuleRequest = new GetRuleRequest( + request.param(_ID_STRING), + attributeFilters, + request.param(SEARCH_AFTER_STRING) + ); return channel -> client.execute(GetRuleAction.INSTANCE, getRuleRequest, getRuleResponse(channel)); } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java index 4d00cb0decd27..aa45dda3ba210 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java @@ -12,8 +12,13 @@ import org.apache.logging.log4j.Logger; import org.opensearch.ResourceNotFoundException; import org.opensearch.action.get.GetResponse; +import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.Rule; +import org.opensearch.autotagging.Rule.Builder; import org.opensearch.client.Client; +import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -22,35 +27,41 @@ import org.opensearch.core.xcontent.MediaTypeRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilders; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; -import org.opensearch.wlm.Rule; -import org.opensearch.wlm.Rule.Builder; -import org.opensearch.wlm.Rule.RuleAttribute; +import org.opensearch.search.SearchHit; +import org.opensearch.search.sort.SortOrder; import java.io.IOException; import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import static org.opensearch.autotagging.Rule._ID_STRING; + /** - * This class defines the functions for Rule persistence + * This class encapsulates the logic to manage the lifecycle of rules at index level * @opensearch.experimental */ public class RulePersistenceService { - public static final String RULE_INDEX = ".rule"; + public static final String RULES_INDEX = ".rules"; private final Client client; + private final ClusterService clusterService; private static final Logger logger = LogManager.getLogger(RulePersistenceService.class); - private static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; + public static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 100; /** * Constructor for RulePersistenceService * @param client {@link Client} - The client to be used by RulePersistenceService */ @Inject - public RulePersistenceService(final Client client) { + public RulePersistenceService(final ClusterService clusterService, final Client client) { + this.clusterService = clusterService; this.client = client; } @@ -58,37 +69,39 @@ public RulePersistenceService(final Client client) { * Entry point for the get rule api logic in persistence service. * @param id - The id of the rule to get. Get all matching rules when id is null * @param attributeFilters - A map containing the attributes that user want to filter on + * @param searchAfter - The sort values from the last document of the previous page, used for pagination * @param listener - ActionListener for GetRuleResponse */ - public void getRule(String id, Map> attributeFilters, ActionListener listener) { + public void getRule( + String id, + Map> attributeFilters, + String searchAfter, + ActionListener listener + ) { if (id != null) { fetchRuleById(id, listener); } else { - fetchAllRules(attributeFilters, listener); + fetchAllRules(attributeFilters, searchAfter, listener); } } /** * Fetch a single rule from system index using id - * @param id - The id of the rule to get. + * @param id - The id of the rule to get * @param listener - ActionListener for GetRuleResponse */ private void fetchRuleById(String id, ActionListener listener) { ThreadContext.StoredContext storedContext = client.threadPool().getThreadContext().stashContext(); - client.prepareGet(RULE_INDEX, id) - .execute(ActionListener.wrap( - getResponse -> { - try (ThreadContext.StoredContext context = storedContext) { - handleGetOneRuleResponse(id, getResponse, listener); - } - }, - e -> { - try (ThreadContext.StoredContext context = storedContext) { - logger.error("Failed to fetch rule with ID {}: {}", id, e.getMessage()); - listener.onFailure(e); - } - } - )); + client.prepareGet(RULES_INDEX, id).execute(ActionListener.wrap(getResponse -> { + try (ThreadContext.StoredContext context = storedContext) { + handleGetOneRuleResponse(id, getResponse, listener); + } + }, e -> { + try (ThreadContext.StoredContext context = storedContext) { + logger.error("Failed to fetch rule with ID {}: {}", id, e.getMessage()); + listener.onFailure(e); + } + })); } /** @@ -106,7 +119,13 @@ private void handleGetOneRuleResponse(String id, GetResponse getResponse, Action DeprecationHandler.THROW_UNSUPPORTED_OPERATION, getResponse.getSourceAsString() ); - listener.onResponse(new GetRuleResponse(Map.of(id, Builder.fromXContent(parser).build()), RestStatus.OK)); + listener.onResponse( + new GetRuleResponse( + Map.of(id, Builder.fromXContent(parser, QueryGroupFeatureType.INSTANCE).build()), + null, + RestStatus.OK + ) + ); } catch (IOException e) { logger.error("Error parsing rule with ID {}: {}", id, e.getMessage()); listener.onFailure(e); @@ -117,74 +136,79 @@ private void handleGetOneRuleResponse(String id, GetResponse getResponse, Action } /** - * Fetch all rule from system index based on attributeFilters + * Fetch all rule from system index based on attributeFilters. * @param attributeFilters - A map containing the attributes that user want to filter on + * @param searchAfter - The sort values from the last document of the previous page, used for pagination * @param listener - ActionListener for GetRuleResponse */ - private void fetchAllRules(Map> attributeFilters, ActionListener listener) { + private void fetchAllRules(Map> attributeFilters, String searchAfter, ActionListener listener) { ThreadContext.StoredContext storedContext = client.threadPool().getThreadContext().stashContext(); - client.prepareSearch(RULE_INDEX) - .setQuery(QueryBuilders.matchAllQuery()) - .setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST) - .execute(ActionListener.wrap( - searchResponse -> { - try (ThreadContext.StoredContext context = storedContext) { - handleGetAllRuleResponse(searchResponse, attributeFilters, listener); - } - }, - e -> { - try (ThreadContext.StoredContext context = storedContext) { - logger.error("Failed to fetch all rules: {}", e.getMessage()); - listener.onFailure(e); - } + SearchRequestBuilder searchRequest = buildGetAllRuleSearchRequest(attributeFilters, searchAfter); + searchRequest.execute(ActionListener.wrap(searchResponse -> { + try (ThreadContext.StoredContext context = storedContext) { + listener.onResponse(handleGetAllRuleResponse(searchResponse)); + } + }, e -> { + try (ThreadContext.StoredContext context = storedContext) { + logger.error("Failed to fetch all rules: {}", e.getMessage()); + listener.onFailure(e); + } + })); + } + + /** + * Builds a search request to retrieve all rules from the rules index, applying attribute-based filters + * and ensuring that the rules are associated with the query group feature type. + * @param attributeFilters A map of attributes to their associated set of values used to filter the rules. + * @param searchAfter A cursor to enable pagination, used to fetch results after a specific document. + */ + SearchRequestBuilder buildGetAllRuleSearchRequest(Map> attributeFilters, String searchAfter) { + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + for (Map.Entry> entry : attributeFilters.entrySet()) { + Attribute attribute = entry.getKey(); + Set values = entry.getValue(); + if (values != null && !values.isEmpty()) { + BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); + for (String value : values) { + attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); } - )); + boolQuery.must(attributeQuery); + } + } + boolQuery.filter(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME)); + SearchRequestBuilder searchRequest = client.prepareSearch(RULES_INDEX) + .setQuery(boolQuery) + .setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST) + .addSort(_ID_STRING, SortOrder.ASC); + if (searchAfter != null) { + searchRequest.searchAfter(new Object[] { searchAfter }); + } + return searchRequest; } /** * Process searchResponse from index and send a GetRuleResponse * @param searchResponse - Response received from index - * @param attributeFilters - A map containing the attributes that user want to filter on - * @param listener - ActionListener for GetRuleResponse */ - private void handleGetAllRuleResponse( - SearchResponse searchResponse, - Map> attributeFilters, - ActionListener listener - ) { - Map ruleMap = Arrays.stream(searchResponse.getHits().getHits()).map(hit -> { + GetRuleResponse handleGetAllRuleResponse(SearchResponse searchResponse) { + List hits = Arrays.asList(searchResponse.getHits().getHits()); + Map> ruleMap = hits.stream().map(hit -> { + String hitId = hit.getId(); try (ThreadContext.StoredContext context = client.threadPool().getThreadContext().stashContext()) { XContentParser parser = MediaTypeRegistry.JSON.xContent() .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, hit.getSourceAsString()); - Rule currRule = Rule.Builder.fromXContent(parser).build(); - if (matchesFilters(currRule, attributeFilters)) { - return Map.entry(hit.getId(), currRule); - } - return null; + return Map.entry(hitId, Builder.fromXContent(parser, QueryGroupFeatureType.INSTANCE).build()); } catch (IOException e) { - logger.error("Failed to parse rule from hit: {}", e.getMessage()); - listener.onFailure(e); + logger.info( + "Issue met when parsing rule from hit, the feature type for rule id {} is probably not query_group: {}", + hitId, + e.getMessage() + ); return null; } }).filter(Objects::nonNull).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - listener.onResponse(new GetRuleResponse(ruleMap, RestStatus.OK)); - } - - /** - * Returns true if the rule matches the attributeFilters and should be included in the response - * @param rule - the rule to be checked against the attribute filters - * @param attributeFilters - A map containing the attributes that user want to filter on - */ - private boolean matchesFilters(Rule rule, Map> attributeFilters) { - for (Map.Entry> entry : attributeFilters.entrySet()) { - RuleAttribute attribute = entry.getKey(); - Set expectedValues = entry.getValue(); - Set ruleValues = rule.getAttributeMap().get(attribute); - if (ruleValues == null || ruleValues.stream().noneMatch(expectedValues::contains)) { - return false; - } - } - return true; + String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); + return new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK); } /** diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java index d7ccb01e32e59..387cdb1bae6e7 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java @@ -8,18 +8,20 @@ package org.opensearch.plugin.wlm; +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.Rule; import org.opensearch.client.Client; +import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.plugin.wlm.rule.service.RulePersistenceService; import org.opensearch.threadpool.ThreadPool; -import org.opensearch.wlm.Rule; -import org.opensearch.wlm.Rule.RuleAttribute; import java.util.Map; import java.util.Set; -import static org.opensearch.wlm.Rule.builder; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; @@ -32,48 +34,61 @@ public class RuleTestUtils { public static final String LABEL_TWO = "label_two"; public static final String PATTERN_ONE = "pattern_1"; public static final String PATTERN_TWO = "pattern_2"; - public static final String QUERY_GROUP = "query_group"; + public static final String DESCRIPTION_ONE = "description_1"; + public static final String DESCRIPTION_TWO = "description_2"; public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; - public static final Rule ruleOne = builder().feature(QUERY_GROUP) + public static final String SEARCH_AFTER = "search_after_id"; + public static final Map> attributes = Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE)); + public static final Rule ruleOne = Rule.builder() + .description(DESCRIPTION_ONE) + .featureType(QueryGroupFeatureType.INSTANCE) .label(LABEL_ONE) - .attributeMap(Map.of(RuleAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE))) + .attributeMap(Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE))) .updatedAt(TIMESTAMP_ONE) .build(); - public static final Rule ruleTwo = builder().feature(QUERY_GROUP) + public static final Rule ruleTwo = Rule.builder() + .description(DESCRIPTION_TWO) + .featureType(QueryGroupFeatureType.INSTANCE) .label(LABEL_TWO) - .attributeMap(Map.of(RuleAttribute.INDEX_PATTERN, Set.of(PATTERN_TWO))) + .attributeMap(Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_TWO))) .updatedAt(TIMESTAMP_TWO) .build(); - public static Map ruleMap() { + public static Map> ruleMap() { return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); } public static RulePersistenceService setUpRulePersistenceService() { Client client = mock(Client.class); + ClusterService clusterService = mock(ClusterService.class); ThreadPool threadPool = mock(ThreadPool.class); ThreadContext threadContext = new ThreadContext(Settings.EMPTY); when(client.threadPool()).thenReturn(threadPool); when(threadPool.getThreadContext()).thenReturn(threadContext); - return new RulePersistenceService(client); + return new RulePersistenceService(clusterService, client); } - public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { + public static void assertEqualRules( + Map> mapOne, + Map> mapTwo, + boolean ruleUpdated + ) { assertEquals(mapOne.size(), mapTwo.size()); - for (Map.Entry entry : mapOne.entrySet()) { + for (Map.Entry> entry : mapOne.entrySet()) { String id = entry.getKey(); assertTrue(mapTwo.containsKey(id)); - Rule one = mapOne.get(id); - Rule two = mapTwo.get(id); + Rule one = mapOne.get(id); + Rule two = mapTwo.get(id); assertEqualRule(one, two, ruleUpdated); } } - public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { + public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { if (ruleUpdated) { - assertEquals(one.getFeature(), two.getFeature()); + assertEquals(one.getDescription(), two.getDescription()); + assertEquals(one.getFeatureType(), two.getFeatureType()); assertEquals(one.getLabel(), two.getLabel()); assertEquals(one.getAttributeMap(), two.getAttributeMap()); } else { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java index e9abb281df8b2..0b8e9d186a6cb 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java @@ -11,7 +11,6 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.wlm.Rule; import java.io.IOException; import java.util.HashMap; @@ -19,7 +18,9 @@ import java.util.Set; import static org.opensearch.plugin.wlm.RuleTestUtils.PATTERN_ONE; +import static org.opensearch.plugin.wlm.RuleTestUtils.SEARCH_AFTER; import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; +import static org.opensearch.plugin.wlm.rule.QueryGroupAttribute.INDEX_PATTERN; public class GetRuleRequestTests extends OpenSearchTestCase { @@ -27,7 +28,7 @@ public class GetRuleRequestTests extends OpenSearchTestCase { * Test case to verify the serialization and deserialization of GetRuleRequest */ public void testSerialization() throws IOException { - GetRuleRequest request = new GetRuleRequest(_ID_ONE, Map.of(Rule.RuleAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE))); + GetRuleRequest request = new GetRuleRequest(_ID_ONE, Map.of(INDEX_PATTERN, Set.of(PATTERN_ONE)), null); assertEquals(_ID_ONE, request.get_id()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); @@ -41,7 +42,7 @@ public void testSerialization() throws IOException { * Test case to verify the serialization and deserialization of GetRuleRequest when name is null */ public void testSerializationWithNull() throws IOException { - GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>()); + GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER); assertNull(request.get_id()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java index 47545e554803e..9c5198704058c 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java @@ -8,19 +8,21 @@ package org.opensearch.plugin.wlm.rule.action; +import org.opensearch.autotagging.Rule; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.common.xcontent.json.JsonXContent; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.wlm.Rule; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import static org.opensearch.plugin.wlm.RuleTestUtils.SEARCH_AFTER; import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; import static org.opensearch.plugin.wlm.RuleTestUtils.assertEqualRules; import static org.opensearch.plugin.wlm.RuleTestUtils.ruleMap; @@ -33,9 +35,9 @@ public class GetRuleResponseTests extends OpenSearchTestCase { * Test case to verify the serialization and deserialization of GetRuleResponse */ public void testSerializationSingleRule() throws IOException { - Map map = new HashMap<>(); + Map> map = new HashMap<>(); map.put(_ID_ONE, ruleOne); - GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), RestStatus.OK); + GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), null, RestStatus.OK); assertEquals(response.getRules(), map); BytesStreamOutput out = new BytesStreamOutput(); @@ -51,7 +53,7 @@ public void testSerializationSingleRule() throws IOException { * Test case to verify the serialization and deserialization of GetRuleResponse when the result contains multiple rules */ public void testSerializationMultipleRule() throws IOException { - GetRuleResponse response = new GetRuleResponse(ruleMap(), RestStatus.OK); + GetRuleResponse response = new GetRuleResponse(ruleMap(), SEARCH_AFTER, RestStatus.OK); assertEquals(response.getRules(), ruleMap()); BytesStreamOutput out = new BytesStreamOutput(); @@ -68,8 +70,8 @@ public void testSerializationMultipleRule() throws IOException { * Test case to verify the serialization and deserialization of GetRuleResponse when the result is empty */ public void testSerializationNull() throws IOException { - Map map = new HashMap<>(); - GetRuleResponse response = new GetRuleResponse(map, RestStatus.OK); + Map> map = new HashMap<>(); + GetRuleResponse response = new GetRuleResponse(map, SEARCH_AFTER, RestStatus.OK); assertEquals(response.getRules(), map); BytesStreamOutput out = new BytesStreamOutput(); @@ -85,21 +87,25 @@ public void testSerializationNull() throws IOException { * Test case to verify the toXContent of GetRuleResponse */ public void testToXContentGetSingleRule() throws IOException { - Map map = new HashMap<>(); + Map> map = new HashMap<>(); map.put(_ID_ONE, ruleOne); - GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), RestStatus.OK); + GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER, RestStatus.OK); XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" + " \"rules\" : [\n" + " {\n" + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + + " \"description\" : \"description_1\",\n" + " \"index_pattern\" : [\n" + " \"pattern_1\"\n" + " ],\n" + " \"query_group\" : \"label_one\",\n" + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + " }\n" + + " ],\n" + + " \"search_after\" : [\n" + + " \"search_after_id\"\n" + " ]\n" + "}"; assertEquals(expected, actual); @@ -110,7 +116,7 @@ public void testToXContentGetSingleRule() throws IOException { */ public void testToXContentGetZeroRule() throws IOException { XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - GetRuleResponse otherResponse = new GetRuleResponse(new HashMap<>(), RestStatus.OK); + GetRuleResponse otherResponse = new GetRuleResponse(new HashMap<>(), null, RestStatus.OK); String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" + " \"rules\" : [ ]\n" + "}"; assertEquals(expected, actual); diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java index fa8225cf3552e..da426760086b7 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java @@ -11,11 +11,14 @@ import org.opensearch.ResourceNotFoundException; import org.opensearch.action.get.GetRequestBuilder; import org.opensearch.action.get.GetResponse; +import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.client.Client; import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.action.ActionListener; import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; +import org.opensearch.search.sort.SortOrder; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; @@ -24,25 +27,26 @@ import org.mockito.ArgumentCaptor; +import static org.opensearch.autotagging.Rule._ID_STRING; import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; import static org.opensearch.plugin.wlm.RuleTestUtils.assertEqualRules; import static org.opensearch.plugin.wlm.RuleTestUtils.ruleOne; import static org.opensearch.plugin.wlm.RuleTestUtils.setUpRulePersistenceService; -import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.RULE_INDEX; +import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST; +import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.RULES_INDEX; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") public class RulePersistenceServiceTests extends OpenSearchTestCase { - /** - * Test case to validate the logic for get Rule by id - */ public void testGetRuleById() throws IOException { String ruleSource = ruleOne.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS).toString(); ActionListener listener = mock(ActionListener.class); @@ -53,14 +57,14 @@ public void testGetRuleById() throws IOException { when(getResponse.isExists()).thenReturn(true); when(getResponse.getSourceAsString()).thenReturn(ruleSource); - when(client.prepareGet(eq(RULE_INDEX), eq(_ID_ONE))).thenReturn(getRequestBuilder); + when(client.prepareGet(eq(RULES_INDEX), eq(_ID_ONE))).thenReturn(getRequestBuilder); doAnswer(invocation -> { ActionListener actionListener = invocation.getArgument(0); actionListener.onResponse(getResponse); return null; }).when(getRequestBuilder).execute(any(ActionListener.class)); - rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), listener); + rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), null, listener); ArgumentCaptor captor = ArgumentCaptor.forClass(GetRuleResponse.class); verify(listener).onResponse(captor.capture()); @@ -70,9 +74,6 @@ public void testGetRuleById() throws IOException { clearInvocations(client, getRequestBuilder, getResponse, listener); } - /** - * Test case to validate the get rule for an invalid id - */ public void testGetRuleByIdNotFound() { String nonExistentRuleId = "non-existent-rule"; RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); @@ -81,7 +82,7 @@ public void testGetRuleByIdNotFound() { GetResponse getResponse = mock(GetResponse.class); ActionListener listener = mock(ActionListener.class); - when(client.prepareGet(RULE_INDEX, nonExistentRuleId)).thenReturn(getRequestBuilder); + when(client.prepareGet(RULES_INDEX, nonExistentRuleId)).thenReturn(getRequestBuilder); when(getResponse.isExists()).thenReturn(false); doAnswer(invocation -> { @@ -90,7 +91,7 @@ public void testGetRuleByIdNotFound() { return null; }).when(getRequestBuilder).execute(any(ActionListener.class)); - rulePersistenceService.getRule(nonExistentRuleId, new HashMap<>(), listener); + rulePersistenceService.getRule(nonExistentRuleId, new HashMap<>(), null, listener); ArgumentCaptor captor = ArgumentCaptor.forClass(Exception.class); verify(listener).onFailure(captor.capture()); @@ -98,4 +99,34 @@ public void testGetRuleByIdNotFound() { assertTrue(exception instanceof ResourceNotFoundException); clearInvocations(client, getRequestBuilder, getResponse, listener); } + + public void testBuildGetAllRuleSearchRequest() { + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); + Client client = rulePersistenceService.getClient(); + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + + when(client.prepareSearch(anyString())).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setQuery(any(BoolQueryBuilder.class))).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST)).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.addSort(eq(_ID_STRING), eq(SortOrder.ASC))).thenReturn(searchRequestBuilder); + + rulePersistenceService.buildGetAllRuleSearchRequest(ruleOne.getAttributeMap(), _ID_ONE); + ArgumentCaptor captor = ArgumentCaptor.forClass(Object[].class); + verify(searchRequestBuilder).searchAfter(captor.capture()); + assertEquals(_ID_ONE, captor.getValue()[0]); + } + + public void testBuildGetAllRuleSearchRequest_noSearchAfter() { + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); + Client client = rulePersistenceService.getClient(); + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + + when(client.prepareSearch(anyString())).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setQuery(any(BoolQueryBuilder.class))).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST)).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.addSort(eq(_ID_STRING), eq(SortOrder.ASC))).thenReturn(searchRequestBuilder); + + rulePersistenceService.buildGetAllRuleSearchRequest(ruleOne.getAttributeMap(), null); + verify(searchRequestBuilder, times(0)).searchAfter(any()); + } } diff --git a/server/src/main/java/org/opensearch/wlm/Rule.java b/server/src/main/java/org/opensearch/wlm/Rule.java deleted file mode 100644 index 273abc455c7e3..0000000000000 --- a/server/src/main/java/org/opensearch/wlm/Rule.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.wlm; - -import org.opensearch.common.ValidationException; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.common.io.stream.Writeable; -import org.opensearch.core.xcontent.ToXContentObject; -import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.core.xcontent.XContentParseException; -import org.opensearch.core.xcontent.XContentParser; -import org.joda.time.Instant; - -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import static org.opensearch.cluster.metadata.QueryGroup.isValid; - -/** - * Represents a rule schema used for automatic query tagging in the system. - * This class encapsulates the criteria (defined through attributes) for automatically applying relevant - * tags to queries based on matching attribute patterns. This class provides an in-memory representation - * of a rule. The indexed view may differ in representation. - * { - * "_id": "fwehf8302582mglfio349==", - * "index_pattern": ["logs123", "user*"], - * "query_group": "dev_query_group_id", - * "updated_at": "01-10-2025T21:23:21.456Z" - * } - * @opensearch.experimental - */ -public class Rule implements Writeable, ToXContentObject { - private final Map> attributeMap; - private final Feature feature; - private final String label; - private final String updatedAt; - public static final String _ID_STRING = "_id"; - public static final String UPDATED_AT_STRING = "updated_at"; - public static final int MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE = 10; - public static final int MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING = 100; - - public Rule(Map> attributeMap, String label, String updatedAt, Feature feature) { - ValidationException validationException = new ValidationException(); - validateRuleInputs(attributeMap, label, updatedAt, feature, validationException); - if (!validationException.validationErrors().isEmpty()) { - throw new IllegalArgumentException(validationException); - } - - this.attributeMap = attributeMap; - this.feature = feature; - this.label = label; - this.updatedAt = updatedAt; - } - - public Rule(StreamInput in) throws IOException { - this( - in.readMap((i) -> RuleAttribute.fromName(i.readString()), i -> new HashSet<>(i.readStringList())), - in.readString(), - in.readString(), - Feature.fromName(in.readString()) - ); - } - - public static void requireNonNullOrEmpty(String value, String message, ValidationException validationException) { - if (value == null || value.isEmpty()) { - validationException.addValidationError(message); - } - } - - public static void validateRuleInputs( - Map> attributeMap, - String label, - String updatedAt, - Feature feature, - ValidationException validationException - ) { - if (feature == null) { - validationException.addValidationError("Couldn't identify which feature the rule belongs to. Rule feature name can't be null."); - } - requireNonNullOrEmpty(label, "Rule label can't be null or empty", validationException); - requireNonNullOrEmpty(updatedAt, "Rule update time can't be null or empty", validationException); - if (attributeMap == null || attributeMap.isEmpty()) { - validationException.addValidationError("Rule should have at least 1 attribute requirement"); - } - if (updatedAt != null && !isValid(Instant.parse(updatedAt).getMillis())) { - validationException.addValidationError("Rule update time is not a valid epoch"); - } - if (attributeMap != null && feature != null) { - validateAttributeMap(attributeMap, feature, validationException); - } - } - - public static void validateAttributeMap( - Map> attributeMap, - Feature feature, - ValidationException validationException - ) { - for (Map.Entry> entry : attributeMap.entrySet()) { - RuleAttribute ruleAttribute = entry.getKey(); - Set attributeValues = entry.getValue(); - if (!feature.isValidAttribute(ruleAttribute)) { - validationException.addValidationError( - ruleAttribute.getName() + " is not a valid attribute name under the feature: " + feature.getName() - ); - } - if (attributeValues.size() > MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE) { - validationException.addValidationError( - "Each attribute can only have a maximum of 10 values. The input attribute " + ruleAttribute + " exceeds this limit." - ); - } - for (String attributeValue : attributeValues) { - if (attributeValue.isEmpty() || attributeValue.length() > MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING) { - validationException.addValidationError( - "Attribute value [" + attributeValue + "] is invalid (empty or exceeds 100 characters)" - ); - } - } - } - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeMap(attributeMap, RuleAttribute::writeTo, StreamOutput::writeStringCollection); - out.writeString(label); - out.writeString(updatedAt); - out.writeString(feature.getName()); - } - - public static Rule fromXContent(final XContentParser parser) throws IOException { - return Builder.fromXContent(parser).build(); - } - - public String getLabel() { - return label; - } - - public String getUpdatedAt() { - return updatedAt; - } - - public Feature getFeature() { - return feature; - } - - public Map> getAttributeMap() { - return attributeMap; - } - - /** - * This enum enumerates the features that can use the Rule Based Auto-tagging - * @opensearch.experimental - */ - public enum Feature { - QUERY_GROUP("query_group", Set.of(RuleAttribute.INDEX_PATTERN)); - - private final String name; - private final Set allowedAttributes; - - Feature(String name, Set allowedAttributes) { - this.name = name; - this.allowedAttributes = allowedAttributes; - } - - public String getName() { - return name; - } - - public Set getAllowedAttributes() { - return allowedAttributes; - } - - public boolean isValidAttribute(RuleAttribute attribute) { - return allowedAttributes.contains(attribute); - } - - public static boolean isValidFeature(String s) { - return Arrays.stream(values()).anyMatch(feature -> feature.getName().equalsIgnoreCase(s)); - } - - public static Feature fromName(String s) { - return Arrays.stream(values()) - .filter(feature -> feature.getName().equalsIgnoreCase(s)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Invalid value for Feature: " + s)); - } - } - - /** - * This RuleAttribute enum contains the attribute names for a rule. - * @opensearch.experimental - */ - public enum RuleAttribute { - INDEX_PATTERN("index_pattern"); - - private final String name; - - RuleAttribute(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public static void writeTo(StreamOutput out, RuleAttribute ruleAttribute) throws IOException { - out.writeString(ruleAttribute.getName()); - } - - public static RuleAttribute fromName(String s) { - for (RuleAttribute attribute : values()) { - if (attribute.getName().equalsIgnoreCase(s)) return attribute; - - } - throw new IllegalArgumentException("Invalid value for RuleAttribute: " + s); - } - } - - @Override - public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException { - builder.startObject(); - String id = params.param(_ID_STRING); - if (id != null) { - builder.field(_ID_STRING, id); - } - for (Map.Entry> entry : attributeMap.entrySet()) { - builder.array(entry.getKey().getName(), entry.getValue().toArray(new String[0])); - } - builder.field(feature.getName(), label); - builder.field(UPDATED_AT_STRING, updatedAt); - builder.endObject(); - return builder; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Rule that = (Rule) o; - return Objects.equals(label, that.label) - && Objects.equals(feature, that.feature) - && Objects.equals(attributeMap, that.attributeMap) - && Objects.equals(updatedAt, that.updatedAt); - } - - @Override - public int hashCode() { - return Objects.hash(label, feature, attributeMap, updatedAt); - } - - /** - * builder method for the {@link Rule} - * @return Builder object - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Builder class for {@link Rule} - * @opensearch.experimental - */ - public static class Builder { - private Map> attributeMap; - private Feature feature; - private String label; - private String updatedAt; - - private Builder() {} - - public static Builder fromXContent(XContentParser parser) throws IOException { - if (parser.currentToken() == null) { - parser.nextToken(); - } - Builder builder = builder(); - XContentParser.Token token = parser.currentToken(); - - if (token != XContentParser.Token.START_OBJECT) { - throw new IllegalArgumentException("Expected START_OBJECT token but found [" + parser.currentName() + "]"); - } - Map> attributeMap1 = new HashMap<>(); - String fieldName = ""; - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token == XContentParser.Token.FIELD_NAME) { - fieldName = parser.currentName(); - } else if (token.isValue()) { - if (Feature.isValidFeature(fieldName)) { - builder.feature(fieldName); - builder.label(parser.text()); - } else if (fieldName.equals(UPDATED_AT_STRING)) { - builder.updatedAt(parser.text()); - } else { - throw new IllegalArgumentException(fieldName + " is not a valid field in Rule"); - } - } else if (token == XContentParser.Token.START_ARRAY) { - fromXContentParseArray(parser, fieldName, attributeMap1); - } - } - return builder.attributeMap(attributeMap1); - } - - public static void fromXContentParseArray(XContentParser parser, String fieldName, Map> attributeMap) - throws IOException { - RuleAttribute ruleAttribute = RuleAttribute.fromName(fieldName); - Set attributeValueSet = new HashSet<>(); - while (parser.nextToken() != XContentParser.Token.END_ARRAY) { - if (parser.currentToken() == XContentParser.Token.VALUE_STRING) { - attributeValueSet.add(parser.text()); - } else { - throw new XContentParseException("Unexpected token in array: " + parser.currentToken()); - } - } - attributeMap.put(ruleAttribute, attributeValueSet); - } - - public Builder label(String label) { - this.label = label; - return this; - } - - public Builder attributeMap(Map> attributeMap) { - this.attributeMap = attributeMap; - return this; - } - - public Builder feature(String feature) { - this.feature = Feature.fromName(feature); - return this; - } - - public Builder updatedAt(String updatedAt) { - this.updatedAt = updatedAt; - return this; - } - - public Rule build() { - return new Rule(attributeMap, label, updatedAt, feature); - } - - public String getLabel() { - return label; - } - - public Map> getAttributeMap() { - return attributeMap; - } - } -} diff --git a/server/src/test/java/org/opensearch/wlm/RuleTests.java b/server/src/test/java/org/opensearch/wlm/RuleTests.java deleted file mode 100644 index 72a4abf1f3877..0000000000000 --- a/server/src/test/java/org/opensearch/wlm/RuleTests.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.wlm; - -import org.opensearch.common.xcontent.json.JsonXContent; -import org.opensearch.core.common.io.stream.Writeable; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.core.xcontent.XContentParser; -import org.opensearch.test.AbstractSerializingTestCase; -import org.opensearch.wlm.Rule.Feature; -import org.opensearch.wlm.Rule.RuleAttribute; -import org.joda.time.Instant; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.opensearch.wlm.Rule.MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING; -import static org.opensearch.wlm.Rule.MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE; -import static org.opensearch.wlm.Rule._ID_STRING; - -public class RuleTests extends AbstractSerializingTestCase { - public static final String _ID = "AgfUfjw039vhdONlYi3TQ=="; - public static final String LABEL = "label"; - - static Rule createRandomRule(String label) { - Feature feature = randomFeature(); - return Rule.builder() - .label(label) - .feature(feature.getName()) - .attributeMap(randomAttributeMaps(feature)) - .updatedAt(Instant.now().toString()) - .build(); - } - - private static Feature randomFeature() { - return Feature.values()[randomIntBetween(0, Feature.values().length - 1)]; - } - - private static Map> randomAttributeMaps(Feature feature) { - Map> attributeMap = new HashMap<>(); - if (feature == null) { - return attributeMap; - } - List allowedAttributes = new ArrayList<>(feature.getAllowedAttributes()); - do { - attributeMap.clear(); - for (RuleAttribute currAttribute : allowedAttributes) { - if (randomBoolean()) { - attributeMap.put(currAttribute, randomAttributeValues()); - } - } - } while (attributeMap.isEmpty()); - return attributeMap; - } - - private static Set randomAttributeValues() { - Set res = new HashSet<>(); - int numberOfValues = randomIntBetween(1, MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE); - for (int i = 0; i < numberOfValues; i++) { - res.add(randomAlphaOfLength(randomIntBetween(1, MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING))); - } - return res; - } - - @Override - protected Rule doParseInstance(XContentParser parser) throws IOException { - return Rule.fromXContent(parser); - } - - @Override - protected Writeable.Reader instanceReader() { - return Rule::new; - } - - @Override - protected Rule createTestInstance() { - return createRandomRule(LABEL); - } - - static Rule buildRule(String label, String feature, Map> attributeListMap, String updatedAt) { - return Rule.builder().label(label).feature(feature).attributeMap(attributeListMap).updatedAt(updatedAt).build(); - } - - public void testInvalidFeature() { - assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, null, randomAttributeMaps(null), Instant.now().toString())); - assertThrows( - IllegalArgumentException.class, - () -> buildRule(LABEL, "invalid", randomAttributeMaps(null), Instant.now().toString()) - ); - } - - public void testInvalidLabel() { - assertThrows(IllegalArgumentException.class, () -> createRandomRule(null)); - assertThrows(IllegalArgumentException.class, () -> createRandomRule("")); - } - - public void testInvalidUpdateTime() { - Feature feature = randomFeature(); - assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, feature.toString(), randomAttributeMaps(feature), null)); - } - - public void testNullOrEmptyAttributeMap() { - Feature feature = randomFeature(); - assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, feature.toString(), new HashMap<>(), Instant.now().toString())); - assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, feature.toString(), null, Instant.now().toString())); - } - - public void testInvalidAttributeMap() { - Map> map = new HashMap<>(); - map.put(RuleAttribute.INDEX_PATTERN, Set.of("")); - assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, randomFeature().getName(), map, Instant.now().toString())); - - map.put(RuleAttribute.INDEX_PATTERN, Set.of(randomAlphaOfLength(MAX_CHARACTER_LENGTH_PER_ATTRIBUTE_VALUE_STRING + 1))); - assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, randomFeature().getName(), map, Instant.now().toString())); - - map.put(RuleAttribute.INDEX_PATTERN, new HashSet<>()); - for (int i = 0; i < MAX_NUMBER_OF_VALUES_PER_ATTRIBUTE + 1; i++) { - map.get(RuleAttribute.INDEX_PATTERN).add(String.valueOf(i)); - } - assertThrows(IllegalArgumentException.class, () -> buildRule(LABEL, randomFeature().getName(), map, Instant.now().toString())); - } - - public void testValidRule() { - Map> map = Map.of(RuleAttribute.INDEX_PATTERN, Set.of("index*", "log*")); - String updatedAt = Instant.now().toString(); - Rule rule = buildRule(LABEL, Feature.QUERY_GROUP.getName(), map, updatedAt); - assertNotNull(rule.getLabel()); - assertEquals(LABEL, rule.getLabel()); - assertNotNull(updatedAt); - assertEquals(updatedAt, rule.getUpdatedAt()); - Map> resultMap = rule.getAttributeMap(); - assertNotNull(resultMap); - assertFalse(resultMap.isEmpty()); - assertNotNull(rule.getFeature()); - assertEquals(Feature.QUERY_GROUP, rule.getFeature()); - } - - public void testToXContent() throws IOException { - Map> map = Map.of(RuleAttribute.INDEX_PATTERN, Set.of("log*")); - String updatedAt = Instant.now().toString(); - Rule rule = buildRule(LABEL, Feature.QUERY_GROUP.getName(), map, updatedAt); - - XContentBuilder builder = JsonXContent.contentBuilder(); - rule.toXContent(builder, new ToXContent.MapParams(Map.of(_ID_STRING, _ID))); - - assertEquals( - "{\"_id\":\"" + _ID + "\",\"index_pattern\":[\"log*\"],\"query_group\":\"label\",\"updated_at\":\"" + updatedAt + "\"}", - builder.toString() - ); - } -} From bf5589e5cd601d019ff053f8d94b61dc04c9db30 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Fri, 21 Mar 2025 17:31:55 -0700 Subject: [PATCH 03/28] rebase from main after the schema merged Signed-off-by: Ruirui Zhang --- .../plugin/wlm/rule/QueryGroupAttribute.java | 25 ++- .../wlm/rule/QueryGroupFeatureType.java | 10 +- .../wlm/rule/action/GetRuleRequest.java | 21 +-- .../wlm/rule/action/GetRuleResponse.java | 9 +- .../rule/action/TransportGetRuleAction.java | 2 +- .../wlm/rule/rest/RestGetRuleAction.java | 2 +- .../rule/service/RulePersistenceService.java | 167 +++++++++++------- .../opensearch/plugin/wlm/RuleTestUtils.java | 46 ++--- .../wlm/rule/action/GetRuleRequestTests.java | 8 +- .../wlm/rule/action/GetRuleResponseTests.java | 9 +- .../service/RulePersistenceServiceTests.java | 44 +---- 11 files changed, 169 insertions(+), 174 deletions(-) diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java index 906b68e37efff..f57a92bce5c9d 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java @@ -9,11 +9,12 @@ package org.opensearch.plugin.wlm.rule; import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.AutoTaggingRegistry; + +import java.util.HashMap; +import java.util.Map; /** * Attributes specific to the query group feature. - * @opensearch.experimental */ public enum QueryGroupAttribute implements Attribute { INDEX_PATTERN("index_pattern"); @@ -22,12 +23,7 @@ public enum QueryGroupAttribute implements Attribute { QueryGroupAttribute(String name) { this.name = name; - } - - static { - for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { - attr.registerAttribute(); - } + validateAttribute(); } @Override @@ -35,11 +31,6 @@ public String getName() { return name; } - @Override - public void registerAttribute() { - AutoTaggingRegistry.registerAttribute(this); - } - public static QueryGroupAttribute fromName(String name) { for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { if (attr.getName().equals(name)) { @@ -48,4 +39,12 @@ public static QueryGroupAttribute fromName(String name) { } throw new IllegalArgumentException("Unknown QueryGroupAttribute: " + name); } + + public static Map toMap() { + Map map = new HashMap<>(); + for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { + map.put(attr.getName(), attr); + } + return map; + } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java index 18e227d23e888..feb762b8ad99b 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java @@ -12,18 +12,14 @@ import org.opensearch.autotagging.AutoTaggingRegistry; import org.opensearch.autotagging.FeatureType; -import java.util.Set; +import java.util.Map; -/** - * Represents the feature type for "query_group" in the OpenSearch workload management plugin. - * @opensearch.experimental - */ public class QueryGroupFeatureType implements FeatureType { public static final QueryGroupFeatureType INSTANCE = new QueryGroupFeatureType(); public static final String NAME = "query_group"; private static final int MAX_ATTRIBUTE_VALUES = 10; private static final int MAX_ATTRIBUTE_VALUE_LENGTH = 100; - private static final Set ALLOWED_ATTRIBUTES = Set.of(QueryGroupAttribute.values()); + private static final Map ALLOWED_ATTRIBUTES = QueryGroupAttribute.toMap(); private QueryGroupFeatureType() {} @@ -47,7 +43,7 @@ public int getMaxCharLengthPerAttributeValue() { } @Override - public Set getAllowedAttributes() { + public Map getAllowedAttributesRegistry() { return ALLOWED_ATTRIBUTES; } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java index 0f9b4cef43925..181bd9583ce34 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java @@ -13,6 +13,7 @@ import org.opensearch.autotagging.Attribute; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import java.io.IOException; import java.util.HashSet; @@ -28,18 +29,18 @@ * @opensearch.experimental */ public class GetRuleRequest extends ActionRequest { - private final String _id; + private final String id; private final Map> attributeFilters; private final String searchAfter; /** * Constructor for GetRuleRequest - * @param _id - Rule _id that we want to get + * @param id - Rule id that we want to get * @param attributeFilters - Attributes that we want to filter on * @param searchAfter - The sort values from the last document of the previous page, used for pagination */ - public GetRuleRequest(String _id, Map> attributeFilters, String searchAfter) { - this._id = _id; + public GetRuleRequest(String id, Map> attributeFilters, String searchAfter) { + this.id = id; this.attributeFilters = attributeFilters; this.searchAfter = searchAfter; } @@ -50,8 +51,8 @@ public GetRuleRequest(String _id, Map> attributeFilters, */ public GetRuleRequest(StreamInput in) throws IOException { super(in); - _id = in.readOptionalString(); - attributeFilters = in.readMap(Attribute::from, i -> new HashSet<>(i.readStringList())); + id = in.readOptionalString(); + attributeFilters = in.readMap(i -> Attribute.from(i, QueryGroupFeatureType.INSTANCE), i -> new HashSet<>(i.readStringList())); searchAfter = in.readOptionalString(); } @@ -63,16 +64,16 @@ public ActionRequestValidationException validate() { @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); - out.writeOptionalString(_id); + out.writeOptionalString(id); out.writeMap(attributeFilters, (output, attribute) -> attribute.writeTo(output), StreamOutput::writeStringCollection); out.writeOptionalString(searchAfter); } /** - * _id getter + * id getter */ - public String get_id() { - return _id; + public String getId() { + return id; } /** diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java index 2b4ffd6b4f431..2f45e372b8325 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java @@ -16,7 +16,6 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import java.io.IOException; import java.util.Map; @@ -43,7 +42,7 @@ * @opensearch.experimental */ public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final Map> rules; + private final Map rules; private final String searchAfter; private final RestStatus restStatus; @@ -53,7 +52,7 @@ public class GetRuleResponse extends ActionResponse implements ToXContent, ToXCo * @param searchAfter - The searchAfter field for the response * @param restStatus - The restStatus for the response */ - public GetRuleResponse(final Map> rules, String searchAfter, RestStatus restStatus) { + public GetRuleResponse(final Map rules, String searchAfter, RestStatus restStatus) { this.rules = rules; this.searchAfter = searchAfter; this.restStatus = restStatus; @@ -78,7 +77,7 @@ public void writeTo(StreamOutput out) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); builder.startArray("rules"); - for (Map.Entry> entry : rules.entrySet()) { + for (Map.Entry entry : rules.entrySet()) { entry.getValue().toXContent(builder, new MapParams(Map.of(_ID_STRING, entry.getKey()))); } builder.endArray(); @@ -92,7 +91,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws /** * rules getter */ - public Map> getRules() { + public Map getRules() { return rules; } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java index a7c2e4cac2e04..7b9a77d78e328 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java @@ -42,6 +42,6 @@ public TransportGetRuleAction( @Override protected void doExecute(Task task, GetRuleRequest request, ActionListener listener) { - rulePersistenceService.getRule(request.get_id(), request.getAttributeFilters(), request.getSearchAfter(), listener); + rulePersistenceService.getRule(request.getId(), request.getAttributeFilters(), request.getSearchAfter(), listener); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java index 01f734e12d91e..c3a9844fc6f33 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java @@ -9,7 +9,6 @@ package org.opensearch.plugin.wlm.rule.rest; import org.opensearch.autotagging.Attribute; -import org.opensearch.client.node.NodeClient; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; @@ -22,6 +21,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; +import org.opensearch.transport.client.node.NodeClient; import java.io.IOException; import java.util.Arrays; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java index aa45dda3ba210..a903f80b2249e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java @@ -17,7 +17,6 @@ import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.Rule; import org.opensearch.autotagging.Rule.Builder; -import org.opensearch.client.Client; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.util.concurrent.ThreadContext; @@ -33,9 +32,11 @@ import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; import org.opensearch.search.SearchHit; import org.opensearch.search.sort.SortOrder; +import org.opensearch.transport.client.Client; import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -53,12 +54,8 @@ public class RulePersistenceService { private final Client client; private final ClusterService clusterService; private static final Logger logger = LogManager.getLogger(RulePersistenceService.class); - public static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 100; + public static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; - /** - * Constructor for RulePersistenceService - * @param client {@link Client} - The client to be used by RulePersistenceService - */ @Inject public RulePersistenceService(final ClusterService clusterService, final Client client) { this.clusterService = clusterService; @@ -90,18 +87,14 @@ public void getRule( * @param id - The id of the rule to get * @param listener - ActionListener for GetRuleResponse */ - private void fetchRuleById(String id, ActionListener listener) { - ThreadContext.StoredContext storedContext = client.threadPool().getThreadContext().stashContext(); - client.prepareGet(RULES_INDEX, id).execute(ActionListener.wrap(getResponse -> { - try (ThreadContext.StoredContext context = storedContext) { - handleGetOneRuleResponse(id, getResponse, listener); - } - }, e -> { - try (ThreadContext.StoredContext context = storedContext) { - logger.error("Failed to fetch rule with ID {}: {}", id, e.getMessage()); - listener.onFailure(e); - } - })); + void fetchRuleById(String id, ActionListener listener) { + try (ThreadContext.StoredContext context = getContext()) { + client.prepareGet(RULES_INDEX, id) + .execute(ActionListener.wrap(getResponse -> handleGetOneRuleResponse(id, getResponse, listener), e -> { + logger.error("Failed to fetch rule with ID {}: {}", id, e.getMessage()); + listener.onFailure(e); + })); + } } /** @@ -112,7 +105,7 @@ private void fetchRuleById(String id, ActionListener listener) */ private void handleGetOneRuleResponse(String id, GetResponse getResponse, ActionListener listener) { if (getResponse.isExists()) { - try (ThreadContext.StoredContext context = client.threadPool().getThreadContext().stashContext()) { + try (ThreadContext.StoredContext context = getContext()) { XContentParser parser = MediaTypeRegistry.JSON.xContent() .createParser( NamedXContentRegistry.EMPTY, @@ -142,18 +135,44 @@ private void handleGetOneRuleResponse(String id, GetResponse getResponse, Action * @param listener - ActionListener for GetRuleResponse */ private void fetchAllRules(Map> attributeFilters, String searchAfter, ActionListener listener) { - ThreadContext.StoredContext storedContext = client.threadPool().getThreadContext().stashContext(); - SearchRequestBuilder searchRequest = buildGetAllRuleSearchRequest(attributeFilters, searchAfter); - searchRequest.execute(ActionListener.wrap(searchResponse -> { - try (ThreadContext.StoredContext context = storedContext) { - listener.onResponse(handleGetAllRuleResponse(searchResponse)); + try (ThreadContext.StoredContext context = getContext()) { + client.prepareSearch(RULES_INDEX) + .setSize(0) + .execute( + ActionListener.wrap(countResponse -> handleCountResponse(countResponse, attributeFilters, searchAfter, listener), e -> { + logger.error("Failed to check if index is empty: {}", e.getMessage()); + listener.onFailure(e); + }) + ); + } + } + + /** + * Processes the count response from a search query on the rules index. + * If no rules exist, it responds with an empty result. + * Otherwise, it constructs and executes a search request to retrieve all rules. + * @param countResponse The response from the count query on the rules index. + * @param attributeFilters A map of attribute filters to apply in the search query. + * @param searchAfter The searchAfter parameter for pagination. + * @param listener The action listener to handle the final response or failure. + */ + void handleCountResponse( + SearchResponse countResponse, + Map> attributeFilters, + String searchAfter, + ActionListener listener + ) { + try (ThreadContext.StoredContext context = getContext()) { + if (countResponse.getHits().getTotalHits().value() == 0) { + listener.onResponse(new GetRuleResponse(new HashMap<>(), null, RestStatus.OK)); + return; } - }, e -> { - try (ThreadContext.StoredContext context = storedContext) { + SearchRequestBuilder searchRequest = buildGetAllRuleSearchRequest(attributeFilters, searchAfter); + searchRequest.execute(ActionListener.wrap(searchResponse -> handleGetAllRuleResponse(searchResponse, listener), e -> { logger.error("Failed to fetch all rules: {}", e.getMessage()); listener.onFailure(e); - } - })); + })); + } } /** @@ -163,58 +182,72 @@ private void fetchAllRules(Map> attributeFilters, String * @param searchAfter A cursor to enable pagination, used to fetch results after a specific document. */ SearchRequestBuilder buildGetAllRuleSearchRequest(Map> attributeFilters, String searchAfter) { - BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); - for (Map.Entry> entry : attributeFilters.entrySet()) { - Attribute attribute = entry.getKey(); - Set values = entry.getValue(); - if (values != null && !values.isEmpty()) { - BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); - for (String value : values) { - attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); + try (ThreadContext.StoredContext context = getContext()) { + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + for (Map.Entry> entry : attributeFilters.entrySet()) { + Attribute attribute = entry.getKey(); + Set values = entry.getValue(); + if (values != null && !values.isEmpty()) { + BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); + for (String value : values) { + attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); + } + boolQuery.must(attributeQuery); } - boolQuery.must(attributeQuery); } + boolQuery.filter(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME)); + SearchRequestBuilder searchRequest = client.prepareSearch(RULES_INDEX) + .setQuery(boolQuery) + .setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST) + .addSort(_ID_STRING, SortOrder.ASC); + if (searchAfter != null) { + searchRequest.searchAfter(new Object[] { searchAfter }); + } + return searchRequest; } - boolQuery.filter(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME)); - SearchRequestBuilder searchRequest = client.prepareSearch(RULES_INDEX) - .setQuery(boolQuery) - .setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST) - .addSort(_ID_STRING, SortOrder.ASC); - if (searchAfter != null) { - searchRequest.searchAfter(new Object[] { searchAfter }); - } - return searchRequest; } /** * Process searchResponse from index and send a GetRuleResponse * @param searchResponse - Response received from index + * @param listener - ActionListener for GetRuleResponse */ - GetRuleResponse handleGetAllRuleResponse(SearchResponse searchResponse) { + void handleGetAllRuleResponse(SearchResponse searchResponse, ActionListener listener) { List hits = Arrays.asList(searchResponse.getHits().getHits()); - Map> ruleMap = hits.stream().map(hit -> { - String hitId = hit.getId(); - try (ThreadContext.StoredContext context = client.threadPool().getThreadContext().stashContext()) { - XContentParser parser = MediaTypeRegistry.JSON.xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, hit.getSourceAsString()); - return Map.entry(hitId, Builder.fromXContent(parser, QueryGroupFeatureType.INSTANCE).build()); - } catch (IOException e) { - logger.info( - "Issue met when parsing rule from hit, the feature type for rule id {} is probably not query_group: {}", - hitId, - e.getMessage() - ); - return null; - } - }).filter(Objects::nonNull).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); - return new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK); + try (ThreadContext.StoredContext context = getContext()) { + Map ruleMap = hits.stream().map(hit -> { + String hitId = hit.getId(); + try { + XContentParser parser = MediaTypeRegistry.JSON.xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, hit.getSourceAsString()); + return Map.entry(hitId, Builder.fromXContent(parser, QueryGroupFeatureType.INSTANCE).build()); + } catch (IOException e) { + logger.info( + "Issue met when parsing rule from hit, the feature type for rule id {} is probably not query_group: {}", + hitId, + e.getMessage() + ); + return null; + } + }).filter(Objects::nonNull).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); + listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); + } + } + + private ThreadContext.StoredContext getContext() { + return client.threadPool().getThreadContext().stashContext(); + } + + private boolean isExistingQueryGroup(String queryGroupId) { + return clusterService.state().metadata().queryGroups().containsKey(queryGroupId); } - /** - * client getter - */ public Client getClient() { return client; } + + public ClusterService getClusterService() { + return clusterService; + } } diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java index 387cdb1bae6e7..e00614055d250 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java @@ -10,7 +10,9 @@ import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.Rule; -import org.opensearch.client.Client; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.metadata.Metadata; +import org.opensearch.cluster.metadata.QueryGroup; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; @@ -18,6 +20,7 @@ import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.plugin.wlm.rule.service.RulePersistenceService; import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.client.Client; import java.util.Map; import java.util.Set; @@ -30,8 +33,8 @@ public class RuleTestUtils { public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; - public static final String LABEL_ONE = "label_one"; - public static final String LABEL_TWO = "label_two"; + public static final String FEATURE_VALUE_ONE = "feature_value_one"; + public static final String FEATURE_VALUE_TWO = "feature_value_two"; public static final String PATTERN_ONE = "pattern_1"; public static final String PATTERN_TWO = "pattern_2"; public static final String DESCRIPTION_ONE = "description_1"; @@ -39,57 +42,60 @@ public class RuleTestUtils { public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; public static final String SEARCH_AFTER = "search_after_id"; - public static final Map> attributes = Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE)); - public static final Rule ruleOne = Rule.builder() + public static final Map> ATTRIBUTE_MAP = Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE)); + public static final Rule ruleOne = Rule.builder() .description(DESCRIPTION_ONE) .featureType(QueryGroupFeatureType.INSTANCE) - .label(LABEL_ONE) + .featureValue(FEATURE_VALUE_ONE) .attributeMap(Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE))) .updatedAt(TIMESTAMP_ONE) .build(); - public static final Rule ruleTwo = Rule.builder() + public static final Rule ruleTwo = Rule.builder() .description(DESCRIPTION_TWO) .featureType(QueryGroupFeatureType.INSTANCE) - .label(LABEL_TWO) + .featureValue(FEATURE_VALUE_TWO) .attributeMap(Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_TWO))) .updatedAt(TIMESTAMP_TWO) .build(); - public static Map> ruleMap() { + public static Map ruleMap() { return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); } - public static RulePersistenceService setUpRulePersistenceService() { + public static RulePersistenceService setUpRulePersistenceService(Map queryGroupMap) { Client client = mock(Client.class); ClusterService clusterService = mock(ClusterService.class); + ClusterState clusterState = mock(ClusterState.class); + Metadata metadata = mock(Metadata.class); ThreadPool threadPool = mock(ThreadPool.class); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); when(client.threadPool()).thenReturn(threadPool); when(threadPool.getThreadContext()).thenReturn(threadContext); + when(clusterService.state()).thenReturn(clusterState); + when(clusterState.metadata()).thenReturn(metadata); + when(metadata.queryGroups()).thenReturn(queryGroupMap); return new RulePersistenceService(clusterService, client); } - public static void assertEqualRules( - Map> mapOne, - Map> mapTwo, - boolean ruleUpdated - ) { + public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { assertEquals(mapOne.size(), mapTwo.size()); - for (Map.Entry> entry : mapOne.entrySet()) { + for (Map.Entry entry : mapOne.entrySet()) { String id = entry.getKey(); assertTrue(mapTwo.containsKey(id)); - Rule one = mapOne.get(id); - Rule two = mapTwo.get(id); + Rule one = mapOne.get(id); + Rule two = mapTwo.get(id); assertEqualRule(one, two, ruleUpdated); } } - public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { + public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { if (ruleUpdated) { assertEquals(one.getDescription(), two.getDescription()); assertEquals(one.getFeatureType(), two.getFeatureType()); - assertEquals(one.getLabel(), two.getLabel()); + assertEquals(one.getFeatureValue(), two.getFeatureValue()); + assertEquals(one.getAttributeMap(), two.getAttributeMap()); assertEquals(one.getAttributeMap(), two.getAttributeMap()); } else { assertEquals(one, two); diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java index 0b8e9d186a6cb..e0811b2d85e4f 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java @@ -29,12 +29,12 @@ public class GetRuleRequestTests extends OpenSearchTestCase { */ public void testSerialization() throws IOException { GetRuleRequest request = new GetRuleRequest(_ID_ONE, Map.of(INDEX_PATTERN, Set.of(PATTERN_ONE)), null); - assertEquals(_ID_ONE, request.get_id()); + assertEquals(_ID_ONE, request.getId()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); GetRuleRequest otherRequest = new GetRuleRequest(streamInput); - assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getId(), otherRequest.getId()); assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); } @@ -43,12 +43,12 @@ public void testSerialization() throws IOException { */ public void testSerializationWithNull() throws IOException { GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER); - assertNull(request.get_id()); + assertNull(request.getId()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); GetRuleRequest otherRequest = new GetRuleRequest(streamInput); - assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getId(), otherRequest.getId()); assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); } } diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java index 9c5198704058c..8c9983a1bb770 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java @@ -15,7 +15,6 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; @@ -35,7 +34,7 @@ public class GetRuleResponseTests extends OpenSearchTestCase { * Test case to verify the serialization and deserialization of GetRuleResponse */ public void testSerializationSingleRule() throws IOException { - Map> map = new HashMap<>(); + Map map = new HashMap<>(); map.put(_ID_ONE, ruleOne); GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), null, RestStatus.OK); assertEquals(response.getRules(), map); @@ -70,7 +69,7 @@ public void testSerializationMultipleRule() throws IOException { * Test case to verify the serialization and deserialization of GetRuleResponse when the result is empty */ public void testSerializationNull() throws IOException { - Map> map = new HashMap<>(); + Map map = new HashMap<>(); GetRuleResponse response = new GetRuleResponse(map, SEARCH_AFTER, RestStatus.OK); assertEquals(response.getRules(), map); @@ -87,7 +86,7 @@ public void testSerializationNull() throws IOException { * Test case to verify the toXContent of GetRuleResponse */ public void testToXContentGetSingleRule() throws IOException { - Map> map = new HashMap<>(); + Map map = new HashMap<>(); map.put(_ID_ONE, ruleOne); GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER, RestStatus.OK); XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); @@ -100,7 +99,7 @@ public void testToXContentGetSingleRule() throws IOException { + " \"index_pattern\" : [\n" + " \"pattern_1\"\n" + " ],\n" - + " \"query_group\" : \"label_one\",\n" + + " \"query_group\" : \"feature_value_one\",\n" + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + " }\n" + " ],\n" diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java index da426760086b7..d995cf19a3bd7 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java @@ -11,15 +11,12 @@ import org.opensearch.ResourceNotFoundException; import org.opensearch.action.get.GetRequestBuilder; import org.opensearch.action.get.GetResponse; -import org.opensearch.action.search.SearchRequestBuilder; -import org.opensearch.client.Client; import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.action.ActionListener; import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; -import org.opensearch.search.sort.SortOrder; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.client.Client; import java.io.IOException; import java.util.HashMap; @@ -27,30 +24,25 @@ import org.mockito.ArgumentCaptor; -import static org.opensearch.autotagging.Rule._ID_STRING; import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; import static org.opensearch.plugin.wlm.RuleTestUtils.assertEqualRules; import static org.opensearch.plugin.wlm.RuleTestUtils.ruleOne; import static org.opensearch.plugin.wlm.RuleTestUtils.setUpRulePersistenceService; -import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST; import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.RULES_INDEX; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") public class RulePersistenceServiceTests extends OpenSearchTestCase { - public void testGetRuleById() throws IOException { String ruleSource = ruleOne.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS).toString(); ActionListener listener = mock(ActionListener.class); - RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); Client client = rulePersistenceService.getClient(); GetRequestBuilder getRequestBuilder = mock(GetRequestBuilder.class); GetResponse getResponse = mock(GetResponse.class); @@ -76,7 +68,7 @@ public void testGetRuleById() throws IOException { public void testGetRuleByIdNotFound() { String nonExistentRuleId = "non-existent-rule"; - RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); Client client = rulePersistenceService.getClient(); GetRequestBuilder getRequestBuilder = mock(GetRequestBuilder.class); GetResponse getResponse = mock(GetResponse.class); @@ -99,34 +91,4 @@ public void testGetRuleByIdNotFound() { assertTrue(exception instanceof ResourceNotFoundException); clearInvocations(client, getRequestBuilder, getResponse, listener); } - - public void testBuildGetAllRuleSearchRequest() { - RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); - Client client = rulePersistenceService.getClient(); - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - - when(client.prepareSearch(anyString())).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setQuery(any(BoolQueryBuilder.class))).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST)).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.addSort(eq(_ID_STRING), eq(SortOrder.ASC))).thenReturn(searchRequestBuilder); - - rulePersistenceService.buildGetAllRuleSearchRequest(ruleOne.getAttributeMap(), _ID_ONE); - ArgumentCaptor captor = ArgumentCaptor.forClass(Object[].class); - verify(searchRequestBuilder).searchAfter(captor.capture()); - assertEquals(_ID_ONE, captor.getValue()[0]); - } - - public void testBuildGetAllRuleSearchRequest_noSearchAfter() { - RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); - Client client = rulePersistenceService.getClient(); - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - - when(client.prepareSearch(anyString())).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setQuery(any(BoolQueryBuilder.class))).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST)).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.addSort(eq(_ID_STRING), eq(SortOrder.ASC))).thenReturn(searchRequestBuilder); - - rulePersistenceService.buildGetAllRuleSearchRequest(ruleOne.getAttributeMap(), null); - verify(searchRequestBuilder, times(0)).searchAfter(any()); - } } From d1cab5db8d675ff6062fc02be9fdf55d3751d904 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Tue, 25 Mar 2025 14:43:51 -0700 Subject: [PATCH 04/28] modify based on comments Signed-off-by: Ruirui Zhang --- .../plugin/wlm/rule/QueryGroupAttribute.java | 11 + .../wlm/rule/QueryGroupFeatureType.java | 10 + .../plugin/wlm/rule/action/GetRuleAction.java | 9 + .../wlm/rule/rest/RestGetRuleAction.java | 3 + .../rule/service/RulePersistenceService.java | 220 ++++++------------ .../service/RulePersistenceServiceTests.java | 101 ++++---- 6 files changed, 159 insertions(+), 195 deletions(-) diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java index f57a92bce5c9d..5357a344da407 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java @@ -15,8 +15,12 @@ /** * Attributes specific to the query group feature. + * @opensearch.experimental */ public enum QueryGroupAttribute implements Attribute { + /** + * Represents the index_pattern attribute in QueryGroupAttribute + */ INDEX_PATTERN("index_pattern"); private final String name; @@ -31,6 +35,10 @@ public String getName() { return name; } + /** + * Retrieves the QueryGroupAttribute from a name string + * @param name - attribute name + */ public static QueryGroupAttribute fromName(String name) { for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { if (attr.getName().equals(name)) { @@ -40,6 +48,9 @@ public static QueryGroupAttribute fromName(String name) { throw new IllegalArgumentException("Unknown QueryGroupAttribute: " + name); } + /** + * Converts the QueryGroupAttribute values into a map with attribute names as keys. + */ public static Map toMap() { Map map = new HashMap<>(); for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java index feb762b8ad99b..42f45d3d7c5d6 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java @@ -14,8 +14,18 @@ import java.util.Map; +/** + * Represents a feature type specific to the query group feature + * @opensearch.experimental + */ public class QueryGroupFeatureType implements FeatureType { + /** + * The instance for QueryGroupFeatureType + */ public static final QueryGroupFeatureType INSTANCE = new QueryGroupFeatureType(); + /** + * Name for QueryGroupFeatureType + */ public static final String NAME = "query_group"; private static final int MAX_ATTRIBUTE_VALUES = 10; private static final int MAX_ATTRIBUTE_VALUE_LENGTH = 100; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java index 2ee030576c18e..ea53653d2fd67 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java @@ -16,10 +16,19 @@ */ public class GetRuleAction extends ActionType { + /** + * An instance of GetRuleAction + */ public static final GetRuleAction INSTANCE = new GetRuleAction(); + /** + * Name for GetRuleAction + */ public static final String NAME = "cluster:admin/opensearch/wlm/rule/_get"; + /** + * Default constructor for GetRuleAction + */ private GetRuleAction() { super(NAME, GetRuleResponse::new); } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java index c3a9844fc6f33..41dd780b464a5 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java @@ -39,6 +39,9 @@ * @opensearch.experimental */ public class RestGetRuleAction extends BaseRestHandler { + /** + * Field name used for search pagination with the search_after mechanism + */ public static final String SEARCH_AFTER_STRING = "search_after"; /** diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java index a903f80b2249e..ada07ec4705f7 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java @@ -11,7 +11,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.get.GetResponse; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; import org.opensearch.autotagging.Attribute; @@ -19,6 +18,7 @@ import org.opensearch.autotagging.Rule.Builder; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.rest.RestStatus; @@ -36,7 +36,6 @@ import java.io.IOException; import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -50,12 +49,23 @@ * @opensearch.experimental */ public class RulePersistenceService { + /** + * The system index name used for storing rules + */ public static final String RULES_INDEX = ".rules"; private final Client client; private final ClusterService clusterService; private static final Logger logger = LogManager.getLogger(RulePersistenceService.class); + /** + * The maximum number of results allowed per GET request + */ public static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; + /** + * Constructor for RulePersistenceService + * @param clusterService {@link ClusterService} - The cluster service to be used by RulePersistenceService + * @param client {@link Settings} - The client to be used by RulePersistenceService + */ @Inject public RulePersistenceService(final ClusterService clusterService, final Client client) { this.clusterService = clusterService; @@ -63,8 +73,9 @@ public RulePersistenceService(final ClusterService clusterService, final Client } /** - * Entry point for the get rule api logic in persistence service. - * @param id - The id of the rule to get. Get all matching rules when id is null + * Entry point for the get rule api logic in persistence service. If id is provided, we only get a single rule. + * Otherwise, we get all rules that satisfy the attributeFilters. + * @param id - The id of the rule to get. * @param attributeFilters - A map containing the attributes that user want to filter on * @param searchAfter - The sort values from the last document of the previous page, used for pagination * @param listener - ActionListener for GetRuleResponse @@ -75,100 +86,18 @@ public void getRule( String searchAfter, ActionListener listener ) { - if (id != null) { - fetchRuleById(id, listener); - } else { - fetchAllRules(attributeFilters, searchAfter, listener); - } - } - - /** - * Fetch a single rule from system index using id - * @param id - The id of the rule to get - * @param listener - ActionListener for GetRuleResponse - */ - void fetchRuleById(String id, ActionListener listener) { - try (ThreadContext.StoredContext context = getContext()) { - client.prepareGet(RULES_INDEX, id) - .execute(ActionListener.wrap(getResponse -> handleGetOneRuleResponse(id, getResponse, listener), e -> { - logger.error("Failed to fetch rule with ID {}: {}", id, e.getMessage()); - listener.onFailure(e); - })); - } - } - - /** - * Process getResponse from index and send a GetRuleResponse - * @param id - The id of the rule to get - * @param getResponse - Response received from index - * @param listener - ActionListener for GetRuleResponse - */ - private void handleGetOneRuleResponse(String id, GetResponse getResponse, ActionListener listener) { - if (getResponse.isExists()) { - try (ThreadContext.StoredContext context = getContext()) { - XContentParser parser = MediaTypeRegistry.JSON.xContent() - .createParser( - NamedXContentRegistry.EMPTY, - DeprecationHandler.THROW_UNSUPPORTED_OPERATION, - getResponse.getSourceAsString() - ); - listener.onResponse( - new GetRuleResponse( - Map.of(id, Builder.fromXContent(parser, QueryGroupFeatureType.INSTANCE).build()), - null, - RestStatus.OK - ) - ); - } catch (IOException e) { - logger.error("Error parsing rule with ID {}: {}", id, e.getMessage()); - listener.onFailure(e); - } - } else { - listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " not found.")); - } - } - - /** - * Fetch all rule from system index based on attributeFilters. - * @param attributeFilters - A map containing the attributes that user want to filter on - * @param searchAfter - The sort values from the last document of the previous page, used for pagination - * @param listener - ActionListener for GetRuleResponse - */ - private void fetchAllRules(Map> attributeFilters, String searchAfter, ActionListener listener) { + // Stash the current thread context when interacting with system index to perform + // operations as the system itself, bypassing authorization checks. This ensures that + // actions within this block are trusted and executed with system-level privileges. try (ThreadContext.StoredContext context = getContext()) { - client.prepareSearch(RULES_INDEX) - .setSize(0) - .execute( - ActionListener.wrap(countResponse -> handleCountResponse(countResponse, attributeFilters, searchAfter, listener), e -> { - logger.error("Failed to check if index is empty: {}", e.getMessage()); - listener.onFailure(e); - }) - ); - } - } - - /** - * Processes the count response from a search query on the rules index. - * If no rules exist, it responds with an empty result. - * Otherwise, it constructs and executes a search request to retrieve all rules. - * @param countResponse The response from the count query on the rules index. - * @param attributeFilters A map of attribute filters to apply in the search query. - * @param searchAfter The searchAfter parameter for pagination. - * @param listener The action listener to handle the final response or failure. - */ - void handleCountResponse( - SearchResponse countResponse, - Map> attributeFilters, - String searchAfter, - ActionListener listener - ) { - try (ThreadContext.StoredContext context = getContext()) { - if (countResponse.getHits().getTotalHits().value() == 0) { - listener.onResponse(new GetRuleResponse(new HashMap<>(), null, RestStatus.OK)); - return; + BoolQueryBuilder boolQuery = buildGetRuleQuery(id, attributeFilters); + SearchRequestBuilder searchRequest = client.prepareSearch(RULES_INDEX) + .setQuery(boolQuery) + .setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST); + if (searchAfter != null) { + searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); } - SearchRequestBuilder searchRequest = buildGetAllRuleSearchRequest(attributeFilters, searchAfter); - searchRequest.execute(ActionListener.wrap(searchResponse -> handleGetAllRuleResponse(searchResponse, listener), e -> { + searchRequest.execute(ActionListener.wrap(searchResponse -> handleGetRuleResponse(id, searchResponse, listener), e -> { logger.error("Failed to fetch all rules: {}", e.getMessage()); listener.onFailure(e); })); @@ -176,35 +105,29 @@ void handleCountResponse( } /** - * Builds a search request to retrieve all rules from the rules index, applying attribute-based filters - * and ensuring that the rules are associated with the query group feature type. + * Builds a bool query to retrieve rules from the rules index, applying attribute-based filters + * when needed and ensuring that the rules are associated with the query group feature type. + * @param id The ID of the rule to fetch. If not null, the search will return only this specific rule. * @param attributeFilters A map of attributes to their associated set of values used to filter the rules. - * @param searchAfter A cursor to enable pagination, used to fetch results after a specific document. */ - SearchRequestBuilder buildGetAllRuleSearchRequest(Map> attributeFilters, String searchAfter) { - try (ThreadContext.StoredContext context = getContext()) { - BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); - for (Map.Entry> entry : attributeFilters.entrySet()) { - Attribute attribute = entry.getKey(); - Set values = entry.getValue(); - if (values != null && !values.isEmpty()) { - BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); - for (String value : values) { - attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); - } - boolQuery.must(attributeQuery); + BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters) { + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + if (id != null) { + return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); + } + for (Map.Entry> entry : attributeFilters.entrySet()) { + Attribute attribute = entry.getKey(); + Set values = entry.getValue(); + if (values != null && !values.isEmpty()) { + BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); + for (String value : values) { + attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); } + boolQuery.must(attributeQuery); } - boolQuery.filter(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME)); - SearchRequestBuilder searchRequest = client.prepareSearch(RULES_INDEX) - .setQuery(boolQuery) - .setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST) - .addSort(_ID_STRING, SortOrder.ASC); - if (searchAfter != null) { - searchRequest.searchAfter(new Object[] { searchAfter }); - } - return searchRequest; } + boolQuery.filter(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME)); + return boolQuery; } /** @@ -212,41 +135,52 @@ SearchRequestBuilder buildGetAllRuleSearchRequest(Map> at * @param searchResponse - Response received from index * @param listener - ActionListener for GetRuleResponse */ - void handleGetAllRuleResponse(SearchResponse searchResponse, ActionListener listener) { + void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { List hits = Arrays.asList(searchResponse.getHits().getHits()); - try (ThreadContext.StoredContext context = getContext()) { - Map ruleMap = hits.stream().map(hit -> { - String hitId = hit.getId(); - try { - XContentParser parser = MediaTypeRegistry.JSON.xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, hit.getSourceAsString()); - return Map.entry(hitId, Builder.fromXContent(parser, QueryGroupFeatureType.INSTANCE).build()); - } catch (IOException e) { - logger.info( - "Issue met when parsing rule from hit, the feature type for rule id {} is probably not query_group: {}", - hitId, - e.getMessage() - ); - return null; - } - }).filter(Objects::nonNull).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); - listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); + if (id != null && hits.isEmpty()) { + logger.error("Rule with ID " + id + " not found."); + listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " doesn't exist in the .rules index.")); + return; } + Map ruleMap = hits.stream() + .map(hit -> parseRule(hit.getId(), hit.getSourceAsString())) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); + listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); } - private ThreadContext.StoredContext getContext() { - return client.threadPool().getThreadContext().stashContext(); + /** + * Parses a source string into a Rule object + * @param id - document id for the Rule object + * @param source - The raw source string representing the rule to be parsed + */ + private Map.Entry parseRule(String id, String source) { + try ( + XContentParser parser = MediaTypeRegistry.JSON.xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source) + ) { + return Map.entry(id, Builder.fromXContent(parser, QueryGroupFeatureType.INSTANCE).build()); + } catch (IOException e) { + logger.info("Issue met when parsing rule for ID {}: {}", id, e.getMessage()); + return null; + } } - private boolean isExistingQueryGroup(String queryGroupId) { - return clusterService.state().metadata().queryGroups().containsKey(queryGroupId); + private ThreadContext.StoredContext getContext() { + return client.threadPool().getThreadContext().stashContext(); } + /** + * client getter + */ public Client getClient() { return client; } + /** + * clusterService getter + */ public ClusterService getClusterService() { return clusterService; } diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java index d995cf19a3bd7..6bfa8b96cf16e 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java @@ -8,30 +8,27 @@ package org.opensearch.plugin.wlm.rule.service; -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.get.GetRequestBuilder; -import org.opensearch.action.get.GetResponse; -import org.opensearch.common.xcontent.XContentFactory; +import org.opensearch.action.search.SearchRequestBuilder; +import org.opensearch.action.search.SearchResponse; import org.opensearch.core.action.ActionListener; -import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; +import org.opensearch.search.sort.SortOrder; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.Client; -import java.io.IOException; import java.util.HashMap; -import java.util.Map; - -import org.mockito.ArgumentCaptor; +import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.plugin.wlm.RuleTestUtils.ATTRIBUTE_MAP; import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; -import static org.opensearch.plugin.wlm.RuleTestUtils.assertEqualRules; -import static org.opensearch.plugin.wlm.RuleTestUtils.ruleOne; +import static org.opensearch.plugin.wlm.RuleTestUtils._ID_TWO; import static org.opensearch.plugin.wlm.RuleTestUtils.setUpRulePersistenceService; -import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.RULES_INDEX; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -39,56 +36,56 @@ @SuppressWarnings("unchecked") public class RulePersistenceServiceTests extends OpenSearchTestCase { - public void testGetRuleById() throws IOException { - String ruleSource = ruleOne.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS).toString(); - ActionListener listener = mock(ActionListener.class); + public void testBuildGetRuleQuery_WithId() { RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - Client client = rulePersistenceService.getClient(); - GetRequestBuilder getRequestBuilder = mock(GetRequestBuilder.class); - GetResponse getResponse = mock(GetResponse.class); + BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(_ID_ONE, new HashMap<>()); + assertTrue(query.hasClauses()); + assertEquals(QueryBuilders.termQuery(_ID_STRING, _ID_ONE).toString(), query.must().get(0).toString()); + } - when(getResponse.isExists()).thenReturn(true); - when(getResponse.getSourceAsString()).thenReturn(ruleSource); - when(client.prepareGet(eq(RULES_INDEX), eq(_ID_ONE))).thenReturn(getRequestBuilder); - doAnswer(invocation -> { - ActionListener actionListener = invocation.getArgument(0); - actionListener.onResponse(getResponse); - return null; - }).when(getRequestBuilder).execute(any(ActionListener.class)); + public void testBuildGetRuleQuery_WithFilters() { + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(null, ATTRIBUTE_MAP); + assertTrue(query.hasClauses()); + assertEquals(1, query.must().size()); + assertTrue(query.filter().contains(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME))); + } - rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), null, listener); + public void testGetRule_WithId() { + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + Client client = rulePersistenceService.getClient(); + ActionListener listener = mock(ActionListener.class); + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + SetupMocksForGetRule(client, searchRequestBuilder); - ArgumentCaptor captor = ArgumentCaptor.forClass(GetRuleResponse.class); - verify(listener).onResponse(captor.capture()); - GetRuleResponse response = captor.getValue(); - assertNotNull(response); - assertEqualRules(Map.of(_ID_ONE, ruleOne), response.getRules(), false); - clearInvocations(client, getRequestBuilder, getResponse, listener); + rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), null, listener); + verify(client).prepareSearch(RulePersistenceService.RULES_INDEX); + verify(searchRequestBuilder).setQuery(any()); + verify(searchRequestBuilder).execute(any()); } - public void testGetRuleByIdNotFound() { - String nonExistentRuleId = "non-existent-rule"; + public void testGetRule_WithSearchAfter() { RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); Client client = rulePersistenceService.getClient(); - GetRequestBuilder getRequestBuilder = mock(GetRequestBuilder.class); - GetResponse getResponse = mock(GetResponse.class); ActionListener listener = mock(ActionListener.class); + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + SetupMocksForGetRule(client, searchRequestBuilder); + when(searchRequestBuilder.addSort(anyString(), any(SortOrder.class))).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.searchAfter(any())).thenReturn(searchRequestBuilder); - when(client.prepareGet(RULES_INDEX, nonExistentRuleId)).thenReturn(getRequestBuilder); - when(getResponse.isExists()).thenReturn(false); + rulePersistenceService.getRule(null, new HashMap<>(), _ID_TWO, listener); + verify(searchRequestBuilder).addSort(_ID_STRING, SortOrder.ASC); + verify(searchRequestBuilder).searchAfter(new Object[] { _ID_TWO }); + } + public void SetupMocksForGetRule(Client client, SearchRequestBuilder searchRequestBuilder) { + when(client.prepareSearch(anyString())).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setQuery(any())).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); doAnswer(invocation -> { - ActionListener actionListener = invocation.getArgument(0); - actionListener.onResponse(getResponse); + ActionListener searchListener = invocation.getArgument(0); + searchListener.onResponse(mock(SearchResponse.class)); return null; - }).when(getRequestBuilder).execute(any(ActionListener.class)); - - rulePersistenceService.getRule(nonExistentRuleId, new HashMap<>(), null, listener); - - ArgumentCaptor captor = ArgumentCaptor.forClass(Exception.class); - verify(listener).onFailure(captor.capture()); - Exception exception = captor.getValue(); - assertTrue(exception instanceof ResourceNotFoundException); - clearInvocations(client, getRequestBuilder, getResponse, listener); + }).when(searchRequestBuilder).execute(any()); } } From 34fa4ad51acf9c7c5733a0aa1e910624362f82cb Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Sun, 30 Mar 2025 23:30:53 -0700 Subject: [PATCH 05/28] extract common logics to libs Signed-off-by: Ruirui Zhang --- .../rule/action/GetRuleRequest.java | 31 +++------ .../rule/action/GetRuleResponse.java | 26 +------- .../opensearch/rule/action/package-info.java | 12 ++++ .../rule/rest/RestGetRuleAction.java | 44 ++++++------- .../opensearch/rule/rest/package-info.java | 12 ++++ .../rule/service/RulePersistenceService.java | 63 ++++++++++-------- .../opensearch/rule/service/package-info.java | 12 ++++ .../plugin/wlm/WorkloadManagementPlugin.java | 2 +- ...tRuleAction.java => GetWlmRuleAction.java} | 14 ++-- .../wlm/rule/action/GetWlmRuleRequest.java | 52 +++++++++++++++ .../wlm/rule/action/GetWlmRuleResponse.java | 55 ++++++++++++++++ ...on.java => TransportGetWlmRuleAction.java} | 20 +++--- .../wlm/rule/rest/RestGetWlmRuleAction.java | 64 +++++++++++++++++++ .../service/WlmRulePersistenceService.java | 50 +++++++++++++++ .../plugin/wlm/WorkloadGroupTestUtils.java | 2 +- .../WlmRuleTestUtils.java} | 12 ++-- ...Tests.java => GetWlmRuleRequestTests.java} | 16 ++--- ...ests.java => GetWlmRuleResponseTests.java} | 28 ++++---- ...ts.java => RestGetWlmRuleActionTests.java} | 5 +- ...va => WlmRulePersistenceServiceTests.java} | 26 ++++---- 20 files changed, 387 insertions(+), 159 deletions(-) rename {plugins/workload-management/src/main/java/org/opensearch/plugin/wlm => libs/autotagging-commons/src/main/java/org/opensearch}/rule/action/GetRuleRequest.java (71%) rename {plugins/workload-management/src/main/java/org/opensearch/plugin/wlm => libs/autotagging-commons/src/main/java/org/opensearch}/rule/action/GetRuleResponse.java (77%) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java rename {plugins/workload-management/src/main/java/org/opensearch/plugin/wlm => libs/autotagging-commons/src/main/java/org/opensearch}/rule/rest/RestGetRuleAction.java (65%) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java rename {plugins/workload-management/src/main/java/org/opensearch/plugin/wlm => libs/autotagging-commons/src/main/java/org/opensearch}/rule/service/RulePersistenceService.java (78%) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/{GetRuleAction.java => GetWlmRuleAction.java} (60%) create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponse.java rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/{TransportGetRuleAction.java => TransportGetWlmRuleAction.java} (58%) create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{RuleTestUtils.java => rule/WlmRuleTestUtils.java} (90%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/{GetRuleRequestTests.java => GetWlmRuleRequestTests.java} (71%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/{GetRuleResponseTests.java => GetWlmRuleResponseTests.java} (78%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/{RestGetRuleActionTests.java => RestGetWlmRuleActionTests.java} (88%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/{RulePersistenceServiceTests.java => WlmRulePersistenceServiceTests.java} (76%) diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java similarity index 71% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java index 181bd9583ce34..6cae3e860c3ad 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequest.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java @@ -6,14 +6,14 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rule.action; +package org.opensearch.rule.action; import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import java.io.IOException; import java.util.HashSet; @@ -23,36 +23,27 @@ /** * A request for get Rule * Example Request: + * The endpoint "localhost:9200/_wlm/rule" is specific to the Workload Management feature to manage rules * curl -X GET "localhost:9200/_wlm/rule" - get all rules * curl -X GET "localhost:9200/_wlm/rule/{_id}" - get single rule by id - * curl -X GET "localhost:9200/_wlm/rule?index_pattern=a,b" - get all rules containing index_pattern as a or b + * curl -X GET "localhost:9200/_wlm/rule?index_pattern=a,b" - get all rules containing attribute index_pattern as a or b * @opensearch.experimental */ -public class GetRuleRequest extends ActionRequest { +public abstract class GetRuleRequest extends ActionRequest { private final String id; private final Map> attributeFilters; private final String searchAfter; - /** - * Constructor for GetRuleRequest - * @param id - Rule id that we want to get - * @param attributeFilters - Attributes that we want to filter on - * @param searchAfter - The sort values from the last document of the previous page, used for pagination - */ public GetRuleRequest(String id, Map> attributeFilters, String searchAfter) { this.id = id; this.attributeFilters = attributeFilters; this.searchAfter = searchAfter; } - /** - * Constructor for GetRuleRequest - * @param in - A {@link StreamInput} object - */ public GetRuleRequest(StreamInput in) throws IOException { super(in); id = in.readOptionalString(); - attributeFilters = in.readMap(i -> Attribute.from(i, QueryGroupFeatureType.INSTANCE), i -> new HashSet<>(i.readStringList())); + attributeFilters = in.readMap(i -> Attribute.from(i, retrieveFeatureTypeInstance()), i -> new HashSet<>(i.readStringList())); searchAfter = in.readOptionalString(); } @@ -70,22 +61,18 @@ public void writeTo(StreamOutput out) throws IOException { } /** - * id getter + * Abstract method for subclasses to provide specific FeatureType Instance */ + protected abstract FeatureType retrieveFeatureTypeInstance(); + public String getId() { return id; } - /** - * attributeFilters getter - */ public Map> getAttributeFilters() { return attributeFilters; } - /** - * searchAfter getter - */ public String getSearchAfter() { return searchAfter; } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java similarity index 77% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java index 2f45e372b8325..a92d3c4d79df8 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponse.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rule.action; +package org.opensearch.rule.action; import org.opensearch.autotagging.Rule; import org.opensearch.core.action.ActionResponse; @@ -21,7 +21,6 @@ import java.util.Map; import static org.opensearch.autotagging.Rule._ID_STRING; -import static org.opensearch.plugin.wlm.rule.rest.RestGetRuleAction.SEARCH_AFTER_STRING; /** * Response for the get API for Rule. @@ -41,27 +40,17 @@ * } * @opensearch.experimental */ -public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { +public abstract class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { private final Map rules; private final String searchAfter; private final RestStatus restStatus; - /** - * Constructor for GetRuleResponse - * @param rules - The Map of Rules to be included in the response - * @param searchAfter - The searchAfter field for the response - * @param restStatus - The restStatus for the response - */ public GetRuleResponse(final Map rules, String searchAfter, RestStatus restStatus) { this.rules = rules; this.searchAfter = searchAfter; this.restStatus = restStatus; } - /** - * Constructor for GetRuleResponse - * @param in - A {@link StreamInput} object - */ public GetRuleResponse(StreamInput in) throws IOException { this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString(), RestStatus.readFrom(in)); } @@ -82,29 +71,20 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws } builder.endArray(); if (searchAfter != null && !searchAfter.isEmpty()) { - builder.field(SEARCH_AFTER_STRING, new Object[] { searchAfter }); + builder.field("search_after", new Object[] { searchAfter }); } builder.endObject(); return builder; } - /** - * rules getter - */ public Map getRules() { return rules; } - /** - * restStatus getter - */ public RestStatus getRestStatus() { return restStatus; } - /** - * searchAfter getter - */ public String getSearchAfter() { return searchAfter; } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java new file mode 100644 index 0000000000000..91913aff23eac --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * This package contains abstract action classes for rules + */ +package org.opensearch.rule.action; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java similarity index 65% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java index 41dd780b464a5..686b4cbf2406e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleAction.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java @@ -6,21 +6,20 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rule.rest; +package org.opensearch.rule.rest; +import org.opensearch.action.ActionType; import org.opensearch.autotagging.Attribute; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; -import org.opensearch.plugin.wlm.rule.action.GetRuleAction; -import org.opensearch.plugin.wlm.rule.action.GetRuleRequest; -import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.transport.client.node.NodeClient; import java.io.IOException; @@ -32,35 +31,21 @@ import java.util.Set; import static org.opensearch.autotagging.Rule._ID_STRING; -import static org.opensearch.rest.RestRequest.Method.GET; /** * Rest action to get a Rule * @opensearch.experimental */ -public class RestGetRuleAction extends BaseRestHandler { - /** - * Field name used for search pagination with the search_after mechanism - */ +public abstract class RestGetRuleAction extends BaseRestHandler { public static final String SEARCH_AFTER_STRING = "search_after"; - /** - * Constructor for RestGetRuleAction - */ public RestGetRuleAction() {} @Override - public String getName() { - return "get_rule"; - } + public abstract String getName(); - /** - * The list of {@link Route}s that this RestHandler is responsible for handling. - */ @Override - public List routes() { - return List.of(new Route(GET, "_wlm/rule/"), new Route(GET, "_wlm/rule/{_id}")); - } + public abstract List routes(); @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { @@ -70,14 +55,14 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli continue; } String[] valuesArray = request.param(attributeName).split(","); - attributeFilters.put(QueryGroupAttribute.fromName(attributeName), new HashSet<>(Arrays.asList(valuesArray))); + attributeFilters.put(getAttributeFromName(attributeName), new HashSet<>(Arrays.asList(valuesArray))); } - final GetRuleRequest getRuleRequest = new GetRuleRequest( + final GetRuleRequest getRuleRequest = buildGetRuleRequest( request.param(_ID_STRING), attributeFilters, request.param(SEARCH_AFTER_STRING) ); - return channel -> client.execute(GetRuleAction.INSTANCE, getRuleRequest, getRuleResponse(channel)); + return channel -> client.execute(retrieveGetRuleActionInstance(), getRuleRequest, getRuleResponse(channel)); } private RestResponseListener getRuleResponse(final RestChannel channel) { @@ -88,4 +73,13 @@ public RestResponse buildResponse(final GetRuleResponse response) throws Excepti } }; } + + protected abstract Attribute getAttributeFromName(String name); + + /** + * Abstract method for subclasses to provide specific ActionType Instance + */ + protected abstract > T retrieveGetRuleActionInstance(); + + protected abstract GetRuleRequest buildGetRuleRequest(String id, Map> attributeFilters, String searchAfter); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java new file mode 100644 index 0000000000000..c1000b90b1856 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * This package contains abstract rest classes for rules + */ +package org.opensearch.rule.rest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java similarity index 78% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java index ada07ec4705f7..69c957c94bf3d 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java @@ -6,40 +6,46 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rule.service; +package org.opensearch.rule.service; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.opensearch.ResourceAlreadyExistsException; import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.admin.indices.create.CreateIndexRequest; +import org.opensearch.action.admin.indices.create.CreateIndexResponse; +import org.opensearch.action.index.IndexRequest; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; +import org.opensearch.action.update.UpdateRequest; import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; import org.opensearch.autotagging.Rule; import org.opensearch.autotagging.Rule.Builder; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.action.ActionListener; +import org.opensearch.core.action.ActionResponse; import org.opensearch.core.rest.RestStatus; -import org.opensearch.core.xcontent.DeprecationHandler; -import org.opensearch.core.xcontent.MediaTypeRegistry; -import org.opensearch.core.xcontent.NamedXContentRegistry; -import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.core.xcontent.*; import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilders; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; +import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.search.SearchHit; import org.opensearch.search.sort.SortOrder; import org.opensearch.transport.client.Client; import java.io.IOException; +import java.time.Instant; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.HashMap; import java.util.stream.Collectors; import static org.opensearch.autotagging.Rule._ID_STRING; @@ -48,7 +54,7 @@ * This class encapsulates the logic to manage the lifecycle of rules at index level * @opensearch.experimental */ -public class RulePersistenceService { +public abstract class RulePersistenceService { /** * The system index name used for storing rules */ @@ -56,16 +62,12 @@ public class RulePersistenceService { private final Client client; private final ClusterService clusterService; private static final Logger logger = LogManager.getLogger(RulePersistenceService.class); + /** * The maximum number of results allowed per GET request */ public static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; - /** - * Constructor for RulePersistenceService - * @param clusterService {@link ClusterService} - The cluster service to be used by RulePersistenceService - * @param client {@link Settings} - The client to be used by RulePersistenceService - */ @Inject public RulePersistenceService(final ClusterService clusterService, final Client client) { this.clusterService = clusterService; @@ -84,7 +86,7 @@ public void getRule( String id, Map> attributeFilters, String searchAfter, - ActionListener listener + ActionListener listener ) { // Stash the current thread context when interacting with system index to perform // operations as the system itself, bypassing authorization checks. This ensures that @@ -93,7 +95,7 @@ public void getRule( BoolQueryBuilder boolQuery = buildGetRuleQuery(id, attributeFilters); SearchRequestBuilder searchRequest = client.prepareSearch(RULES_INDEX) .setQuery(boolQuery) - .setSize(MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST); + .setSize(getMaxReturnSizeAllowedPerGetRequest()); if (searchAfter != null) { searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); } @@ -110,7 +112,7 @@ public void getRule( * @param id The ID of the rule to fetch. If not null, the search will return only this specific rule. * @param attributeFilters A map of attributes to their associated set of values used to filter the rules. */ - BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters) { + public BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters) { BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); if (id != null) { return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); @@ -126,7 +128,7 @@ BoolQueryBuilder buildGetRuleQuery(String id, Map> attrib boolQuery.must(attributeQuery); } } - boolQuery.filter(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME)); + boolQuery.filter(QueryBuilders.existsQuery(retrieveFeatureTypeInstance().getName())); return boolQuery; } @@ -135,7 +137,7 @@ BoolQueryBuilder buildGetRuleQuery(String id, Map> attrib * @param searchResponse - Response received from index * @param listener - ActionListener for GetRuleResponse */ - void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { + void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { List hits = Arrays.asList(searchResponse.getHits().getHits()); if (id != null && hits.isEmpty()) { logger.error("Rule with ID " + id + " not found."); @@ -147,7 +149,7 @@ void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListe .filter(Objects::nonNull) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); - listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); + listener.onResponse(buildGetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); } /** @@ -160,27 +162,36 @@ private Map.Entry parseRule(String id, String source) { XContentParser parser = MediaTypeRegistry.JSON.xContent() .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source) ) { - return Map.entry(id, Builder.fromXContent(parser, QueryGroupFeatureType.INSTANCE).build()); + return Map.entry(id, Builder.fromXContent(parser, retrieveFeatureTypeInstance()).build()); } catch (IOException e) { logger.info("Issue met when parsing rule for ID {}: {}", id, e.getMessage()); return null; } } - private ThreadContext.StoredContext getContext() { - return client.threadPool().getThreadContext().stashContext(); + private boolean isExistingQueryGroup(String queryGroupId) { + return clusterService.state().metadata().queryGroups().containsKey(queryGroupId); } /** - * client getter + * Abstract method for subclasses to provide specific FeatureType Instance */ + protected abstract FeatureType retrieveFeatureTypeInstance(); + + protected abstract T buildGetRuleResponse(Map ruleMap, String nextSearchAfter, RestStatus restStatus); + + private ThreadContext.StoredContext getContext() { + return client.threadPool().getThreadContext().stashContext(); + } + + public int getMaxReturnSizeAllowedPerGetRequest() { + return MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST; + } + public Client getClient() { return client; } - /** - * clusterService getter - */ public ClusterService getClusterService() { return clusterService; } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java new file mode 100644 index 0000000000000..f51b281884dc6 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * This package contains abstract service classes for rules + */ +package org.opensearch.rule.service; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index f92c8a4df80e0..fa2cb33182255 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -45,7 +45,7 @@ import java.util.List; import java.util.function.Supplier; -import static org.opensearch.plugin.wlm.rule.service.RulePersistenceService.RULES_INDEX; +import static org.opensearch.plugin.wlm.rule.service.WlmRulePersistenceService.RULES_INDEX; /** * Plugin class for WorkloadManagement diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java similarity index 60% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java index ea53653d2fd67..95ecbe6d6a4ec 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java @@ -14,22 +14,22 @@ * Action type for getting Rules in workload management * @opensearch.experimental */ -public class GetRuleAction extends ActionType { +public class GetWlmRuleAction extends ActionType { /** - * An instance of GetRuleAction + * An instance of GetWlmRuleAction */ - public static final GetRuleAction INSTANCE = new GetRuleAction(); + public static final GetWlmRuleAction INSTANCE = new GetWlmRuleAction(); /** - * Name for GetRuleAction + * Name for GetWlmRuleAction */ public static final String NAME = "cluster:admin/opensearch/wlm/rule/_get"; /** - * Default constructor for GetRuleAction + * Default constructor for GetWlmRuleAction */ - private GetRuleAction() { - super(NAME, GetRuleResponse::new); + private GetWlmRuleAction() { + super(NAME, GetWlmRuleResponse::new); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java new file mode 100644 index 0000000000000..d2b3e6f9c962f --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; +import org.opensearch.rule.action.GetRuleRequest; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; + +/** + * A request to get workload management Rules in workload management + * Example Request: + * curl -X GET "localhost:9200/_wlm/rule" - get all rules + * curl -X GET "localhost:9200/_wlm/rule/{_id}" - get single rule by id + * curl -X GET "localhost:9200/_wlm/rule?index_pattern=a,b" - get all rules containing attribute index_pattern as a or b + * @opensearch.experimental + */ +public class GetWlmRuleRequest extends GetRuleRequest { + /** + * Constructor for GetWlmRuleRequest + * @param id - Rule id to get + * @param attributeFilters - A map containing the attributes to filter on + * @param searchAfter - A string used for pagination + */ + public GetWlmRuleRequest(String id, Map> attributeFilters, String searchAfter) { + super(id, attributeFilters, searchAfter); + } + + /** + * Constructs a new GetWlmRuleRequest instance from StreamInput + * @param in The {@link StreamInput} from which to read the request data. + */ + public GetWlmRuleRequest(StreamInput in) throws IOException { + super(in); + } + + @Override + protected FeatureType retrieveFeatureTypeInstance() { + return QueryGroupFeatureType.INSTANCE; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponse.java new file mode 100644 index 0000000000000..c3ab2a80ecf1a --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponse.java @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.autotagging.Rule; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.rule.action.GetRuleResponse; + +import java.io.IOException; +import java.util.Map; + +/** + * A response to get workload management Rules in workload management + * Example response: + * { + * "rules": [ + * { + * "_id": "z1MJApUB0zgMcDmz-UQq", + * "description": "Rule for tagging query_group_id to index123" + * "index_pattern": ["index123"], + * "query_group": "query_group_id", + * "updated_at": "2025-02-14T01:19:22.589Z" + * }, + * ... + * ], + * "search_after": ["z1MJApUB0zgMcDmz-UQq"] + * } + * @opensearch.experimental + */ +public class GetWlmRuleResponse extends GetRuleResponse { + /** + * Constructor for GetWlmRuleResponse + * @param rules - A map of rule IDs to objects representing the retrieved rules + * @param searchAfter - A string used for pagination + * @param restStatus - The {@link RestStatus} indicating the status of the request. + */ + public GetWlmRuleResponse(Map rules, String searchAfter, RestStatus restStatus) { + super(rules, searchAfter, restStatus); + } + + /** + * Constructs a new GetWlmRuleResponse instance from StreamInput + * @param in The {@link StreamInput} from which to read the response data. + */ + public GetWlmRuleResponse(StreamInput in) throws IOException { + super(in); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java similarity index 58% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java index 7b9a77d78e328..ca20ea4d1815a 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java @@ -12,36 +12,36 @@ import org.opensearch.action.support.HandledTransportAction; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; -import org.opensearch.plugin.wlm.rule.service.RulePersistenceService; +import org.opensearch.plugin.wlm.rule.service.WlmRulePersistenceService; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; /** - * Transport action to get Rule + * Transport action to get workload management Rules * @opensearch.experimental */ -public class TransportGetRuleAction extends HandledTransportAction { +public class TransportGetWlmRuleAction extends HandledTransportAction { - private final RulePersistenceService rulePersistenceService; + private final WlmRulePersistenceService rulePersistenceService; /** - * Constructor for TransportGetRuleAction + * Constructor for TransportGetWlmRuleAction * @param transportService - a {@link TransportService} object * @param actionFilters - a {@link ActionFilters} object - * @param rulePersistenceService - a {@link RulePersistenceService} object + * @param rulePersistenceService - a {@link WlmRulePersistenceService} object */ @Inject - public TransportGetRuleAction( + public TransportGetWlmRuleAction( TransportService transportService, ActionFilters actionFilters, - RulePersistenceService rulePersistenceService + WlmRulePersistenceService rulePersistenceService ) { - super(GetRuleAction.NAME, transportService, actionFilters, GetRuleRequest::new); + super(GetWlmRuleAction.NAME, transportService, actionFilters, GetWlmRuleRequest::new); this.rulePersistenceService = rulePersistenceService; } @Override - protected void doExecute(Task task, GetRuleRequest request, ActionListener listener) { + protected void doExecute(Task task, GetWlmRuleRequest request, ActionListener listener) { rulePersistenceService.getRule(request.getId(), request.getAttributeFilters(), request.getSearchAfter(), listener); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java new file mode 100644 index 0000000000000..11f7776c77c21 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.rest; + +import org.opensearch.action.ActionType; +import org.opensearch.autotagging.Attribute; +import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; +import org.opensearch.plugin.wlm.rule.action.GetWlmRuleAction; +import org.opensearch.plugin.wlm.rule.action.GetWlmRuleRequest; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.rest.RestGetRuleAction; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.rest.RestRequest.Method.GET; + +/** + * Rest action to get workload management Rules + * @opensearch.experimental + */ +public class RestGetWlmRuleAction extends RestGetRuleAction { + + /** + * Constructor for RestGetWlmRuleAction + */ + public RestGetWlmRuleAction() { + super(); + } + + @Override + public String getName() { + return "get_rule"; + } + + @Override + public List routes() { + return List.of(new Route(GET, "_wlm/rule/"), new Route(GET, "_wlm/rule/{_id}")); + } + + @Override + protected Attribute getAttributeFromName(String name) { + return QueryGroupAttribute.fromName(name); + } + + @Override + @SuppressWarnings("unchecked") + protected > T retrieveGetRuleActionInstance() { + return (T) GetWlmRuleAction.INSTANCE; + } + + @Override + protected GetRuleRequest buildGetRuleRequest(String id, Map> attributeFilters, String searchAfter) { + return new GetWlmRuleRequest(id, attributeFilters, searchAfter); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java new file mode 100644 index 0000000000000..5ee6a1d65dbb0 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java @@ -0,0 +1,50 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.service; + +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; +import org.opensearch.plugin.wlm.rule.action.GetWlmRuleResponse; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.service.RulePersistenceService; +import org.opensearch.transport.client.Client; + +import java.util.Map; + +/** + * This class encapsulates the logic to manage the lifecycle of workload management rules at index level + * @opensearch.experimental + */ +@SuppressWarnings("unchecked") +public class WlmRulePersistenceService extends RulePersistenceService { + /** + * Constructor for WlmRulePersistenceService + * @param clusterService {@link ClusterService} - The cluster service to be used by RulePersistenceService + * @param client {@link Settings} - The client to be used by RulePersistenceService + */ + @Inject + public WlmRulePersistenceService(ClusterService clusterService, Client client) { + super(clusterService, client); + } + + @Override + protected FeatureType retrieveFeatureTypeInstance() { + return QueryGroupFeatureType.INSTANCE; + } + + @Override + protected T buildGetRuleResponse(Map ruleMap, String nextSearchAfter, RestStatus restStatus) { + return (T) new GetWlmRuleResponse(ruleMap, nextSearchAfter, restStatus); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java index bac644a172c1e..dac26c3c0f929 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm; +package org.opensearch.plugin.wlm.querygroup; import org.opensearch.cluster.ClusterName; import org.opensearch.cluster.ClusterState; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java similarity index 90% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java index e00614055d250..f374ae8f5b703 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm; +package org.opensearch.plugin.wlm.rule; import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.Rule; @@ -16,9 +16,7 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.plugin.wlm.rule.service.RulePersistenceService; +import org.opensearch.plugin.wlm.rule.service.WlmRulePersistenceService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.client.Client; @@ -30,7 +28,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class RuleTestUtils { +public class WlmRuleTestUtils { public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; public static final String FEATURE_VALUE_ONE = "feature_value_one"; @@ -63,7 +61,7 @@ public static Map ruleMap() { return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); } - public static RulePersistenceService setUpRulePersistenceService(Map queryGroupMap) { + public static WlmRulePersistenceService setUpRulePersistenceService(Map queryGroupMap) { Client client = mock(Client.class); ClusterService clusterService = mock(ClusterService.class); ClusterState clusterState = mock(ClusterState.class); @@ -76,7 +74,7 @@ public static RulePersistenceService setUpRulePersistenceService(Map mapOne, Map mapTwo, boolean ruleUpdated) { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java similarity index 71% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java index e0811b2d85e4f..d3eb6fba53821 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java @@ -17,23 +17,23 @@ import java.util.Map; import java.util.Set; -import static org.opensearch.plugin.wlm.RuleTestUtils.PATTERN_ONE; -import static org.opensearch.plugin.wlm.RuleTestUtils.SEARCH_AFTER; -import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; import static org.opensearch.plugin.wlm.rule.QueryGroupAttribute.INDEX_PATTERN; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.PATTERN_ONE; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.SEARCH_AFTER; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils._ID_ONE; -public class GetRuleRequestTests extends OpenSearchTestCase { +public class GetWlmRuleRequestTests extends OpenSearchTestCase { /** * Test case to verify the serialization and deserialization of GetRuleRequest */ public void testSerialization() throws IOException { - GetRuleRequest request = new GetRuleRequest(_ID_ONE, Map.of(INDEX_PATTERN, Set.of(PATTERN_ONE)), null); + GetWlmRuleRequest request = new GetWlmRuleRequest(_ID_ONE, Map.of(INDEX_PATTERN, Set.of(PATTERN_ONE)), null); assertEquals(_ID_ONE, request.getId()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); - GetRuleRequest otherRequest = new GetRuleRequest(streamInput); + GetWlmRuleRequest otherRequest = new GetWlmRuleRequest(streamInput); assertEquals(request.getId(), otherRequest.getId()); assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); } @@ -42,12 +42,12 @@ public void testSerialization() throws IOException { * Test case to verify the serialization and deserialization of GetRuleRequest when name is null */ public void testSerializationWithNull() throws IOException { - GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER); + GetWlmRuleRequest request = new GetWlmRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER); assertNull(request.getId()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); - GetRuleRequest otherRequest = new GetRuleRequest(streamInput); + GetWlmRuleRequest otherRequest = new GetWlmRuleRequest(streamInput); assertEquals(request.getId(), otherRequest.getId()); assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); } diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponseTests.java similarity index 78% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponseTests.java index 8c9983a1bb770..76f1f7a0a2534 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetRuleResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponseTests.java @@ -21,14 +21,14 @@ import java.util.HashMap; import java.util.Map; -import static org.opensearch.plugin.wlm.RuleTestUtils.SEARCH_AFTER; -import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; -import static org.opensearch.plugin.wlm.RuleTestUtils.assertEqualRules; -import static org.opensearch.plugin.wlm.RuleTestUtils.ruleMap; -import static org.opensearch.plugin.wlm.RuleTestUtils.ruleOne; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.SEARCH_AFTER; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils._ID_ONE; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.assertEqualRules; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.ruleMap; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.ruleOne; import static org.mockito.Mockito.mock; -public class GetRuleResponseTests extends OpenSearchTestCase { +public class GetWlmRuleResponseTests extends OpenSearchTestCase { /** * Test case to verify the serialization and deserialization of GetRuleResponse @@ -36,14 +36,14 @@ public class GetRuleResponseTests extends OpenSearchTestCase { public void testSerializationSingleRule() throws IOException { Map map = new HashMap<>(); map.put(_ID_ONE, ruleOne); - GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), null, RestStatus.OK); + GetWlmRuleResponse response = new GetWlmRuleResponse(Map.of(_ID_ONE, ruleOne), null, RestStatus.OK); assertEquals(response.getRules(), map); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); - GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + GetWlmRuleResponse otherResponse = new GetWlmRuleResponse(streamInput); assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); assertEqualRules(response.getRules(), otherResponse.getRules(), false); } @@ -52,14 +52,14 @@ public void testSerializationSingleRule() throws IOException { * Test case to verify the serialization and deserialization of GetRuleResponse when the result contains multiple rules */ public void testSerializationMultipleRule() throws IOException { - GetRuleResponse response = new GetRuleResponse(ruleMap(), SEARCH_AFTER, RestStatus.OK); + GetWlmRuleResponse response = new GetWlmRuleResponse(ruleMap(), SEARCH_AFTER, RestStatus.OK); assertEquals(response.getRules(), ruleMap()); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); - GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + GetWlmRuleResponse otherResponse = new GetWlmRuleResponse(streamInput); assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); assertEquals(2, otherResponse.getRules().size()); assertEqualRules(response.getRules(), otherResponse.getRules(), false); @@ -70,14 +70,14 @@ public void testSerializationMultipleRule() throws IOException { */ public void testSerializationNull() throws IOException { Map map = new HashMap<>(); - GetRuleResponse response = new GetRuleResponse(map, SEARCH_AFTER, RestStatus.OK); + GetWlmRuleResponse response = new GetWlmRuleResponse(map, SEARCH_AFTER, RestStatus.OK); assertEquals(response.getRules(), map); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); - GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + GetWlmRuleResponse otherResponse = new GetWlmRuleResponse(streamInput); assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); assertEquals(0, otherResponse.getRules().size()); } @@ -88,7 +88,7 @@ public void testSerializationNull() throws IOException { public void testToXContentGetSingleRule() throws IOException { Map map = new HashMap<>(); map.put(_ID_ONE, ruleOne); - GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER, RestStatus.OK); + GetWlmRuleResponse response = new GetWlmRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER, RestStatus.OK); XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" @@ -115,7 +115,7 @@ public void testToXContentGetSingleRule() throws IOException { */ public void testToXContentGetZeroRule() throws IOException { XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - GetRuleResponse otherResponse = new GetRuleResponse(new HashMap<>(), null, RestStatus.OK); + GetWlmRuleResponse otherResponse = new GetWlmRuleResponse(new HashMap<>(), null, RestStatus.OK); String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" + " \"rules\" : [ ]\n" + "}"; assertEquals(expected, actual); diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleActionTests.java similarity index 88% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleActionTests.java index c09600be6fc6e..a0f61cbaf3c8b 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetRuleActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleActionTests.java @@ -1,3 +1,4 @@ + /* * SPDX-License-Identifier: Apache-2.0 * @@ -15,12 +16,12 @@ import static org.opensearch.rest.RestRequest.Method.GET; -public class RestGetRuleActionTests extends OpenSearchTestCase { +public class RestGetWlmRuleActionTests extends OpenSearchTestCase { /** * Test case to validate the construction for RestGetRuleAction */ public void testConstruction() { - RestGetRuleAction action = new RestGetRuleAction(); + RestGetWlmRuleAction action = new RestGetWlmRuleAction(); assertNotNull(action); assertEquals("get_rule", action.getName()); List routes = action.routes(); diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java similarity index 76% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java index 6bfa8b96cf16e..4a1cc1c122ecd 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java @@ -14,7 +14,7 @@ import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilders; import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.plugin.wlm.rule.action.GetRuleResponse; +import org.opensearch.plugin.wlm.rule.action.GetWlmRuleResponse; import org.opensearch.search.sort.SortOrder; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.Client; @@ -22,10 +22,10 @@ import java.util.HashMap; import static org.opensearch.autotagging.Rule._ID_STRING; -import static org.opensearch.plugin.wlm.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.plugin.wlm.RuleTestUtils._ID_ONE; -import static org.opensearch.plugin.wlm.RuleTestUtils._ID_TWO; -import static org.opensearch.plugin.wlm.RuleTestUtils.setUpRulePersistenceService; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils._ID_ONE; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils._ID_TWO; +import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.setUpRulePersistenceService; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; @@ -35,16 +35,16 @@ import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") -public class RulePersistenceServiceTests extends OpenSearchTestCase { +public class WlmRulePersistenceServiceTests extends OpenSearchTestCase { public void testBuildGetRuleQuery_WithId() { - RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(_ID_ONE, new HashMap<>()); assertTrue(query.hasClauses()); assertEquals(QueryBuilders.termQuery(_ID_STRING, _ID_ONE).toString(), query.must().get(0).toString()); } public void testBuildGetRuleQuery_WithFilters() { - RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(null, ATTRIBUTE_MAP); assertTrue(query.hasClauses()); assertEquals(1, query.must().size()); @@ -52,22 +52,22 @@ public void testBuildGetRuleQuery_WithFilters() { } public void testGetRule_WithId() { - RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); Client client = rulePersistenceService.getClient(); - ActionListener listener = mock(ActionListener.class); + ActionListener listener = mock(ActionListener.class); SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); SetupMocksForGetRule(client, searchRequestBuilder); rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), null, listener); - verify(client).prepareSearch(RulePersistenceService.RULES_INDEX); + verify(client).prepareSearch(WlmRulePersistenceService.RULES_INDEX); verify(searchRequestBuilder).setQuery(any()); verify(searchRequestBuilder).execute(any()); } public void testGetRule_WithSearchAfter() { - RulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); Client client = rulePersistenceService.getClient(); - ActionListener listener = mock(ActionListener.class); + ActionListener listener = mock(ActionListener.class); SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); SetupMocksForGetRule(client, searchRequestBuilder); when(searchRequestBuilder.addSort(anyString(), any(SortOrder.class))).thenReturn(searchRequestBuilder); From 09178eb5b5c50bf209b42dc31f8a2bcfe2440887 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Mon, 31 Mar 2025 16:22:32 -0700 Subject: [PATCH 06/28] Add javadocs for libs Signed-off-by: Ruirui Zhang --- .../rule/action/GetRuleRequest.java | 19 ++++++++ .../rule/action/GetRuleResponse.java | 20 +++++++-- .../rule/rest/RestGetRuleAction.java | 19 ++++++++ .../rule/service/RulePersistenceService.java | 45 +++++++++++++------ 4 files changed, 85 insertions(+), 18 deletions(-) diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java index 6cae3e860c3ad..f3b3c61ee17f6 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java @@ -34,12 +34,22 @@ public abstract class GetRuleRequest extends ActionRequest { private final Map> attributeFilters; private final String searchAfter; + /** + * Constructor for GetRuleRequest + * @param id - Rule id to get + * @param attributeFilters - Rules will be filtered based on the attribute-value mappings. + * @param searchAfter - The sort value used for pagination. + */ public GetRuleRequest(String id, Map> attributeFilters, String searchAfter) { this.id = id; this.attributeFilters = attributeFilters; this.searchAfter = searchAfter; } + /** + * Constructs a GetRuleRequest from a StreamInput for deserialization + * @param in - The {@link StreamInput} instance to read from. + */ public GetRuleRequest(StreamInput in) throws IOException { super(in); id = in.readOptionalString(); @@ -65,14 +75,23 @@ public void writeTo(StreamOutput out) throws IOException { */ protected abstract FeatureType retrieveFeatureTypeInstance(); + /** + * id getter + */ public String getId() { return id; } + /** + * attributeFilters getter + */ public Map> getAttributeFilters() { return attributeFilters; } + /** + * searchAfter getter + */ public String getSearchAfter() { return searchAfter; } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java index a92d3c4d79df8..954c39cfdfc8e 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java @@ -45,12 +45,22 @@ public abstract class GetRuleResponse extends ActionResponse implements ToXConte private final String searchAfter; private final RestStatus restStatus; + /** + * Constructor for GetRuleResponse + * @param rules - Rules get from the request + * @param searchAfter - The sort value used for pagination. + * @param restStatus - Status of the GetRuleResponse + */ public GetRuleResponse(final Map rules, String searchAfter, RestStatus restStatus) { this.rules = rules; this.searchAfter = searchAfter; this.restStatus = restStatus; } + /** + * Constructs a GetRuleResponse from a StreamInput for deserialization + * @param in - The {@link StreamInput} instance to read from. + */ public GetRuleResponse(StreamInput in) throws IOException { this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString(), RestStatus.readFrom(in)); } @@ -77,15 +87,17 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } + /** + * rules getter + */ public Map getRules() { return rules; } + /** + * restStatus getter + */ public RestStatus getRestStatus() { return restStatus; } - - public String getSearchAfter() { - return searchAfter; - } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java index 686b4cbf2406e..f27bdfbbb4e59 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java @@ -37,8 +37,14 @@ * @opensearch.experimental */ public abstract class RestGetRuleAction extends BaseRestHandler { + /** + * field name used for pagination + */ public static final String SEARCH_AFTER_STRING = "search_after"; + /** + * Constructor for RestGetRuleAction + */ public RestGetRuleAction() {} @Override @@ -74,6 +80,11 @@ public RestResponse buildResponse(final GetRuleResponse response) throws Excepti }; } + /** + * Abstract method for subclasses to retrieve the Attribute corresponding + * to the attribute name. + * @param name - The name of the attribute to retrieve. + */ protected abstract Attribute getAttributeFromName(String name); /** @@ -81,5 +92,13 @@ public RestResponse buildResponse(final GetRuleResponse response) throws Excepti */ protected abstract > T retrieveGetRuleActionInstance(); + /** + * Abstract method for subclasses to construct a {@link GetRuleRequest}. This method allows subclasses + * to define their own request-building logic depending on their specific needs. + * + * @param id - The ID of the rule to retrieve. + * @param attributeFilters - A map of {@link Attribute} keys to sets of string values for filtering. + * @param searchAfter - The pagination value to fetch the next set of results. + */ protected abstract GetRuleRequest buildGetRuleRequest(String id, Map> attributeFilters, String searchAfter); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java index 69c957c94bf3d..cb5eebb94a54c 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java @@ -10,27 +10,22 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.ResourceAlreadyExistsException; import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.admin.indices.create.CreateIndexRequest; -import org.opensearch.action.admin.indices.create.CreateIndexResponse; -import org.opensearch.action.index.IndexRequest; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; -import org.opensearch.action.update.UpdateRequest; import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.FeatureType; import org.opensearch.autotagging.Rule; import org.opensearch.autotagging.Rule.Builder; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; -import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.action.ActionListener; -import org.opensearch.core.action.ActionResponse; import org.opensearch.core.rest.RestStatus; -import org.opensearch.core.xcontent.*; +import org.opensearch.core.xcontent.DeprecationHandler; +import org.opensearch.core.xcontent.MediaTypeRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.core.xcontent.XContentParser; import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilders; import org.opensearch.rule.action.GetRuleResponse; @@ -39,13 +34,11 @@ import org.opensearch.transport.client.Client; import java.io.IOException; -import java.time.Instant; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.HashMap; import java.util.stream.Collectors; import static org.opensearch.autotagging.Rule._ID_STRING; @@ -68,6 +61,11 @@ public abstract class RulePersistenceService { */ public static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; + /** + * Constructor for RulePersistenceService + * @param clusterService - The {@link ClusterService} to be used by RulePersistenceService + * @param client - The {@link Client} to be used by RulePersistenceService + */ @Inject public RulePersistenceService(final ClusterService clusterService, final Client client) { this.clusterService = clusterService; @@ -109,8 +107,8 @@ public void getRule( /** * Builds a bool query to retrieve rules from the rules index, applying attribute-based filters * when needed and ensuring that the rules are associated with the query group feature type. - * @param id The ID of the rule to fetch. If not null, the search will return only this specific rule. - * @param attributeFilters A map of attributes to their associated set of values used to filter the rules. + * @param id - The ID of the rule to fetch. If not null, the search will return only this specific rule. + * @param attributeFilters - A map of attributes to their associated set of values used to filter the rules. */ public BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters) { BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); @@ -178,20 +176,39 @@ private boolean isExistingQueryGroup(String queryGroupId) { */ protected abstract FeatureType retrieveFeatureTypeInstance(); - protected abstract T buildGetRuleResponse(Map ruleMap, String nextSearchAfter, RestStatus restStatus); + /** + * Builds a GetRuleResponse. Subclasses can override based on their own needs. + * @param ruleMap - The map of rules the response contains + * @param nextSearchAfter - The search after string containing a rule id used for pagination + * @param restStatus - Status of the response + */ + protected abstract T buildGetRuleResponse( + Map ruleMap, + String nextSearchAfter, + RestStatus restStatus + ); private ThreadContext.StoredContext getContext() { return client.threadPool().getThreadContext().stashContext(); } + /** + * Get the max return size allowed for page for get request when pagination is needed + */ public int getMaxReturnSizeAllowedPerGetRequest() { return MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST; } + /** + * client getter + */ public Client getClient() { return client; } + /** + * clusterService getter + */ public ClusterService getClusterService() { return clusterService; } From f7a324af0c0cb846f73f4bf153c6541fa9737ca6 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Wed, 2 Apr 2025 00:08:06 -0700 Subject: [PATCH 07/28] modify based on comments Signed-off-by: Ruirui Zhang --- .../rule/action/GetRuleRequest.java | 16 +- .../rule/service/RulePersistenceService.java | 144 ++++-------------- .../rule/service/RuleProcessingService.java | 63 ++++++++ .../rule/service/RuleResponseBuilder.java | 29 ++++ .../opensearch/rule/service/RuleService.java | 74 +++++++++ .../wlm/rule/action/GetWlmRuleRequest.java | 15 +- .../action/TransportGetWlmRuleAction.java | 16 +- .../wlm/rule/rest/RestGetWlmRuleAction.java | 3 +- .../service/WlmRulePersistenceService.java | 33 ++-- .../service/WlmRuleProcessingService.java | 20 +++ .../rule/service/WlmRuleResponseBuilder.java | 25 +++ .../rule/action/GetWlmRuleRequestTests.java | 10 +- .../WlmRulePersistenceServiceTests.java | 5 +- .../java/org/opensearch/autotagging/Rule.java | 23 +++ 14 files changed, 315 insertions(+), 161 deletions(-) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleProcessingService.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleResponseBuilder.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleService.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleProcessingService.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleResponseBuilder.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java index f3b3c61ee17f6..052ceb90bbf77 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java @@ -33,27 +33,31 @@ public abstract class GetRuleRequest extends ActionRequest { private final String id; private final Map> attributeFilters; private final String searchAfter; + private final FeatureType featureType; /** * Constructor for GetRuleRequest * @param id - Rule id to get * @param attributeFilters - Rules will be filtered based on the attribute-value mappings. * @param searchAfter - The sort value used for pagination. + * @param featureType - The feature type related to rule. */ - public GetRuleRequest(String id, Map> attributeFilters, String searchAfter) { + public GetRuleRequest(String id, Map> attributeFilters, String searchAfter, FeatureType featureType) { this.id = id; this.attributeFilters = attributeFilters; this.searchAfter = searchAfter; + this.featureType = featureType; } /** - * Constructs a GetRuleRequest from a StreamInput for deserialization + * Constructs a GetRuleRequest from a StreamInput for deserialization. * @param in - The {@link StreamInput} instance to read from. */ public GetRuleRequest(StreamInput in) throws IOException { super(in); id = in.readOptionalString(); - attributeFilters = in.readMap(i -> Attribute.from(i, retrieveFeatureTypeInstance()), i -> new HashSet<>(i.readStringList())); + featureType = FeatureType.from(in); + attributeFilters = in.readMap(i -> Attribute.from(i, featureType), i -> new HashSet<>(i.readStringList())); searchAfter = in.readOptionalString(); } @@ -66,15 +70,11 @@ public ActionRequestValidationException validate() { public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeOptionalString(id); + featureType.writeTo(out); out.writeMap(attributeFilters, (output, attribute) -> attribute.writeTo(output), StreamOutput::writeStringCollection); out.writeOptionalString(searchAfter); } - /** - * Abstract method for subclasses to provide specific FeatureType Instance - */ - protected abstract FeatureType retrieveFeatureTypeInstance(); - /** * id getter */ diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java index cb5eebb94a54c..08856b38cdb08 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java @@ -10,36 +10,20 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.ResourceNotFoundException; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; -import org.opensearch.autotagging.Rule.Builder; import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.inject.Inject; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.core.xcontent.DeprecationHandler; -import org.opensearch.core.xcontent.MediaTypeRegistry; -import org.opensearch.core.xcontent.NamedXContentRegistry; -import org.opensearch.core.xcontent.XContentParser; import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilders; -import org.opensearch.rule.action.GetRuleResponse; -import org.opensearch.search.SearchHit; import org.opensearch.search.sort.SortOrder; import org.opensearch.transport.client.Client; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; import static org.opensearch.autotagging.Rule._ID_STRING; @@ -47,31 +31,39 @@ * This class encapsulates the logic to manage the lifecycle of rules at index level * @opensearch.experimental */ -public abstract class RulePersistenceService { +public interface RulePersistenceService { + /** + * The default maximum number of results allowed per GET request + */ + int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; + /** * The system index name used for storing rules */ - public static final String RULES_INDEX = ".rules"; - private final Client client; - private final ClusterService clusterService; - private static final Logger logger = LogManager.getLogger(RulePersistenceService.class); + String getIndexName(); + + /** + * client getter + */ + Client getClient(); /** - * The maximum number of results allowed per GET request + * clusterService getter */ - public static final int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; + ClusterService getClusterService(); /** - * Constructor for RulePersistenceService - * @param clusterService - The {@link ClusterService} to be used by RulePersistenceService - * @param client - The {@link Client} to be used by RulePersistenceService + * Get the max return size allowed for page for get request when pagination is needed */ - @Inject - public RulePersistenceService(final ClusterService clusterService, final Client client) { - this.clusterService = clusterService; - this.client = client; + default int getMaxReturnSizeAllowedPerGetRequest() { + return MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST; } + /** + * logger for RulePersistenceService + */ + Logger logger = LogManager.getLogger(RulePersistenceService.class); + /** * Entry point for the get rule api logic in persistence service. If id is provided, we only get a single rule. * Otherwise, we get all rules that satisfy the attributeFilters. @@ -80,24 +72,24 @@ public RulePersistenceService(final ClusterService clusterService, final Client * @param searchAfter - The sort values from the last document of the previous page, used for pagination * @param listener - ActionListener for GetRuleResponse */ - public void getRule( + default void getRule( String id, Map> attributeFilters, String searchAfter, - ActionListener listener + ActionListener listener ) { // Stash the current thread context when interacting with system index to perform // operations as the system itself, bypassing authorization checks. This ensures that // actions within this block are trusted and executed with system-level privileges. try (ThreadContext.StoredContext context = getContext()) { BoolQueryBuilder boolQuery = buildGetRuleQuery(id, attributeFilters); - SearchRequestBuilder searchRequest = client.prepareSearch(RULES_INDEX) + SearchRequestBuilder searchRequest = getClient().prepareSearch(getIndexName()) .setQuery(boolQuery) .setSize(getMaxReturnSizeAllowedPerGetRequest()); if (searchAfter != null) { searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); } - searchRequest.execute(ActionListener.wrap(searchResponse -> handleGetRuleResponse(id, searchResponse, listener), e -> { + searchRequest.execute(ActionListener.wrap(listener::onResponse, e -> { logger.error("Failed to fetch all rules: {}", e.getMessage()); listener.onFailure(e); })); @@ -107,10 +99,10 @@ public void getRule( /** * Builds a bool query to retrieve rules from the rules index, applying attribute-based filters * when needed and ensuring that the rules are associated with the query group feature type. - * @param id - The ID of the rule to fetch. If not null, the search will return only this specific rule. - * @param attributeFilters - A map of attributes to their associated set of values used to filter the rules. + * @param id The ID of the rule to fetch. If not null, the search will return only this specific rule. + * @param attributeFilters A map of attributes to their associated set of values used to filter the rules. */ - public BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters) { + default BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters) { BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); if (id != null) { return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); @@ -130,86 +122,12 @@ public BoolQueryBuilder buildGetRuleQuery(String id, Map> return boolQuery; } - /** - * Process searchResponse from index and send a GetRuleResponse - * @param searchResponse - Response received from index - * @param listener - ActionListener for GetRuleResponse - */ - void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { - List hits = Arrays.asList(searchResponse.getHits().getHits()); - if (id != null && hits.isEmpty()) { - logger.error("Rule with ID " + id + " not found."); - listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " doesn't exist in the .rules index.")); - return; - } - Map ruleMap = hits.stream() - .map(hit -> parseRule(hit.getId(), hit.getSourceAsString())) - .filter(Objects::nonNull) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); - listener.onResponse(buildGetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); - } - - /** - * Parses a source string into a Rule object - * @param id - document id for the Rule object - * @param source - The raw source string representing the rule to be parsed - */ - private Map.Entry parseRule(String id, String source) { - try ( - XContentParser parser = MediaTypeRegistry.JSON.xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source) - ) { - return Map.entry(id, Builder.fromXContent(parser, retrieveFeatureTypeInstance()).build()); - } catch (IOException e) { - logger.info("Issue met when parsing rule for ID {}: {}", id, e.getMessage()); - return null; - } - } - - private boolean isExistingQueryGroup(String queryGroupId) { - return clusterService.state().metadata().queryGroups().containsKey(queryGroupId); - } - /** * Abstract method for subclasses to provide specific FeatureType Instance */ - protected abstract FeatureType retrieveFeatureTypeInstance(); - - /** - * Builds a GetRuleResponse. Subclasses can override based on their own needs. - * @param ruleMap - The map of rules the response contains - * @param nextSearchAfter - The search after string containing a rule id used for pagination - * @param restStatus - Status of the response - */ - protected abstract T buildGetRuleResponse( - Map ruleMap, - String nextSearchAfter, - RestStatus restStatus - ); + FeatureType retrieveFeatureTypeInstance(); private ThreadContext.StoredContext getContext() { - return client.threadPool().getThreadContext().stashContext(); - } - - /** - * Get the max return size allowed for page for get request when pagination is needed - */ - public int getMaxReturnSizeAllowedPerGetRequest() { - return MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST; - } - - /** - * client getter - */ - public Client getClient() { - return client; - } - - /** - * clusterService getter - */ - public ClusterService getClusterService() { - return clusterService; + return getClient().threadPool().getThreadContext().stashContext(); } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleProcessingService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleProcessingService.java new file mode 100644 index 0000000000000..95353a25d2343 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleProcessingService.java @@ -0,0 +1,63 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.service; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.common.collect.Tuple; +import org.opensearch.search.SearchHit; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.opensearch.autotagging.Rule.parseRule; + +/** + * Interface defining the contract for processing and parsing rule-related logic. + * @opensearch.experimental + */ +public interface RuleProcessingService { + /** + * logger for RuleProcessingService + */ + Logger logger = LogManager.getLogger(RuleProcessingService.class); + + /** + * function to retrieve the feature type corresponding to the rule + */ + FeatureType retrieveFeatureTypeInstance(); + + /** + * Process searchResponse from index and send a GetRuleResponse + * @param id - Rule id fetched + * @param searchResponse - Response received from index + */ + default Tuple, String> parseGetRuleResponse(String id, SearchResponse searchResponse) { + List hits = Arrays.asList(searchResponse.getHits().getHits()); + if (id != null && hits.isEmpty()) { + logger.error("Rule with ID " + id + " not found."); + return new Tuple<>(new HashMap<>(), null); + } + Map ruleMap = hits.stream() + .collect( + Collectors.toMap( + SearchHit::getId, + hit -> parseRule(hit.getId(), hit.getSourceAsString(), retrieveFeatureTypeInstance()).getValue() + ) + ); + String lastValidRuleId = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); + return new Tuple<>(ruleMap, lastValidRuleId); + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleResponseBuilder.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleResponseBuilder.java new file mode 100644 index 0000000000000..7ef1046effa01 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleResponseBuilder.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.service; + +import org.opensearch.autotagging.Rule; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.rule.action.GetRuleResponse; + +import java.util.Map; + +/** + * A builder interface for rule lifecycle response objects. + * @opensearch.experimental + */ +public interface RuleResponseBuilder { + /** + * Builds a GetRuleResponse object containing rule data. + * @param ruleMap A map of rule IDs to their corresponding {@link Rule} objects. + * @param nextSearchAfter The ID used for pagination to fetch the next set of results, if applicable. + * @param restStatus The response rest status. + */ + T buildGetRuleResponse(Map ruleMap, String nextSearchAfter, RestStatus restStatus); +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleService.java new file mode 100644 index 0000000000000..57fbcb4a01ff5 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleService.java @@ -0,0 +1,74 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.service; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.autotagging.Rule; +import org.opensearch.common.collect.Tuple; +import org.opensearch.common.inject.Inject; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; + +import java.util.Map; + +/** + * Service class responsible for processing the business logic for rule lifecycle operations + * @opensearch.experimental + */ +public class RuleService { + private final RulePersistenceService rulePersistenceService; + private final RuleProcessingService ruleProcessingService; + private final RuleResponseBuilder ruleResponseBuilder; + private final Logger logger = LogManager.getLogger(RuleService.class); + + /** + * Constructs a {@link RuleService} with the specified dependencies. + * @param rulePersistenceService The persistence service for retrieving and storing rules. + * @param ruleProcessingService The service responsible for processing rule data. + * @param ruleResponseBuilder The builder used to construct rule response objects. + */ + @Inject + public RuleService( + RulePersistenceService rulePersistenceService, + RuleProcessingService ruleProcessingService, + RuleResponseBuilder ruleResponseBuilder + ) { + this.rulePersistenceService = rulePersistenceService; + this.ruleProcessingService = ruleProcessingService; + this.ruleResponseBuilder = ruleResponseBuilder; + } + + /** + * Processes a request to retrieve rules based on specified criteria. + * @param request The {@link GetRuleRequest} containing rule retrieval parameters. + * @param listener The {@link ActionListener} that handles the asynchronous response. + */ + public void processGetRuleRequest(GetRuleRequest request, ActionListener listener) { + rulePersistenceService.getRule(request.getId(), request.getAttributeFilters(), request.getSearchAfter(), new ActionListener<>() { + @Override + public void onResponse(SearchResponse searchResponse) { + Tuple, String> responseParams = ruleProcessingService.parseGetRuleResponse( + request.getId(), + searchResponse + ); + listener.onResponse(ruleResponseBuilder.buildGetRuleResponse(responseParams.v1(), responseParams.v2(), RestStatus.OK)); + } + + @Override + public void onFailure(Exception e) { + logger.error("Failed to fetch rules: {}", e.getMessage()); + listener.onFailure(e); + } + }); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java index d2b3e6f9c962f..97120e9425ed1 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java @@ -11,7 +11,6 @@ import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.FeatureType; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.rule.action.GetRuleRequest; import java.io.IOException; @@ -20,10 +19,6 @@ /** * A request to get workload management Rules in workload management - * Example Request: - * curl -X GET "localhost:9200/_wlm/rule" - get all rules - * curl -X GET "localhost:9200/_wlm/rule/{_id}" - get single rule by id - * curl -X GET "localhost:9200/_wlm/rule?index_pattern=a,b" - get all rules containing attribute index_pattern as a or b * @opensearch.experimental */ public class GetWlmRuleRequest extends GetRuleRequest { @@ -32,9 +27,10 @@ public class GetWlmRuleRequest extends GetRuleRequest { * @param id - Rule id to get * @param attributeFilters - A map containing the attributes to filter on * @param searchAfter - A string used for pagination + * @param featureType - The featureType instance for wlm */ - public GetWlmRuleRequest(String id, Map> attributeFilters, String searchAfter) { - super(id, attributeFilters, searchAfter); + public GetWlmRuleRequest(String id, Map> attributeFilters, String searchAfter, FeatureType featureType) { + super(id, attributeFilters, searchAfter, featureType); } /** @@ -44,9 +40,4 @@ public GetWlmRuleRequest(String id, Map> attributeFilters public GetWlmRuleRequest(StreamInput in) throws IOException { super(in); } - - @Override - protected FeatureType retrieveFeatureTypeInstance() { - return QueryGroupFeatureType.INSTANCE; - } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java index ca20ea4d1815a..85bc110b61a03 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java @@ -12,7 +12,7 @@ import org.opensearch.action.support.HandledTransportAction; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; -import org.opensearch.plugin.wlm.rule.service.WlmRulePersistenceService; +import org.opensearch.rule.service.RuleService; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; @@ -22,26 +22,22 @@ */ public class TransportGetWlmRuleAction extends HandledTransportAction { - private final WlmRulePersistenceService rulePersistenceService; + private final RuleService ruleService; /** * Constructor for TransportGetWlmRuleAction * @param transportService - a {@link TransportService} object * @param actionFilters - a {@link ActionFilters} object - * @param rulePersistenceService - a {@link WlmRulePersistenceService} object + * @param ruleService - a {@link RuleService} object */ @Inject - public TransportGetWlmRuleAction( - TransportService transportService, - ActionFilters actionFilters, - WlmRulePersistenceService rulePersistenceService - ) { + public TransportGetWlmRuleAction(TransportService transportService, ActionFilters actionFilters, RuleService ruleService) { super(GetWlmRuleAction.NAME, transportService, actionFilters, GetWlmRuleRequest::new); - this.rulePersistenceService = rulePersistenceService; + this.ruleService = ruleService; } @Override protected void doExecute(Task task, GetWlmRuleRequest request, ActionListener listener) { - rulePersistenceService.getRule(request.getId(), request.getAttributeFilters(), request.getSearchAfter(), listener); + ruleService.processGetRuleRequest(request, listener); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java index 11f7776c77c21..55a07082928dd 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java @@ -11,6 +11,7 @@ import org.opensearch.action.ActionType; import org.opensearch.autotagging.Attribute; import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.plugin.wlm.rule.action.GetWlmRuleAction; import org.opensearch.plugin.wlm.rule.action.GetWlmRuleRequest; import org.opensearch.rule.action.GetRuleRequest; @@ -59,6 +60,6 @@ protected > T retrieveGetRuleAct @Override protected GetRuleRequest buildGetRuleRequest(String id, Map> attributeFilters, String searchAfter) { - return new GetWlmRuleRequest(id, attributeFilters, searchAfter); + return new GetWlmRuleRequest(id, attributeFilters, searchAfter, QueryGroupFeatureType.INSTANCE); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java index 5ee6a1d65dbb0..b4d77f3ca0a90 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java @@ -9,25 +9,28 @@ package org.opensearch.plugin.wlm.rule.service; import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; -import org.opensearch.core.rest.RestStatus; import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.plugin.wlm.rule.action.GetWlmRuleResponse; -import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.rule.service.RulePersistenceService; import org.opensearch.transport.client.Client; -import java.util.Map; - /** * This class encapsulates the logic to manage the lifecycle of workload management rules at index level * @opensearch.experimental */ @SuppressWarnings("unchecked") -public class WlmRulePersistenceService extends RulePersistenceService { +public class WlmRulePersistenceService implements RulePersistenceService { + public static final String RULES_INDEX = ".rules"; + private final ClusterService clusterService; + private final Client client; + + @Override + public String getIndexName() { + return RULES_INDEX; + } + /** * Constructor for WlmRulePersistenceService * @param clusterService {@link ClusterService} - The cluster service to be used by RulePersistenceService @@ -35,16 +38,22 @@ public class WlmRulePersistenceService extends RulePersistenceService { */ @Inject public WlmRulePersistenceService(ClusterService clusterService, Client client) { - super(clusterService, client); + this.client = client; + this.clusterService = clusterService; } @Override - protected FeatureType retrieveFeatureTypeInstance() { - return QueryGroupFeatureType.INSTANCE; + public Client getClient() { + return client; } @Override - protected T buildGetRuleResponse(Map ruleMap, String nextSearchAfter, RestStatus restStatus) { - return (T) new GetWlmRuleResponse(ruleMap, nextSearchAfter, restStatus); + public ClusterService getClusterService() { + return clusterService; + } + + @Override + public FeatureType retrieveFeatureTypeInstance() { + return QueryGroupFeatureType.INSTANCE; } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleProcessingService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleProcessingService.java new file mode 100644 index 0000000000000..3e50ad02ad5d2 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleProcessingService.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.service; + +import org.opensearch.autotagging.FeatureType; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; +import org.opensearch.rule.service.RuleProcessingService; + +public class WlmRuleProcessingService implements RuleProcessingService { + @Override + public FeatureType retrieveFeatureTypeInstance() { + return QueryGroupFeatureType.INSTANCE; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleResponseBuilder.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleResponseBuilder.java new file mode 100644 index 0000000000000..819d5542bab5e --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleResponseBuilder.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.service; + +import org.opensearch.autotagging.Rule; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.plugin.wlm.rule.action.GetWlmRuleResponse; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.service.RuleResponseBuilder; + +import java.util.Map; + +@SuppressWarnings("unchecked") +public class WlmRuleResponseBuilder implements RuleResponseBuilder { + @Override + public T buildGetRuleResponse(Map ruleMap, String nextSearchAfter, RestStatus restStatus) { + return (T) new GetWlmRuleResponse(ruleMap, nextSearchAfter, restStatus); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java index d3eb6fba53821..ccf65d250814f 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java @@ -10,6 +10,7 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; @@ -28,7 +29,12 @@ public class GetWlmRuleRequestTests extends OpenSearchTestCase { * Test case to verify the serialization and deserialization of GetRuleRequest */ public void testSerialization() throws IOException { - GetWlmRuleRequest request = new GetWlmRuleRequest(_ID_ONE, Map.of(INDEX_PATTERN, Set.of(PATTERN_ONE)), null); + GetWlmRuleRequest request = new GetWlmRuleRequest( + _ID_ONE, + Map.of(INDEX_PATTERN, Set.of(PATTERN_ONE)), + null, + QueryGroupFeatureType.INSTANCE + ); assertEquals(_ID_ONE, request.getId()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); @@ -42,7 +48,7 @@ public void testSerialization() throws IOException { * Test case to verify the serialization and deserialization of GetRuleRequest when name is null */ public void testSerializationWithNull() throws IOException { - GetWlmRuleRequest request = new GetWlmRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER); + GetWlmRuleRequest request = new GetWlmRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER, QueryGroupFeatureType.INSTANCE); assertNull(request.getId()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java index 4a1cc1c122ecd..30d3359078140 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java @@ -14,7 +14,6 @@ import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilders; import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.plugin.wlm.rule.action.GetWlmRuleResponse; import org.opensearch.search.sort.SortOrder; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.Client; @@ -54,7 +53,7 @@ public void testBuildGetRuleQuery_WithFilters() { public void testGetRule_WithId() { WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); Client client = rulePersistenceService.getClient(); - ActionListener listener = mock(ActionListener.class); + ActionListener listener = mock(ActionListener.class); SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); SetupMocksForGetRule(client, searchRequestBuilder); @@ -67,7 +66,7 @@ public void testGetRule_WithId() { public void testGetRule_WithSearchAfter() { WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); Client client = rulePersistenceService.getClient(); - ActionListener listener = mock(ActionListener.class); + ActionListener listener = mock(ActionListener.class); SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); SetupMocksForGetRule(client, searchRequestBuilder); when(searchRequestBuilder.addSort(anyString(), any(SortOrder.class))).thenReturn(searchRequestBuilder); diff --git a/server/src/main/java/org/opensearch/autotagging/Rule.java b/server/src/main/java/org/opensearch/autotagging/Rule.java index 10e8a503b8dc6..e058933a26e8e 100644 --- a/server/src/main/java/org/opensearch/autotagging/Rule.java +++ b/server/src/main/java/org/opensearch/autotagging/Rule.java @@ -8,9 +8,14 @@ package org.opensearch.autotagging; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.core.common.io.stream.Writeable; +import org.opensearch.core.xcontent.DeprecationHandler; +import org.opensearch.core.xcontent.MediaTypeRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.core.xcontent.XContentParseException; @@ -47,6 +52,7 @@ public class Rule implements Writeable, ToXContentObject { public static final String _ID_STRING = "_id"; public static final String DESCRIPTION_STRING = "description"; public static final String UPDATED_AT_STRING = "updated_at"; + public static final Logger logger = LogManager.getLogger(Rule.class); public Rule( String description, @@ -87,6 +93,23 @@ public static Rule fromXContent(final XContentParser parser, FeatureType feature return Builder.fromXContent(parser, featureType).build(); } + /** + * Parses a source string into a Rule object + * @param id - document id for the Rule object + * @param source - The raw source string representing the rule to be parsed + */ + public static Map.Entry parseRule(String id, String source, FeatureType featureType) { + try ( + XContentParser parser = MediaTypeRegistry.JSON.xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source) + ) { + return Map.entry(id, Builder.fromXContent(parser, featureType).build()); + } catch (IOException e) { + logger.info("Issue met when parsing rule for ID {}: {}", id, e.getMessage()); + return null; + } + } + public String getDescription() { return description; } From 1e598264f1d73b1eec3968ed46c8718d01679d9a Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Wed, 2 Apr 2025 20:51:25 -0700 Subject: [PATCH 08/28] modify based on comments Signed-off-by: Ruirui Zhang --- .../rule/Utils/IndexStoredRuleParser.java | 40 ++++++ .../rule/Utils/IndexStoredRuleUtils.java | 41 ++++++ .../opensearch/rule/Utils}/package-info.java | 4 +- .../rule/action/GetRuleRequest.java | 2 +- .../rule/action/GetRuleResponse.java | 2 +- .../IndexStoredRulePersistenceService.java | 126 +++++++++++++++++ .../rule/service/RulePersistenceService.java | 122 +---------------- .../rule/service/RuleProcessingService.java | 63 --------- .../rule/service/RuleResponseBuilder.java | 29 ---- .../opensearch/rule/service/RuleService.java | 74 ---------- .../plugin/wlm/WorkloadManagementPlugin.java | 36 ++++- .../wlm/rule/action/GetWlmRuleAction.java | 5 +- .../wlm/rule/action/GetWlmRuleRequest.java | 43 ------ .../wlm/rule/action/GetWlmRuleResponse.java | 55 -------- .../action/TransportGetWlmRuleAction.java | 25 ++-- .../wlm/rule/rest/RestGetWlmRuleAction.java | 3 +- .../service/WlmRulePersistenceService.java | 59 -------- .../service/WlmRuleProcessingService.java | 20 --- .../rule/service/WlmRuleResponseBuilder.java | 25 ---- .../plugin/wlm/rule/WlmRuleTestUtils.java | 41 +++--- .../rule/action/GetWlmRuleRequestTests.java | 60 --------- .../rule/action/GetWlmRuleResponseTests.java | 123 ----------------- .../WlmRulePersistenceServiceTests.java | 127 +++++++----------- 23 files changed, 334 insertions(+), 791 deletions(-) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleParser.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleUtils.java rename {plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service => libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils}/package-info.java (62%) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleProcessingService.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleResponseBuilder.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleService.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponse.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleProcessingService.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleResponseBuilder.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponseTests.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleParser.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleParser.java new file mode 100644 index 0000000000000..0e921b7619c60 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleParser.java @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.Utils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.core.xcontent.DeprecationHandler; +import org.opensearch.core.xcontent.MediaTypeRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.core.xcontent.XContentParser; + +import java.io.IOException; + +public class IndexStoredRuleParser { + private static final Logger logger = LogManager.getLogger(IndexStoredRuleParser.class); + + /** + * Parses a source string into a Rule object + * @param source - The raw source string representing the rule to be parsed + */ + public static Rule parseRule(String source, FeatureType featureType) { + try ( + XContentParser parser = MediaTypeRegistry.JSON.xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source) + ) { + return Rule.Builder.fromXContent(parser, featureType).build(); + } catch (IOException e) { + logger.info("Issue met when parsing rule {}: {}", source, e.getMessage()); + throw new RuntimeException("Cannot parse rule from index: " + source); + } + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleUtils.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleUtils.java new file mode 100644 index 0000000000000..e9f29fbe3c7c0 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleUtils.java @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.Utils; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.QueryBuilders; + +import java.util.Map; +import java.util.Set; + +import static org.opensearch.autotagging.Rule._ID_STRING; + +public class IndexStoredRuleUtils { + public static BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters, FeatureType featureType) { + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + if (id != null) { + return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); + } + for (Map.Entry> entry : attributeFilters.entrySet()) { + Attribute attribute = entry.getKey(); + Set values = entry.getValue(); + if (values != null && !values.isEmpty()) { + BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); + for (String value : values) { + attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); + } + boolQuery.must(attributeQuery); + } + } + boolQuery.filter(QueryBuilders.existsQuery(featureType.getName())); + return boolQuery; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/package-info.java similarity index 62% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/package-info.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/package-info.java index a10b1758d0a58..37ec700e35f6f 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/package-info.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/package-info.java @@ -7,6 +7,6 @@ */ /** - * Package for the service classes related to rules in WorkloadManagementPlugin + * This package contains utility classes for rules */ -package org.opensearch.plugin.wlm.rule.service; +package org.opensearch.rule.Utils; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java index 052ceb90bbf77..03d1899a2e6a8 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java @@ -29,7 +29,7 @@ * curl -X GET "localhost:9200/_wlm/rule?index_pattern=a,b" - get all rules containing attribute index_pattern as a or b * @opensearch.experimental */ -public abstract class GetRuleRequest extends ActionRequest { +public class GetRuleRequest extends ActionRequest { private final String id; private final Map> attributeFilters; private final String searchAfter; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java index 954c39cfdfc8e..110522ff86af6 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java @@ -40,7 +40,7 @@ * } * @opensearch.experimental */ -public abstract class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { +public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { private final Map rules; private final String searchAfter; private final RestStatus restStatus; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java new file mode 100644 index 0000000000000..9ca715e4cecc0 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -0,0 +1,126 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.service; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.search.SearchRequestBuilder; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.rule.Utils.IndexStoredRuleParser; +import org.opensearch.rule.Utils.IndexStoredRuleUtils; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.search.SearchHit; +import org.opensearch.search.sort.SortOrder; +import org.opensearch.transport.client.Client; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.opensearch.autotagging.Rule._ID_STRING; + +/** + * This class encapsulates the logic to manage the lifecycle of rules at index level + * @opensearch.experimental + */ +public class IndexStoredRulePersistenceService implements RulePersistenceService { + /** + * The system index name used for storing rules + */ + private final String indexName; + private final Client client; + private final FeatureType featureType; + private final int maxReturnSizeAllowedPerGetRequest; + private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); + + public IndexStoredRulePersistenceService( + String indexName, + Client client, + FeatureType featureType, + int maxReturnSizeAllowedPerGetRequest + ) { + this.indexName = indexName; + this.client = client; + this.featureType = featureType; + this.maxReturnSizeAllowedPerGetRequest = maxReturnSizeAllowedPerGetRequest; + } + + public void getRule(GetRuleRequest getRuleRequest, ActionListener listener) { + getRuleFromIndex(getRuleRequest.getId(), getRuleRequest.getAttributeFilters(), getRuleRequest.getSearchAfter(), listener); + } + + /** + * Entry point for the get rule api logic in persistence service. If id is provided, we only get a single rule. + * Otherwise, we get all rules that satisfy the attributeFilters. + * @param id - The id of the rule to get. + * @param attributeFilters - A map containing the attributes that user want to filter on + * @param searchAfter - The sort values from the last document of the previous page, used for pagination + * @param listener - ActionListener for GetRuleResponse + */ + public void getRuleFromIndex( + String id, + Map> attributeFilters, + String searchAfter, + ActionListener listener + ) { + // Stash the current thread context when interacting with system index to perform + // operations as the system itself, bypassing authorization checks. This ensures that + // actions within this block are trusted and executed with system-level privileges. + try (ThreadContext.StoredContext context = getContext()) { + BoolQueryBuilder boolQuery = IndexStoredRuleUtils.buildGetRuleQuery(id, attributeFilters, featureType); + SearchRequestBuilder searchRequest = client.prepareSearch(indexName) + .setQuery(boolQuery) + .setSize(maxReturnSizeAllowedPerGetRequest); + if (searchAfter != null) { + searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); + } + searchRequest.execute(ActionListener.wrap(searchResponse -> handleGetRuleResponse(id, searchResponse, listener), e -> { + logger.error("Failed to fetch all rules: {}", e.getMessage()); + listener.onFailure(e); + })); + } + } + + /** + * Process searchResponse from index and send a GetRuleResponse + * @param searchResponse - Response received from index + * @param listener - ActionListener for GetRuleResponse + */ + void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { + List hits = Arrays.asList(searchResponse.getHits().getHits()); + if (id != null && hits.isEmpty()) { + logger.error("Rule with ID " + id + " not found."); + listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " doesn't exist in the .rules index.")); + return; + } + Map ruleMap = hits.stream() + .collect(Collectors.toMap(SearchHit::getId, hit -> IndexStoredRuleParser.parseRule(hit.getSourceAsString(), featureType))); + String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); + listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); + } + + private ThreadContext.StoredContext getContext() { + return client.threadPool().getThreadContext().stashContext(); + } + + public Client getClient() { + return client; + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java index 08856b38cdb08..751607bbc9c92 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java @@ -8,126 +8,10 @@ package org.opensearch.rule.service; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.action.search.SearchRequestBuilder; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; -import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.index.query.QueryBuilders; -import org.opensearch.search.sort.SortOrder; -import org.opensearch.transport.client.Client; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; -import java.util.Map; -import java.util.Set; - -import static org.opensearch.autotagging.Rule._ID_STRING; - -/** - * This class encapsulates the logic to manage the lifecycle of rules at index level - * @opensearch.experimental - */ public interface RulePersistenceService { - /** - * The default maximum number of results allowed per GET request - */ - int MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST = 50; - - /** - * The system index name used for storing rules - */ - String getIndexName(); - - /** - * client getter - */ - Client getClient(); - - /** - * clusterService getter - */ - ClusterService getClusterService(); - - /** - * Get the max return size allowed for page for get request when pagination is needed - */ - default int getMaxReturnSizeAllowedPerGetRequest() { - return MAX_RETURN_SIZE_ALLOWED_PER_GET_REQUEST; - } - - /** - * logger for RulePersistenceService - */ - Logger logger = LogManager.getLogger(RulePersistenceService.class); - - /** - * Entry point for the get rule api logic in persistence service. If id is provided, we only get a single rule. - * Otherwise, we get all rules that satisfy the attributeFilters. - * @param id - The id of the rule to get. - * @param attributeFilters - A map containing the attributes that user want to filter on - * @param searchAfter - The sort values from the last document of the previous page, used for pagination - * @param listener - ActionListener for GetRuleResponse - */ - default void getRule( - String id, - Map> attributeFilters, - String searchAfter, - ActionListener listener - ) { - // Stash the current thread context when interacting with system index to perform - // operations as the system itself, bypassing authorization checks. This ensures that - // actions within this block are trusted and executed with system-level privileges. - try (ThreadContext.StoredContext context = getContext()) { - BoolQueryBuilder boolQuery = buildGetRuleQuery(id, attributeFilters); - SearchRequestBuilder searchRequest = getClient().prepareSearch(getIndexName()) - .setQuery(boolQuery) - .setSize(getMaxReturnSizeAllowedPerGetRequest()); - if (searchAfter != null) { - searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); - } - searchRequest.execute(ActionListener.wrap(listener::onResponse, e -> { - logger.error("Failed to fetch all rules: {}", e.getMessage()); - listener.onFailure(e); - })); - } - } - - /** - * Builds a bool query to retrieve rules from the rules index, applying attribute-based filters - * when needed and ensuring that the rules are associated with the query group feature type. - * @param id The ID of the rule to fetch. If not null, the search will return only this specific rule. - * @param attributeFilters A map of attributes to their associated set of values used to filter the rules. - */ - default BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters) { - BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); - if (id != null) { - return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); - } - for (Map.Entry> entry : attributeFilters.entrySet()) { - Attribute attribute = entry.getKey(); - Set values = entry.getValue(); - if (values != null && !values.isEmpty()) { - BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); - for (String value : values) { - attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); - } - boolQuery.must(attributeQuery); - } - } - boolQuery.filter(QueryBuilders.existsQuery(retrieveFeatureTypeInstance().getName())); - return boolQuery; - } - - /** - * Abstract method for subclasses to provide specific FeatureType Instance - */ - FeatureType retrieveFeatureTypeInstance(); - - private ThreadContext.StoredContext getContext() { - return getClient().threadPool().getThreadContext().stashContext(); - } + void getRule(GetRuleRequest request, ActionListener listener); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleProcessingService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleProcessingService.java deleted file mode 100644 index 95353a25d2343..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleProcessingService.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.service; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; -import org.opensearch.common.collect.Tuple; -import org.opensearch.search.SearchHit; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.opensearch.autotagging.Rule.parseRule; - -/** - * Interface defining the contract for processing and parsing rule-related logic. - * @opensearch.experimental - */ -public interface RuleProcessingService { - /** - * logger for RuleProcessingService - */ - Logger logger = LogManager.getLogger(RuleProcessingService.class); - - /** - * function to retrieve the feature type corresponding to the rule - */ - FeatureType retrieveFeatureTypeInstance(); - - /** - * Process searchResponse from index and send a GetRuleResponse - * @param id - Rule id fetched - * @param searchResponse - Response received from index - */ - default Tuple, String> parseGetRuleResponse(String id, SearchResponse searchResponse) { - List hits = Arrays.asList(searchResponse.getHits().getHits()); - if (id != null && hits.isEmpty()) { - logger.error("Rule with ID " + id + " not found."); - return new Tuple<>(new HashMap<>(), null); - } - Map ruleMap = hits.stream() - .collect( - Collectors.toMap( - SearchHit::getId, - hit -> parseRule(hit.getId(), hit.getSourceAsString(), retrieveFeatureTypeInstance()).getValue() - ) - ); - String lastValidRuleId = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); - return new Tuple<>(ruleMap, lastValidRuleId); - } -} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleResponseBuilder.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleResponseBuilder.java deleted file mode 100644 index 7ef1046effa01..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleResponseBuilder.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.service; - -import org.opensearch.autotagging.Rule; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.rule.action.GetRuleResponse; - -import java.util.Map; - -/** - * A builder interface for rule lifecycle response objects. - * @opensearch.experimental - */ -public interface RuleResponseBuilder { - /** - * Builds a GetRuleResponse object containing rule data. - * @param ruleMap A map of rule IDs to their corresponding {@link Rule} objects. - * @param nextSearchAfter The ID used for pagination to fetch the next set of results, if applicable. - * @param restStatus The response rest status. - */ - T buildGetRuleResponse(Map ruleMap, String nextSearchAfter, RestStatus restStatus); -} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleService.java deleted file mode 100644 index 57fbcb4a01ff5..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RuleService.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.service; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.autotagging.Rule; -import org.opensearch.common.collect.Tuple; -import org.opensearch.common.inject.Inject; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.rule.action.GetRuleRequest; -import org.opensearch.rule.action.GetRuleResponse; - -import java.util.Map; - -/** - * Service class responsible for processing the business logic for rule lifecycle operations - * @opensearch.experimental - */ -public class RuleService { - private final RulePersistenceService rulePersistenceService; - private final RuleProcessingService ruleProcessingService; - private final RuleResponseBuilder ruleResponseBuilder; - private final Logger logger = LogManager.getLogger(RuleService.class); - - /** - * Constructs a {@link RuleService} with the specified dependencies. - * @param rulePersistenceService The persistence service for retrieving and storing rules. - * @param ruleProcessingService The service responsible for processing rule data. - * @param ruleResponseBuilder The builder used to construct rule response objects. - */ - @Inject - public RuleService( - RulePersistenceService rulePersistenceService, - RuleProcessingService ruleProcessingService, - RuleResponseBuilder ruleResponseBuilder - ) { - this.rulePersistenceService = rulePersistenceService; - this.ruleProcessingService = ruleProcessingService; - this.ruleResponseBuilder = ruleResponseBuilder; - } - - /** - * Processes a request to retrieve rules based on specified criteria. - * @param request The {@link GetRuleRequest} containing rule retrieval parameters. - * @param listener The {@link ActionListener} that handles the asynchronous response. - */ - public void processGetRuleRequest(GetRuleRequest request, ActionListener listener) { - rulePersistenceService.getRule(request.getId(), request.getAttributeFilters(), request.getSearchAfter(), new ActionListener<>() { - @Override - public void onResponse(SearchResponse searchResponse) { - Tuple, String> responseParams = ruleProcessingService.parseGetRuleResponse( - request.getId(), - searchResponse - ); - listener.onResponse(ruleResponseBuilder.buildGetRuleResponse(responseParams.v1(), responseParams.v2(), RestStatus.OK)); - } - - @Override - public void onFailure(Exception e) { - logger.error("Failed to fetch rules: {}", e.getMessage()); - listener.onFailure(e); - } - }); - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index fa2cb33182255..6ac5f317a3f0b 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -11,6 +11,7 @@ import org.opensearch.action.ActionRequest; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; +import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Module; import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.IndexScopedSettings; @@ -18,6 +19,10 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; import org.opensearch.core.action.ActionResponse; +import org.opensearch.core.common.io.stream.NamedWriteableRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.env.Environment; +import org.opensearch.env.NodeEnvironment; import org.opensearch.indices.SystemIndexDescriptor; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; @@ -38,25 +43,50 @@ import org.opensearch.plugins.ActionPlugin; import org.opensearch.plugins.Plugin; import org.opensearch.plugins.SystemIndexPlugin; +import org.opensearch.repositories.RepositoriesService; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.script.ScriptService; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.client.Client; +import org.opensearch.watcher.ResourceWatcherService; import java.util.Collection; import java.util.List; import java.util.function.Supplier; -import static org.opensearch.plugin.wlm.rule.service.WlmRulePersistenceService.RULES_INDEX; - /** * Plugin class for WorkloadManagement */ public class WorkloadManagementPlugin extends Plugin implements ActionPlugin, SystemIndexPlugin { + public static final String INDEX_NAME = ".wlm_rules"; + public static final int MAX_ENTRY_SIZE_PER_GET_REQUEST = 50; /** * Default constructor */ public WorkloadManagementPlugin() {} + @Override + public Collection createComponents( + Client client, + ClusterService clusterService, + ThreadPool threadPool, + ResourceWatcherService resourceWatcherService, + ScriptService scriptService, + NamedXContentRegistry xContentRegistry, + Environment environment, + NodeEnvironment nodeEnvironment, + NamedWriteableRegistry namedWriteableRegistry, + IndexNameExpressionResolver indexNameExpressionResolver, + Supplier repositoriesServiceSupplier + ) { + return List.of( + new IndexStoredRulePersistenceService(INDEX_NAME, client, QueryGroupFeatureType.INSTANCE, MAX_ENTRY_SIZE_PER_GET_REQUEST) + ); + } + @Override public List> getActions() { return List.of( @@ -70,7 +100,7 @@ public WorkloadManagementPlugin() {} @Override public Collection getSystemIndexDescriptors(Settings settings) { - return List.of(new SystemIndexDescriptor(RULES_INDEX, "System index used for storing rules")); + return List.of(new SystemIndexDescriptor(".wlm_rules", "System index used for storing rules")); } @Override diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java index 95ecbe6d6a4ec..080d417f1319d 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java @@ -9,12 +9,13 @@ package org.opensearch.plugin.wlm.rule.action; import org.opensearch.action.ActionType; +import org.opensearch.rule.action.GetRuleResponse; /** * Action type for getting Rules in workload management * @opensearch.experimental */ -public class GetWlmRuleAction extends ActionType { +public class GetWlmRuleAction extends ActionType { /** * An instance of GetWlmRuleAction @@ -30,6 +31,6 @@ public class GetWlmRuleAction extends ActionType { * Default constructor for GetWlmRuleAction */ private GetWlmRuleAction() { - super(NAME, GetWlmRuleResponse::new); + super(NAME, GetRuleResponse::new); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java deleted file mode 100644 index 97120e9425ed1..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.action; - -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.action.GetRuleRequest; - -import java.io.IOException; -import java.util.Map; -import java.util.Set; - -/** - * A request to get workload management Rules in workload management - * @opensearch.experimental - */ -public class GetWlmRuleRequest extends GetRuleRequest { - /** - * Constructor for GetWlmRuleRequest - * @param id - Rule id to get - * @param attributeFilters - A map containing the attributes to filter on - * @param searchAfter - A string used for pagination - * @param featureType - The featureType instance for wlm - */ - public GetWlmRuleRequest(String id, Map> attributeFilters, String searchAfter, FeatureType featureType) { - super(id, attributeFilters, searchAfter, featureType); - } - - /** - * Constructs a new GetWlmRuleRequest instance from StreamInput - * @param in The {@link StreamInput} from which to read the request data. - */ - public GetWlmRuleRequest(StreamInput in) throws IOException { - super(in); - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponse.java deleted file mode 100644 index c3ab2a80ecf1a..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponse.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.action; - -import org.opensearch.autotagging.Rule; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.rule.action.GetRuleResponse; - -import java.io.IOException; -import java.util.Map; - -/** - * A response to get workload management Rules in workload management - * Example response: - * { - * "rules": [ - * { - * "_id": "z1MJApUB0zgMcDmz-UQq", - * "description": "Rule for tagging query_group_id to index123" - * "index_pattern": ["index123"], - * "query_group": "query_group_id", - * "updated_at": "2025-02-14T01:19:22.589Z" - * }, - * ... - * ], - * "search_after": ["z1MJApUB0zgMcDmz-UQq"] - * } - * @opensearch.experimental - */ -public class GetWlmRuleResponse extends GetRuleResponse { - /** - * Constructor for GetWlmRuleResponse - * @param rules - A map of rule IDs to objects representing the retrieved rules - * @param searchAfter - A string used for pagination - * @param restStatus - The {@link RestStatus} indicating the status of the request. - */ - public GetWlmRuleResponse(Map rules, String searchAfter, RestStatus restStatus) { - super(rules, searchAfter, restStatus); - } - - /** - * Constructs a new GetWlmRuleResponse instance from StreamInput - * @param in The {@link StreamInput} from which to read the response data. - */ - public GetWlmRuleResponse(StreamInput in) throws IOException { - super(in); - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java index 85bc110b61a03..e4bb603f869a7 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java @@ -12,7 +12,10 @@ import org.opensearch.action.support.HandledTransportAction; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; -import org.opensearch.rule.service.RuleService; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.rule.service.RulePersistenceService; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; @@ -20,24 +23,28 @@ * Transport action to get workload management Rules * @opensearch.experimental */ -public class TransportGetWlmRuleAction extends HandledTransportAction { +public class TransportGetWlmRuleAction extends HandledTransportAction { - private final RuleService ruleService; + private final RulePersistenceService rulePersistenceService; /** * Constructor for TransportGetWlmRuleAction * @param transportService - a {@link TransportService} object * @param actionFilters - a {@link ActionFilters} object - * @param ruleService - a {@link RuleService} object + * @param rulePersistenceService - a {@link RulePersistenceService} object */ @Inject - public TransportGetWlmRuleAction(TransportService transportService, ActionFilters actionFilters, RuleService ruleService) { - super(GetWlmRuleAction.NAME, transportService, actionFilters, GetWlmRuleRequest::new); - this.ruleService = ruleService; + public TransportGetWlmRuleAction( + TransportService transportService, + ActionFilters actionFilters, + RulePersistenceService rulePersistenceService + ) { + super(GetWlmRuleAction.NAME, transportService, actionFilters, GetRuleRequest::new); + this.rulePersistenceService = rulePersistenceService; } @Override - protected void doExecute(Task task, GetWlmRuleRequest request, ActionListener listener) { - ruleService.processGetRuleRequest(request, listener); + protected void doExecute(Task task, GetRuleRequest request, ActionListener listener) { + rulePersistenceService.getRule(request, listener); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java index 55a07082928dd..437dd8b246091 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java @@ -13,7 +13,6 @@ import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.plugin.wlm.rule.action.GetWlmRuleAction; -import org.opensearch.plugin.wlm.rule.action.GetWlmRuleRequest; import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.rule.rest.RestGetRuleAction; @@ -60,6 +59,6 @@ protected > T retrieveGetRuleAct @Override protected GetRuleRequest buildGetRuleRequest(String id, Map> attributeFilters, String searchAfter) { - return new GetWlmRuleRequest(id, attributeFilters, searchAfter, QueryGroupFeatureType.INSTANCE); + return new GetRuleRequest(id, attributeFilters, searchAfter, QueryGroupFeatureType.INSTANCE); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java deleted file mode 100644 index b4d77f3ca0a90..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceService.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.service; - -import org.opensearch.autotagging.FeatureType; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.inject.Inject; -import org.opensearch.common.settings.Settings; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.rule.service.RulePersistenceService; -import org.opensearch.transport.client.Client; - -/** - * This class encapsulates the logic to manage the lifecycle of workload management rules at index level - * @opensearch.experimental - */ -@SuppressWarnings("unchecked") -public class WlmRulePersistenceService implements RulePersistenceService { - public static final String RULES_INDEX = ".rules"; - private final ClusterService clusterService; - private final Client client; - - @Override - public String getIndexName() { - return RULES_INDEX; - } - - /** - * Constructor for WlmRulePersistenceService - * @param clusterService {@link ClusterService} - The cluster service to be used by RulePersistenceService - * @param client {@link Settings} - The client to be used by RulePersistenceService - */ - @Inject - public WlmRulePersistenceService(ClusterService clusterService, Client client) { - this.client = client; - this.clusterService = clusterService; - } - - @Override - public Client getClient() { - return client; - } - - @Override - public ClusterService getClusterService() { - return clusterService; - } - - @Override - public FeatureType retrieveFeatureTypeInstance() { - return QueryGroupFeatureType.INSTANCE; - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleProcessingService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleProcessingService.java deleted file mode 100644 index 3e50ad02ad5d2..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleProcessingService.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.service; - -import org.opensearch.autotagging.FeatureType; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.rule.service.RuleProcessingService; - -public class WlmRuleProcessingService implements RuleProcessingService { - @Override - public FeatureType retrieveFeatureTypeInstance() { - return QueryGroupFeatureType.INSTANCE; - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleResponseBuilder.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleResponseBuilder.java deleted file mode 100644 index 819d5542bab5e..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/WlmRuleResponseBuilder.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.service; - -import org.opensearch.autotagging.Rule; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.plugin.wlm.rule.action.GetWlmRuleResponse; -import org.opensearch.rule.action.GetRuleResponse; -import org.opensearch.rule.service.RuleResponseBuilder; - -import java.util.Map; - -@SuppressWarnings("unchecked") -public class WlmRuleResponseBuilder implements RuleResponseBuilder { - @Override - public T buildGetRuleResponse(Map ruleMap, String nextSearchAfter, RestStatus restStatus) { - return (T) new GetWlmRuleResponse(ruleMap, nextSearchAfter, restStatus); - } -} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java index f374ae8f5b703..6a96918633e9b 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java @@ -10,23 +10,12 @@ import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.Rule; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.metadata.Metadata; -import org.opensearch.cluster.metadata.QueryGroup; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.plugin.wlm.rule.service.WlmRulePersistenceService; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.client.Client; import java.util.Map; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class WlmRuleTestUtils { public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; @@ -61,21 +50,21 @@ public static Map ruleMap() { return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); } - public static WlmRulePersistenceService setUpRulePersistenceService(Map queryGroupMap) { - Client client = mock(Client.class); - ClusterService clusterService = mock(ClusterService.class); - ClusterState clusterState = mock(ClusterState.class); - Metadata metadata = mock(Metadata.class); - ThreadPool threadPool = mock(ThreadPool.class); - - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - when(client.threadPool()).thenReturn(threadPool); - when(threadPool.getThreadContext()).thenReturn(threadContext); - when(clusterService.state()).thenReturn(clusterState); - when(clusterState.metadata()).thenReturn(metadata); - when(metadata.queryGroups()).thenReturn(queryGroupMap); - return new WlmRulePersistenceService(clusterService, client); - } + // public static WlmRulePersistenceService setUpRulePersistenceService(Map queryGroupMap) { + // Client client = mock(Client.class); + // ClusterService clusterService = mock(ClusterService.class); + // ClusterState clusterState = mock(ClusterState.class); + // Metadata metadata = mock(Metadata.class); + // ThreadPool threadPool = mock(ThreadPool.class); + // + // ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + // when(client.threadPool()).thenReturn(threadPool); + // when(threadPool.getThreadContext()).thenReturn(threadContext); + // when(clusterService.state()).thenReturn(clusterState); + // when(clusterState.metadata()).thenReturn(metadata); + // when(metadata.queryGroups()).thenReturn(queryGroupMap); + // return new WlmRulePersistenceService(clusterService, client); + // } public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { assertEquals(mapOne.size(), mapTwo.size()); diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java deleted file mode 100644 index ccf65d250814f..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleRequestTests.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.action; - -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import static org.opensearch.plugin.wlm.rule.QueryGroupAttribute.INDEX_PATTERN; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.PATTERN_ONE; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.SEARCH_AFTER; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils._ID_ONE; - -public class GetWlmRuleRequestTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of GetRuleRequest - */ - public void testSerialization() throws IOException { - GetWlmRuleRequest request = new GetWlmRuleRequest( - _ID_ONE, - Map.of(INDEX_PATTERN, Set.of(PATTERN_ONE)), - null, - QueryGroupFeatureType.INSTANCE - ); - assertEquals(_ID_ONE, request.getId()); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - GetWlmRuleRequest otherRequest = new GetWlmRuleRequest(streamInput); - assertEquals(request.getId(), otherRequest.getId()); - assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); - } - - /** - * Test case to verify the serialization and deserialization of GetRuleRequest when name is null - */ - public void testSerializationWithNull() throws IOException { - GetWlmRuleRequest request = new GetWlmRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER, QueryGroupFeatureType.INSTANCE); - assertNull(request.getId()); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - GetWlmRuleRequest otherRequest = new GetWlmRuleRequest(streamInput); - assertEquals(request.getId(), otherRequest.getId()); - assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); - } -} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponseTests.java deleted file mode 100644 index 76f1f7a0a2534..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleResponseTests.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.action; - -import org.opensearch.autotagging.Rule; -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.common.xcontent.json.JsonXContent; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.SEARCH_AFTER; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils._ID_ONE; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.assertEqualRules; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.ruleMap; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.ruleOne; -import static org.mockito.Mockito.mock; - -public class GetWlmRuleResponseTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of GetRuleResponse - */ - public void testSerializationSingleRule() throws IOException { - Map map = new HashMap<>(); - map.put(_ID_ONE, ruleOne); - GetWlmRuleResponse response = new GetWlmRuleResponse(Map.of(_ID_ONE, ruleOne), null, RestStatus.OK); - assertEquals(response.getRules(), map); - - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - - GetWlmRuleResponse otherResponse = new GetWlmRuleResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); - assertEqualRules(response.getRules(), otherResponse.getRules(), false); - } - - /** - * Test case to verify the serialization and deserialization of GetRuleResponse when the result contains multiple rules - */ - public void testSerializationMultipleRule() throws IOException { - GetWlmRuleResponse response = new GetWlmRuleResponse(ruleMap(), SEARCH_AFTER, RestStatus.OK); - assertEquals(response.getRules(), ruleMap()); - - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - - GetWlmRuleResponse otherResponse = new GetWlmRuleResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); - assertEquals(2, otherResponse.getRules().size()); - assertEqualRules(response.getRules(), otherResponse.getRules(), false); - } - - /** - * Test case to verify the serialization and deserialization of GetRuleResponse when the result is empty - */ - public void testSerializationNull() throws IOException { - Map map = new HashMap<>(); - GetWlmRuleResponse response = new GetWlmRuleResponse(map, SEARCH_AFTER, RestStatus.OK); - assertEquals(response.getRules(), map); - - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - - GetWlmRuleResponse otherResponse = new GetWlmRuleResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); - assertEquals(0, otherResponse.getRules().size()); - } - - /** - * Test case to verify the toXContent of GetRuleResponse - */ - public void testToXContentGetSingleRule() throws IOException { - Map map = new HashMap<>(); - map.put(_ID_ONE, ruleOne); - GetWlmRuleResponse response = new GetWlmRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER, RestStatus.OK); - XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" - + " \"rules\" : [\n" - + " {\n" - + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" - + " \"description\" : \"description_1\",\n" - + " \"index_pattern\" : [\n" - + " \"pattern_1\"\n" - + " ],\n" - + " \"query_group\" : \"feature_value_one\",\n" - + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" - + " }\n" - + " ],\n" - + " \"search_after\" : [\n" - + " \"search_after_id\"\n" - + " ]\n" - + "}"; - assertEquals(expected, actual); - } - - /** - * Test case to verify toXContent of GetRuleResponse when the result contains zero Rule - */ - public void testToXContentGetZeroRule() throws IOException { - XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - GetWlmRuleResponse otherResponse = new GetWlmRuleResponse(new HashMap<>(), null, RestStatus.OK); - String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" + " \"rules\" : [ ]\n" + "}"; - assertEquals(expected, actual); - } -} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java index 30d3359078140..6df56b15ed875 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java @@ -8,83 +8,60 @@ package org.opensearch.plugin.wlm.rule.service; -import org.opensearch.action.search.SearchRequestBuilder; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.core.action.ActionListener; -import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.index.query.QueryBuilders; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.search.sort.SortOrder; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.client.Client; - -import java.util.HashMap; - -import static org.opensearch.autotagging.Rule._ID_STRING; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils._ID_ONE; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils._ID_TWO; -import static org.opensearch.plugin.wlm.rule.WlmRuleTestUtils.setUpRulePersistenceService; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") public class WlmRulePersistenceServiceTests extends OpenSearchTestCase { - public void testBuildGetRuleQuery_WithId() { - WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(_ID_ONE, new HashMap<>()); - assertTrue(query.hasClauses()); - assertEquals(QueryBuilders.termQuery(_ID_STRING, _ID_ONE).toString(), query.must().get(0).toString()); - } - - public void testBuildGetRuleQuery_WithFilters() { - WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(null, ATTRIBUTE_MAP); - assertTrue(query.hasClauses()); - assertEquals(1, query.must().size()); - assertTrue(query.filter().contains(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME))); - } - - public void testGetRule_WithId() { - WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - Client client = rulePersistenceService.getClient(); - ActionListener listener = mock(ActionListener.class); - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - SetupMocksForGetRule(client, searchRequestBuilder); - - rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), null, listener); - verify(client).prepareSearch(WlmRulePersistenceService.RULES_INDEX); - verify(searchRequestBuilder).setQuery(any()); - verify(searchRequestBuilder).execute(any()); - } - - public void testGetRule_WithSearchAfter() { - WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - Client client = rulePersistenceService.getClient(); - ActionListener listener = mock(ActionListener.class); - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - SetupMocksForGetRule(client, searchRequestBuilder); - when(searchRequestBuilder.addSort(anyString(), any(SortOrder.class))).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.searchAfter(any())).thenReturn(searchRequestBuilder); - - rulePersistenceService.getRule(null, new HashMap<>(), _ID_TWO, listener); - verify(searchRequestBuilder).addSort(_ID_STRING, SortOrder.ASC); - verify(searchRequestBuilder).searchAfter(new Object[] { _ID_TWO }); - } - - public void SetupMocksForGetRule(Client client, SearchRequestBuilder searchRequestBuilder) { - when(client.prepareSearch(anyString())).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setQuery(any())).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); - doAnswer(invocation -> { - ActionListener searchListener = invocation.getArgument(0); - searchListener.onResponse(mock(SearchResponse.class)); - return null; - }).when(searchRequestBuilder).execute(any()); - } + // public void testBuildGetRuleQuery_WithId() { + // WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + // BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(_ID_ONE, new HashMap<>()); + // assertTrue(query.hasClauses()); + // assertEquals(QueryBuilders.termQuery(_ID_STRING, _ID_ONE).toString(), query.must().get(0).toString()); + // } + // + // public void testBuildGetRuleQuery_WithFilters() { + // WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + // BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(null, ATTRIBUTE_MAP); + // assertTrue(query.hasClauses()); + // assertEquals(1, query.must().size()); + // assertTrue(query.filter().contains(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME))); + // } + // + // public void testGetRule_WithId() { + // WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + // Client client = rulePersistenceService.getClient(); + // ActionListener listener = mock(ActionListener.class); + // SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + // SetupMocksForGetRule(client, searchRequestBuilder); + // + // rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), null, listener); + // verify(client).prepareSearch(WlmRulePersistenceService.RULES_INDEX); + // verify(searchRequestBuilder).setQuery(any()); + // verify(searchRequestBuilder).execute(any()); + // } + // + // public void testGetRule_WithSearchAfter() { + // WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); + // Client client = rulePersistenceService.getClient(); + // ActionListener listener = mock(ActionListener.class); + // SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + // SetupMocksForGetRule(client, searchRequestBuilder); + // when(searchRequestBuilder.addSort(anyString(), any(SortOrder.class))).thenReturn(searchRequestBuilder); + // when(searchRequestBuilder.searchAfter(any())).thenReturn(searchRequestBuilder); + // + // rulePersistenceService.getRule(null, new HashMap<>(), _ID_TWO, listener); + // verify(searchRequestBuilder).addSort(_ID_STRING, SortOrder.ASC); + // verify(searchRequestBuilder).searchAfter(new Object[] { _ID_TWO }); + // } + // + // public void SetupMocksForGetRule(Client client, SearchRequestBuilder searchRequestBuilder) { + // when(client.prepareSearch(anyString())).thenReturn(searchRequestBuilder); + // when(searchRequestBuilder.setQuery(any())).thenReturn(searchRequestBuilder); + // when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); + // doAnswer(invocation -> { + // ActionListener searchListener = invocation.getArgument(0); + // searchListener.onResponse(mock(SearchResponse.class)); + // return null; + // }).when(searchRequestBuilder).execute(any()); + // } } From a85235250db4b88c96cbe2caec64e3e6bda7df61 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Thu, 3 Apr 2025 13:17:23 -0700 Subject: [PATCH 09/28] modify based on comments Signed-off-by: Ruirui Zhang --- .../IndexStoredRulePersistenceService.java | 37 +++-- .../rule/service/RulePersistenceService.java | 10 ++ .../IndexStoredRuleParser.java | 13 +- .../IndexStoredRuleUtils.java | 18 +- .../rule/{Utils => utils}/package-info.java | 2 +- .../org/opensearch/rule/RuleTestUtils.java | 157 ++++++++++++++++++ .../rule/action/GetRuleRequestTests.java | 53 ++++++ .../rule/action/GetRuleResponseTests.java | 123 ++++++++++++++ ...ndexStoredRulePersistenceServiceTests.java | 87 ++++++++++ .../utils/IndexStoredRuleParserTests.java | 54 ++++++ .../rule/utils/IndexStoredRuleUtilsTests.java | 42 +++++ .../plugin/wlm/WorkloadManagementPlugin.java | 12 +- .../action/TransportGetWlmRuleAction.java | 1 - .../plugin/wlm/rule/WlmRuleTestUtils.java | 91 ---------- .../WlmRulePersistenceServiceTests.java | 67 -------- .../java/org/opensearch/autotagging/Rule.java | 20 --- 16 files changed, 588 insertions(+), 199 deletions(-) rename libs/autotagging-commons/src/main/java/org/opensearch/rule/{Utils => utils}/IndexStoredRuleParser.java (82%) rename libs/autotagging-commons/src/main/java/org/opensearch/rule/{Utils => utils}/IndexStoredRuleUtils.java (69%) rename libs/autotagging-commons/src/main/java/org/opensearch/rule/{Utils => utils}/package-info.java (88%) create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/RuleTestUtils.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index 9ca715e4cecc0..52cd6e97a75b7 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -20,10 +20,10 @@ import org.opensearch.core.action.ActionListener; import org.opensearch.core.rest.RestStatus; import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.rule.Utils.IndexStoredRuleParser; -import org.opensearch.rule.Utils.IndexStoredRuleUtils; import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.utils.IndexStoredRuleParser; +import org.opensearch.rule.utils.IndexStoredRuleUtils; import org.opensearch.search.SearchHit; import org.opensearch.search.sort.SortOrder; import org.opensearch.transport.client.Client; @@ -47,27 +47,35 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService private final String indexName; private final Client client; private final FeatureType featureType; - private final int maxReturnSizeAllowedPerGetRequest; + private final int maxRulesPerGetRequest; private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); - public IndexStoredRulePersistenceService( - String indexName, - Client client, - FeatureType featureType, - int maxReturnSizeAllowedPerGetRequest - ) { + /** + * Constructs an instance of {@link IndexStoredRulePersistenceService} with the specified parameters. + * This service handles persistence and retrieval of stored rules within an OpenSearch index. + * @param indexName - The name of the OpenSearch index where the rules are stored. + * @param client - The OpenSearch client used to interact with the OpenSearch cluster. + * @param featureType - The feature type associated with the stored rules. + * @param maxRulesPerGetRequest - The maximum number of rules that can be returned in a single get request. + */ + public IndexStoredRulePersistenceService(String indexName, Client client, FeatureType featureType, int maxRulesPerGetRequest) { this.indexName = indexName; this.client = client; this.featureType = featureType; - this.maxReturnSizeAllowedPerGetRequest = maxReturnSizeAllowedPerGetRequest; + this.maxRulesPerGetRequest = maxRulesPerGetRequest; } + /** + * Entry point for the get rule api logic in persistence service. + * @param getRuleRequest the getRuleRequest to process. + * @param listener the listener for GetRuleResponse. + */ public void getRule(GetRuleRequest getRuleRequest, ActionListener listener) { getRuleFromIndex(getRuleRequest.getId(), getRuleRequest.getAttributeFilters(), getRuleRequest.getSearchAfter(), listener); } /** - * Entry point for the get rule api logic in persistence service. If id is provided, we only get a single rule. + * Get rules from index. If id is provided, we only get a single rule. * Otherwise, we get all rules that satisfy the attributeFilters. * @param id - The id of the rule to get. * @param attributeFilters - A map containing the attributes that user want to filter on @@ -85,9 +93,7 @@ public void getRuleFromIndex( // actions within this block are trusted and executed with system-level privileges. try (ThreadContext.StoredContext context = getContext()) { BoolQueryBuilder boolQuery = IndexStoredRuleUtils.buildGetRuleQuery(id, attributeFilters, featureType); - SearchRequestBuilder searchRequest = client.prepareSearch(indexName) - .setQuery(boolQuery) - .setSize(maxReturnSizeAllowedPerGetRequest); + SearchRequestBuilder searchRequest = client.prepareSearch(indexName).setQuery(boolQuery).setSize(maxRulesPerGetRequest); if (searchAfter != null) { searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); } @@ -120,6 +126,9 @@ private ThreadContext.StoredContext getContext() { return client.threadPool().getThreadContext().stashContext(); } + /** + * client getter + */ public Client getClient() { return client; } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java index 751607bbc9c92..adcccfc429210 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java @@ -12,6 +12,16 @@ import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; +/** + * Interface for a service that handles rule persistence CRUD operations. + * @opensearch.experimental + */ public interface RulePersistenceService { + + /** + * Get rules based on the provided request. + * @param request The request containing the details for retrieving the rule. + * @param listener The listener that will handle the response or failure. + */ void getRule(GetRuleRequest request, ActionListener listener); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleParser.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java similarity index 82% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleParser.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java index 0e921b7619c60..4d2e808a22c2d 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleParser.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule.Utils; +package org.opensearch.rule.utils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -19,12 +19,23 @@ import java.io.IOException; +/** + * Utility class for parsing index stored rules into Rule objects. + * @opensearch.experimental + */ public class IndexStoredRuleParser { + + /** + * constructor for IndexStoredRuleParser + */ + public IndexStoredRuleParser() {} + private static final Logger logger = LogManager.getLogger(IndexStoredRuleParser.class); /** * Parses a source string into a Rule object * @param source - The raw source string representing the rule to be parsed + * @param featureType - The feature type to associate with the parsed rule */ public static Rule parseRule(String source, FeatureType featureType) { try ( diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleUtils.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java similarity index 69% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleUtils.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java index e9f29fbe3c7c0..d43557a81b4f5 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/IndexStoredRuleUtils.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule.Utils; +package org.opensearch.rule.utils; import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.FeatureType; @@ -18,7 +18,23 @@ import static org.opensearch.autotagging.Rule._ID_STRING; +/** + * Utility class that provides methods for the lifecycle of rules. + * @opensearch.experimental + */ public class IndexStoredRuleUtils { + + /** + * constructor for IndexStoredRuleUtils + */ + public IndexStoredRuleUtils() {} + + /** + * Builds a Boolean query to retrieve a rule by its ID or attribute filters. + * @param id The ID of the rule to search for. If null, no ID-based filtering is applied. + * @param attributeFilters A map of attributes and their corresponding filter values. This allows filtering by specific attribute values. + * @param featureType The feature type that is required in the query. + */ public static BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters, FeatureType featureType) { BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); if (id != null) { diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java similarity index 88% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/package-info.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java index 37ec700e35f6f..c3437a5f6a77a 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/Utils/package-info.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java @@ -9,4 +9,4 @@ /** * This package contains utility classes for rules */ -package org.opensearch.rule.Utils; +package org.opensearch.rule.utils; diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/RuleTestUtils.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/RuleTestUtils.java new file mode 100644 index 0000000000000..7ab8ca45e8afc --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/RuleTestUtils.java @@ -0,0 +1,157 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.AutoTaggingRegistry; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.metadata.Metadata; +import org.opensearch.cluster.metadata.QueryGroup; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.client.Client; + +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class RuleTestUtils { + public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; + public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; + public static final String FEATURE_VALUE_ONE = "feature_value_one"; + public static final String FEATURE_VALUE_TWO = "feature_value_two"; + public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; + public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two"; + public static final String DESCRIPTION_ONE = "description_1"; + public static final String DESCRIPTION_TWO = "description_2"; + public static final String SEARCH_AFTER = "search_after_id"; + public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; + public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; + public static final String FEATURE_TYPE_NAME = "mock_feature_type"; + public static final String TEST_INDEX_NAME = ".test_index_for_rule"; + public static final Map> ATTRIBUTE_MAP = Map.of( + MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, + Set.of(ATTRIBUTE_VALUE_ONE) + ); + public static final Rule ruleOne = Rule.builder() + .description(DESCRIPTION_ONE) + .featureType(MockRuleFeatureType.INSTANCE) + .featureValue(FEATURE_VALUE_ONE) + .attributeMap(ATTRIBUTE_MAP) + .updatedAt(TIMESTAMP_ONE) + .build(); + + public static final Rule ruleTwo = Rule.builder() + .description(DESCRIPTION_TWO) + .featureType(MockRuleFeatureType.INSTANCE) + .featureValue(FEATURE_VALUE_TWO) + .attributeMap(Map.of(MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, Set.of(ATTRIBUTE_VALUE_TWO))) + .updatedAt(TIMESTAMP_TWO) + .build(); + + public static Map ruleMap() { + return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); + } + + public static IndexStoredRulePersistenceService setUpIndexStoredRulePersistenceService(Map queryGroupMap) { + Client client = mock(Client.class); + ClusterService clusterService = mock(ClusterService.class); + ClusterState clusterState = mock(ClusterState.class); + Metadata metadata = mock(Metadata.class); + ThreadPool threadPool = mock(ThreadPool.class); + + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + when(client.threadPool()).thenReturn(threadPool); + when(threadPool.getThreadContext()).thenReturn(threadContext); + when(clusterService.state()).thenReturn(clusterState); + when(clusterState.metadata()).thenReturn(metadata); + when(metadata.queryGroups()).thenReturn(queryGroupMap); + return new IndexStoredRulePersistenceService(TEST_INDEX_NAME, client, MockRuleFeatureType.INSTANCE, 50); + } + + public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { + assertEquals(mapOne.size(), mapTwo.size()); + for (Map.Entry entry : mapOne.entrySet()) { + String id = entry.getKey(); + assertTrue(mapTwo.containsKey(id)); + Rule one = mapOne.get(id); + Rule two = mapTwo.get(id); + assertEqualRule(one, two, ruleUpdated); + } + } + + public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { + if (ruleUpdated) { + assertEquals(one.getDescription(), two.getDescription()); + assertEquals(one.getFeatureType(), two.getFeatureType()); + assertEquals(one.getFeatureValue(), two.getFeatureValue()); + assertEquals(one.getAttributeMap(), two.getAttributeMap()); + assertEquals(one.getAttributeMap(), two.getAttributeMap()); + } else { + assertEquals(one, two); + } + } + + public static class MockRuleFeatureType implements FeatureType { + + public static final MockRuleFeatureType INSTANCE = new MockRuleFeatureType(); + + private MockRuleFeatureType() {} + + static { + INSTANCE.registerFeatureType(); + } + + @Override + public String getName() { + return FEATURE_TYPE_NAME; + } + + @Override + public Map getAllowedAttributesRegistry() { + return Map.of( + ATTRIBUTE_VALUE_ONE, + MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, + ATTRIBUTE_VALUE_TWO, + MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO + ); + } + + @Override + public void registerFeatureType() { + AutoTaggingRegistry.registerFeatureType(INSTANCE); + } + } + + public enum MockRuleAttributes implements Attribute { + MOCK_RULE_ATTRIBUTE_ONE(ATTRIBUTE_VALUE_ONE), + MOCK_RULE_ATTRIBUTE_TWO(ATTRIBUTE_VALUE_TWO); + ; + + private final String name; + + MockRuleAttributes(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java new file mode 100644 index 0000000000000..61f452e26f624 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.rule.RuleTestUtils; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.HashMap; + +import static org.opensearch.rule.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.RuleTestUtils.MockRuleFeatureType; +import static org.opensearch.rule.RuleTestUtils.SEARCH_AFTER; +import static org.opensearch.rule.RuleTestUtils._ID_ONE; + +public class GetRuleRequestTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of GetRuleRequest + */ + public void testSerialization() throws IOException { + GetRuleRequest request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertEquals(_ID_ONE, request.getId()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + GetRuleRequest otherRequest = new GetRuleRequest(streamInput); + assertEquals(request.getId(), otherRequest.getId()); + assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); + } + + /** + * Test case to verify the serialization and deserialization of GetRuleRequest when name is null + */ + public void testSerializationWithNull() throws IOException { + GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER, MockRuleFeatureType.INSTANCE); + assertNull(request.getId()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + GetRuleRequest otherRequest = new GetRuleRequest(streamInput); + assertEquals(request.getId(), otherRequest.getId()); + assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java new file mode 100644 index 0000000000000..5619bf4ee8567 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java @@ -0,0 +1,123 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.autotagging.Rule; +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.common.xcontent.json.JsonXContent; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.opensearch.rule.RuleTestUtils.SEARCH_AFTER; +import static org.opensearch.rule.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.RuleTestUtils.assertEqualRules; +import static org.opensearch.rule.RuleTestUtils.ruleMap; +import static org.opensearch.rule.RuleTestUtils.ruleOne; +import static org.mockito.Mockito.mock; + +public class GetRuleResponseTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of GetRuleResponse + */ + public void testSerializationSingleRule() throws IOException { + Map map = new HashMap<>(); + map.put(_ID_ONE, ruleOne); + GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), null, RestStatus.OK); + assertEquals(response.getRules(), map); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + assertEqualRules(response.getRules(), otherResponse.getRules(), false); + } + + /** + * Test case to verify the serialization and deserialization of GetRuleResponse when the result contains multiple rules + */ + public void testSerializationMultipleRule() throws IOException { + GetRuleResponse response = new GetRuleResponse(ruleMap(), SEARCH_AFTER, RestStatus.OK); + assertEquals(response.getRules(), ruleMap()); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + assertEquals(2, otherResponse.getRules().size()); + assertEqualRules(response.getRules(), otherResponse.getRules(), false); + } + + /** + * Test case to verify the serialization and deserialization of GetRuleResponse when the result is empty + */ + public void testSerializationNull() throws IOException { + Map map = new HashMap<>(); + GetRuleResponse response = new GetRuleResponse(map, SEARCH_AFTER, RestStatus.OK); + assertEquals(response.getRules(), map); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetRuleResponse otherResponse = new GetRuleResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + assertEquals(0, otherResponse.getRules().size()); + } + + /** + * Test case to verify the toXContent of GetRuleResponse + */ + public void testToXContentGetSingleRule() throws IOException { + Map map = new HashMap<>(); + map.put(_ID_ONE, ruleOne); + GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER, RestStatus.OK); + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + + " \"rules\" : [\n" + + " {\n" + + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + + " \"description\" : \"description_1\",\n" + + " \"mock_attribute_one\" : [\n" + + " \"pattern_1\"\n" + + " ],\n" + + " \"mock_feature_type\" : \"feature_value_one\",\n" + + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + + " }\n" + + " ],\n" + + " \"search_after\" : [\n" + + " \"search_after_id\"\n" + + " ]\n" + + "}"; + assertEquals(expected, actual); + } + + /** + * Test case to verify toXContent of GetRuleResponse when the result contains zero Rule + */ + public void testToXContentGetZeroRule() throws IOException { + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + GetRuleResponse otherResponse = new GetRuleResponse(new HashMap<>(), null, RestStatus.OK); + String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + " \"rules\" : [ ]\n" + "}"; + assertEquals(expected, actual); + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java new file mode 100644 index 0000000000000..ef67408c94dfd --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -0,0 +1,87 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.service; + +import org.apache.lucene.search.TotalHits; +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.search.SearchRequestBuilder; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.bytes.BytesArray; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.search.SearchHit; +import org.opensearch.search.SearchHits; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.client.Client; + +import java.util.HashMap; + +import org.mockito.ArgumentCaptor; + +import static org.opensearch.rule.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.RuleTestUtils.TEST_INDEX_NAME; +import static org.opensearch.rule.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.RuleTestUtils.setUpIndexStoredRulePersistenceService; +import static org.opensearch.rule.utils.IndexStoredRuleParserTests.VALID_JSON; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@SuppressWarnings("unchecked") +public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { + + public void testGetRuleByIdSuccess() { + IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + SearchResponse searchResponse = mock(SearchResponse.class); + SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + when(searchResponse.getHits()).thenReturn(searchHits); + SearchHit hit = searchHits.getHits()[0]; + hit.sourceRef(new BytesArray(VALID_JSON)); + + ActionListener listener = mock(ActionListener.class); + rulePersistenceService.handleGetRuleResponse(_ID_ONE, searchResponse, listener); + + ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); + verify(listener).onResponse(responseCaptor.capture()); + GetRuleResponse response = responseCaptor.getValue(); + assertEquals(response.getRules().size(), 1); + assertEquals(RestStatus.OK, response.getRestStatus()); + } + + public void testGetRuleByIdNotFound() { + IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); + + ActionListener listener = mock(ActionListener.class); + rulePersistenceService.handleGetRuleResponse(_ID_ONE, searchResponse, listener); + + ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); + verify(listener).onFailure(exceptionCaptor.capture()); + Exception exception = exceptionCaptor.getValue(); + assertTrue(exception instanceof ResourceNotFoundException); + } + + public void testGetRuleWithAttributes() { + IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + ActionListener listener = mock(ActionListener.class); + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + Client client = rulePersistenceService.getClient(); + when(client.prepareSearch(TEST_INDEX_NAME)).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setQuery(any(QueryBuilder.class))).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); + rulePersistenceService.getRuleFromIndex(null, ATTRIBUTE_MAP, null, listener); + verify(client).prepareSearch(TEST_INDEX_NAME); + verify(searchRequestBuilder).setQuery(any()); + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java new file mode 100644 index 0000000000000..3f5f122056510 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.utils; + +import org.opensearch.autotagging.Rule; +import org.opensearch.rule.RuleTestUtils; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.time.Instant; +import java.util.Locale; + +import static org.opensearch.rule.RuleTestUtils.DESCRIPTION_ONE; + +public class IndexStoredRuleParserTests extends OpenSearchTestCase { + public static final String VALID_JSON = String.format(Locale.ROOT, """ + { + "description": "%s", + "mock_feature_type": "feature value", + "mock_attribute_one": ["attribute_value_one", "attribute_value_two"], + "updated_at": "%s" + } + """, DESCRIPTION_ONE, Instant.now().toString()); + + private static final String INVALID_JSON = """ + { + "name": "TestRule", + "description": "A test rule for unit testing", + "mock_attribute_three": ["attribute_value_one", "attribute_value_two"] + } + """; + + public void testParseRule_Success() throws IOException { + Rule parsedRule = IndexStoredRuleParser.parseRule(VALID_JSON, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertNotNull(parsedRule); + assertEquals(DESCRIPTION_ONE, parsedRule.getDescription()); + assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, parsedRule.getFeatureType()); + } + + public void testParseRule_InvalidJson() { + Exception exception = assertThrows( + RuntimeException.class, + () -> IndexStoredRuleParser.parseRule(INVALID_JSON, RuleTestUtils.MockRuleFeatureType.INSTANCE) + ); + assertTrue(exception.getMessage().contains("mock_attribute_three is not a valid attribute within the mock_feature_type feature.")); + } + +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java new file mode 100644 index 0000000000000..ed9b3bbb4cc79 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.utils; + +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.RuleTestUtils; +import org.opensearch.test.OpenSearchTestCase; + +import java.util.HashMap; + +import static org.opensearch.rule.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.RuleTestUtils.ATTRIBUTE_VALUE_ONE; +import static org.opensearch.rule.RuleTestUtils._ID_ONE; + +public class IndexStoredRuleUtilsTests extends OpenSearchTestCase { + public void testBuildGetRuleQuery_WithId() { + BoolQueryBuilder query = IndexStoredRuleUtils.buildGetRuleQuery( + _ID_ONE, + new HashMap<>(), + RuleTestUtils.MockRuleFeatureType.INSTANCE + ); + assertNotNull(query); + assertEquals(1, query.must().size()); + QueryBuilder idQuery = query.must().get(0); + assertTrue(idQuery.toString().contains(_ID_ONE)); + } + + public void testBuildGetRuleQuery_WithAttributes() { + BoolQueryBuilder query = IndexStoredRuleUtils.buildGetRuleQuery(null, ATTRIBUTE_MAP, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertNotNull(query); + assertTrue(query.must().size() == 1); + assertTrue(query.toString().contains(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE.getName())); + assertTrue(query.toString().contains(ATTRIBUTE_VALUE_ONE)); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index 6ac5f317a3f0b..bc9095624bcba 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -60,8 +60,14 @@ * Plugin class for WorkloadManagement */ public class WorkloadManagementPlugin extends Plugin implements ActionPlugin, SystemIndexPlugin { + /** + * The name of the index where rules are stored. + */ public static final String INDEX_NAME = ".wlm_rules"; - public static final int MAX_ENTRY_SIZE_PER_GET_REQUEST = 50; + /** + * The maximum number of rules allowed per GET request. + */ + public static final int MAX_RULES_PER_GET_REQUEST = 50; /** * Default constructor @@ -83,7 +89,7 @@ public Collection createComponents( Supplier repositoriesServiceSupplier ) { return List.of( - new IndexStoredRulePersistenceService(INDEX_NAME, client, QueryGroupFeatureType.INSTANCE, MAX_ENTRY_SIZE_PER_GET_REQUEST) + new IndexStoredRulePersistenceService(INDEX_NAME, client, QueryGroupFeatureType.INSTANCE, MAX_RULES_PER_GET_REQUEST) ); } @@ -100,7 +106,7 @@ public Collection createComponents( @Override public Collection getSystemIndexDescriptors(Settings settings) { - return List.of(new SystemIndexDescriptor(".wlm_rules", "System index used for storing rules")); + return List.of(new SystemIndexDescriptor(INDEX_NAME, "System index used for storing rules")); } @Override diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java index e4bb603f869a7..0f8f3c3f4628c 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java @@ -14,7 +14,6 @@ import org.opensearch.core.action.ActionListener; import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; -import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.rule.service.RulePersistenceService; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java deleted file mode 100644 index 6a96918633e9b..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WlmRuleTestUtils.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule; - -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.Rule; - -import java.util.Map; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class WlmRuleTestUtils { - public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; - public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; - public static final String FEATURE_VALUE_ONE = "feature_value_one"; - public static final String FEATURE_VALUE_TWO = "feature_value_two"; - public static final String PATTERN_ONE = "pattern_1"; - public static final String PATTERN_TWO = "pattern_2"; - public static final String DESCRIPTION_ONE = "description_1"; - public static final String DESCRIPTION_TWO = "description_2"; - public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; - public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; - public static final String SEARCH_AFTER = "search_after_id"; - public static final Map> ATTRIBUTE_MAP = Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE)); - public static final Rule ruleOne = Rule.builder() - .description(DESCRIPTION_ONE) - .featureType(QueryGroupFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_ONE) - .attributeMap(Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_ONE))) - .updatedAt(TIMESTAMP_ONE) - .build(); - - public static final Rule ruleTwo = Rule.builder() - .description(DESCRIPTION_TWO) - .featureType(QueryGroupFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_TWO) - .attributeMap(Map.of(QueryGroupAttribute.INDEX_PATTERN, Set.of(PATTERN_TWO))) - .updatedAt(TIMESTAMP_TWO) - .build(); - - public static Map ruleMap() { - return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); - } - - // public static WlmRulePersistenceService setUpRulePersistenceService(Map queryGroupMap) { - // Client client = mock(Client.class); - // ClusterService clusterService = mock(ClusterService.class); - // ClusterState clusterState = mock(ClusterState.class); - // Metadata metadata = mock(Metadata.class); - // ThreadPool threadPool = mock(ThreadPool.class); - // - // ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - // when(client.threadPool()).thenReturn(threadPool); - // when(threadPool.getThreadContext()).thenReturn(threadContext); - // when(clusterService.state()).thenReturn(clusterState); - // when(clusterState.metadata()).thenReturn(metadata); - // when(metadata.queryGroups()).thenReturn(queryGroupMap); - // return new WlmRulePersistenceService(clusterService, client); - // } - - public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { - assertEquals(mapOne.size(), mapTwo.size()); - for (Map.Entry entry : mapOne.entrySet()) { - String id = entry.getKey(); - assertTrue(mapTwo.containsKey(id)); - Rule one = mapOne.get(id); - Rule two = mapTwo.get(id); - assertEqualRule(one, two, ruleUpdated); - } - } - - public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { - if (ruleUpdated) { - assertEquals(one.getDescription(), two.getDescription()); - assertEquals(one.getFeatureType(), two.getFeatureType()); - assertEquals(one.getFeatureValue(), two.getFeatureValue()); - assertEquals(one.getAttributeMap(), two.getAttributeMap()); - assertEquals(one.getAttributeMap(), two.getAttributeMap()); - } else { - assertEquals(one, two); - } - } -} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java deleted file mode 100644 index 6df56b15ed875..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/WlmRulePersistenceServiceTests.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.service; - -import org.opensearch.test.OpenSearchTestCase; - -@SuppressWarnings("unchecked") -public class WlmRulePersistenceServiceTests extends OpenSearchTestCase { - // public void testBuildGetRuleQuery_WithId() { - // WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - // BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(_ID_ONE, new HashMap<>()); - // assertTrue(query.hasClauses()); - // assertEquals(QueryBuilders.termQuery(_ID_STRING, _ID_ONE).toString(), query.must().get(0).toString()); - // } - // - // public void testBuildGetRuleQuery_WithFilters() { - // WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - // BoolQueryBuilder query = rulePersistenceService.buildGetRuleQuery(null, ATTRIBUTE_MAP); - // assertTrue(query.hasClauses()); - // assertEquals(1, query.must().size()); - // assertTrue(query.filter().contains(QueryBuilders.existsQuery(QueryGroupFeatureType.NAME))); - // } - // - // public void testGetRule_WithId() { - // WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - // Client client = rulePersistenceService.getClient(); - // ActionListener listener = mock(ActionListener.class); - // SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - // SetupMocksForGetRule(client, searchRequestBuilder); - // - // rulePersistenceService.getRule(_ID_ONE, new HashMap<>(), null, listener); - // verify(client).prepareSearch(WlmRulePersistenceService.RULES_INDEX); - // verify(searchRequestBuilder).setQuery(any()); - // verify(searchRequestBuilder).execute(any()); - // } - // - // public void testGetRule_WithSearchAfter() { - // WlmRulePersistenceService rulePersistenceService = setUpRulePersistenceService(new HashMap<>()); - // Client client = rulePersistenceService.getClient(); - // ActionListener listener = mock(ActionListener.class); - // SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - // SetupMocksForGetRule(client, searchRequestBuilder); - // when(searchRequestBuilder.addSort(anyString(), any(SortOrder.class))).thenReturn(searchRequestBuilder); - // when(searchRequestBuilder.searchAfter(any())).thenReturn(searchRequestBuilder); - // - // rulePersistenceService.getRule(null, new HashMap<>(), _ID_TWO, listener); - // verify(searchRequestBuilder).addSort(_ID_STRING, SortOrder.ASC); - // verify(searchRequestBuilder).searchAfter(new Object[] { _ID_TWO }); - // } - // - // public void SetupMocksForGetRule(Client client, SearchRequestBuilder searchRequestBuilder) { - // when(client.prepareSearch(anyString())).thenReturn(searchRequestBuilder); - // when(searchRequestBuilder.setQuery(any())).thenReturn(searchRequestBuilder); - // when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); - // doAnswer(invocation -> { - // ActionListener searchListener = invocation.getArgument(0); - // searchListener.onResponse(mock(SearchResponse.class)); - // return null; - // }).when(searchRequestBuilder).execute(any()); - // } -} diff --git a/server/src/main/java/org/opensearch/autotagging/Rule.java b/server/src/main/java/org/opensearch/autotagging/Rule.java index e058933a26e8e..0e64e977124d5 100644 --- a/server/src/main/java/org/opensearch/autotagging/Rule.java +++ b/server/src/main/java/org/opensearch/autotagging/Rule.java @@ -13,9 +13,6 @@ import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.core.common.io.stream.Writeable; -import org.opensearch.core.xcontent.DeprecationHandler; -import org.opensearch.core.xcontent.MediaTypeRegistry; -import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.core.xcontent.XContentParseException; @@ -93,23 +90,6 @@ public static Rule fromXContent(final XContentParser parser, FeatureType feature return Builder.fromXContent(parser, featureType).build(); } - /** - * Parses a source string into a Rule object - * @param id - document id for the Rule object - * @param source - The raw source string representing the rule to be parsed - */ - public static Map.Entry parseRule(String id, String source, FeatureType featureType) { - try ( - XContentParser parser = MediaTypeRegistry.JSON.xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source) - ) { - return Map.entry(id, Builder.fromXContent(parser, featureType).build()); - } catch (IOException e) { - logger.info("Issue met when parsing rule for ID {}: {}", id, e.getMessage()); - return null; - } - } - public String getDescription() { return description; } From 0790b36fd47992b9b8fd022495e736127b394b4c Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Thu, 3 Apr 2025 19:40:55 -0700 Subject: [PATCH 10/28] correct UT Signed-off-by: Ruirui Zhang --- .../org/opensearch/rule/rest/RestGetRuleAction.java | 2 +- .../service/IndexStoredRulePersistenceService.java | 10 +++++----- .../opensearch/rule/action/GetRuleRequestTests.java | 10 +++++----- .../opensearch/rule/action/GetRuleResponseTests.java | 12 ++++++------ .../IndexStoredRulePersistenceServiceTests.java | 8 ++++---- .../rule/utils/IndexStoredRuleParserTests.java | 3 +-- .../rule/utils/IndexStoredRuleUtilsTests.java | 7 +++---- .../opensearch/rule/{ => utils}/RuleTestUtils.java | 2 +- .../plugin/wlm/WorkloadManagementPlugin.java | 6 ++---- .../plugin/wlm/rule/rest/RestGetWlmRuleAction.java | 2 +- 10 files changed, 29 insertions(+), 33 deletions(-) rename libs/autotagging-commons/src/test/java/org/opensearch/rule/{ => utils}/RuleTestUtils.java (99%) diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java index f27bdfbbb4e59..637fb68d7bb76 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java @@ -90,7 +90,7 @@ public RestResponse buildResponse(final GetRuleResponse response) throws Excepti /** * Abstract method for subclasses to provide specific ActionType Instance */ - protected abstract > T retrieveGetRuleActionInstance(); + protected abstract > T retrieveGetRuleActionInstance(); /** * Abstract method for subclasses to construct a {@link GetRuleRequest}. This method allows subclasses diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index 52cd6e97a75b7..89aa81dfb02e4 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -47,7 +47,7 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService private final String indexName; private final Client client; private final FeatureType featureType; - private final int maxRulesPerGetRequest; + private final int maxRulesPerPage; private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); /** @@ -56,13 +56,13 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService * @param indexName - The name of the OpenSearch index where the rules are stored. * @param client - The OpenSearch client used to interact with the OpenSearch cluster. * @param featureType - The feature type associated with the stored rules. - * @param maxRulesPerGetRequest - The maximum number of rules that can be returned in a single get request. + * @param maxRulesPerPage - The maximum number of rules that can be returned in a single get request. */ - public IndexStoredRulePersistenceService(String indexName, Client client, FeatureType featureType, int maxRulesPerGetRequest) { + public IndexStoredRulePersistenceService(String indexName, Client client, FeatureType featureType, int maxRulesPerPage) { this.indexName = indexName; this.client = client; this.featureType = featureType; - this.maxRulesPerGetRequest = maxRulesPerGetRequest; + this.maxRulesPerPage = maxRulesPerPage; } /** @@ -93,7 +93,7 @@ public void getRuleFromIndex( // actions within this block are trusted and executed with system-level privileges. try (ThreadContext.StoredContext context = getContext()) { BoolQueryBuilder boolQuery = IndexStoredRuleUtils.buildGetRuleQuery(id, attributeFilters, featureType); - SearchRequestBuilder searchRequest = client.prepareSearch(indexName).setQuery(boolQuery).setSize(maxRulesPerGetRequest); + SearchRequestBuilder searchRequest = client.prepareSearch(indexName).setQuery(boolQuery).setSize(maxRulesPerPage); if (searchAfter != null) { searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); } diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java index 61f452e26f624..110e51b777be4 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java @@ -10,16 +10,16 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.RuleTestUtils; +import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; import java.util.HashMap; -import static org.opensearch.rule.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.RuleTestUtils.MockRuleFeatureType; -import static org.opensearch.rule.RuleTestUtils.SEARCH_AFTER; -import static org.opensearch.rule.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; +import static org.opensearch.rule.utils.RuleTestUtils.SEARCH_AFTER; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; public class GetRuleRequestTests extends OpenSearchTestCase { diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java index 5619bf4ee8567..ca5355c1b8e91 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java @@ -21,11 +21,11 @@ import java.util.HashMap; import java.util.Map; -import static org.opensearch.rule.RuleTestUtils.SEARCH_AFTER; -import static org.opensearch.rule.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.RuleTestUtils.assertEqualRules; -import static org.opensearch.rule.RuleTestUtils.ruleMap; -import static org.opensearch.rule.RuleTestUtils.ruleOne; +import static org.opensearch.rule.utils.RuleTestUtils.SEARCH_AFTER; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRules; +import static org.opensearch.rule.utils.RuleTestUtils.ruleMap; +import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; import static org.mockito.Mockito.mock; public class GetRuleResponseTests extends OpenSearchTestCase { @@ -97,7 +97,7 @@ public void testToXContentGetSingleRule() throws IOException { + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + " \"description\" : \"description_1\",\n" + " \"mock_attribute_one\" : [\n" - + " \"pattern_1\"\n" + + " \"mock_attribute_one\"\n" + " ],\n" + " \"mock_feature_type\" : \"feature_value_one\",\n" + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index ef67408c94dfd..f335cb75332b8 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -26,11 +26,11 @@ import org.mockito.ArgumentCaptor; -import static org.opensearch.rule.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.RuleTestUtils.TEST_INDEX_NAME; -import static org.opensearch.rule.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.RuleTestUtils.setUpIndexStoredRulePersistenceService; import static org.opensearch.rule.utils.IndexStoredRuleParserTests.VALID_JSON; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.setUpIndexStoredRulePersistenceService; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java index 3f5f122056510..7cd37b783705a 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java @@ -9,14 +9,13 @@ package org.opensearch.rule.utils; import org.opensearch.autotagging.Rule; -import org.opensearch.rule.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; import java.time.Instant; import java.util.Locale; -import static org.opensearch.rule.RuleTestUtils.DESCRIPTION_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; public class IndexStoredRuleParserTests extends OpenSearchTestCase { public static final String VALID_JSON = String.format(Locale.ROOT, """ diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java index ed9b3bbb4cc79..7e35a0de87c29 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java @@ -10,14 +10,13 @@ import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.util.HashMap; -import static org.opensearch.rule.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.RuleTestUtils.ATTRIBUTE_VALUE_ONE; -import static org.opensearch.rule.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; public class IndexStoredRuleUtilsTests extends OpenSearchTestCase { public void testBuildGetRuleQuery_WithId() { diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/RuleTestUtils.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java similarity index 99% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/RuleTestUtils.java rename to libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index 7ab8ca45e8afc..689f86cd51cbb 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/RuleTestUtils.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule; +package org.opensearch.rule.utils; import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.AutoTaggingRegistry; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index bc9095624bcba..c4e664f8ccdc2 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -67,7 +67,7 @@ public class WorkloadManagementPlugin extends Plugin implements ActionPlugin, Sy /** * The maximum number of rules allowed per GET request. */ - public static final int MAX_RULES_PER_GET_REQUEST = 50; + public static final int MAX_RULES_PER_PAGE = 50; /** * Default constructor @@ -88,9 +88,7 @@ public Collection createComponents( IndexNameExpressionResolver indexNameExpressionResolver, Supplier repositoriesServiceSupplier ) { - return List.of( - new IndexStoredRulePersistenceService(INDEX_NAME, client, QueryGroupFeatureType.INSTANCE, MAX_RULES_PER_GET_REQUEST) - ); + return List.of(new IndexStoredRulePersistenceService(INDEX_NAME, client, QueryGroupFeatureType.INSTANCE, MAX_RULES_PER_PAGE)); } @Override diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java index 437dd8b246091..bfe6dd570858f 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java @@ -53,7 +53,7 @@ protected Attribute getAttributeFromName(String name) { @Override @SuppressWarnings("unchecked") - protected > T retrieveGetRuleActionInstance() { + protected > T retrieveGetRuleActionInstance() { return (T) GetWlmRuleAction.INSTANCE; } From 5c4856c2222f342ec057ecf06bd1280ac1a68c2c Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Fri, 4 Apr 2025 17:01:17 -0700 Subject: [PATCH 11/28] modify based on comments Signed-off-by: Ruirui Zhang r --- .../rule/action/GetRuleRequest.java | 12 ++ .../rule/action/GetRuleResponse.java | 18 +-- .../rule/rest/RestGetRuleAction.java | 93 +++++++++----- .../IndexStoredRulePersistenceService.java | 9 +- .../rule/utils/IndexStoredRuleParser.java | 7 +- .../rule/utils/IndexStoredRuleUtils.java | 3 + .../rule/action/GetRuleResponseTests.java | 14 +-- ...ndexStoredRulePersistenceServiceTests.java | 116 +++++++----------- .../plugin/wlm/WorkloadManagementPlugin.java | 12 +- .../wlm/rule/rest/RestGetWlmRuleAction.java | 64 ---------- .../plugin/wlm/rule/rest/package-info.java | 12 -- .../rule/rest/RestGetWlmRuleActionTests.java | 36 ------ .../opensearch/autotagging/RuleValidator.java | 4 + 13 files changed, 153 insertions(+), 247 deletions(-) delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleActionTests.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java index 03d1899a2e6a8..95a7f3ef9829f 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java @@ -12,6 +12,7 @@ import org.opensearch.action.ActionRequestValidationException; import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.FeatureType; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; @@ -20,6 +21,10 @@ import java.util.Map; import java.util.Set; +import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.autotagging.RuleValidator.isEmpty; +import static org.opensearch.rule.rest.RestGetRuleAction.SEARCH_AFTER_STRING; + /** * A request for get Rule * Example Request: @@ -29,6 +34,7 @@ * curl -X GET "localhost:9200/_wlm/rule?index_pattern=a,b" - get all rules containing attribute index_pattern as a or b * @opensearch.experimental */ +@ExperimentalApi public class GetRuleRequest extends ActionRequest { private final String id; private final Map> attributeFilters; @@ -63,6 +69,12 @@ public GetRuleRequest(StreamInput in) throws IOException { @Override public ActionRequestValidationException validate() { + if (isEmpty(id)) { + throw new IllegalArgumentException(_ID_STRING + " cannot be empty."); + } + if (isEmpty(searchAfter)) { + throw new IllegalArgumentException(SEARCH_AFTER_STRING + " cannot be empty."); + } return null; } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java index 110522ff86af6..40eef52c26d6b 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java @@ -9,10 +9,10 @@ package org.opensearch.rule.action; import org.opensearch.autotagging.Rule; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; @@ -40,21 +40,19 @@ * } * @opensearch.experimental */ +@ExperimentalApi public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { private final Map rules; private final String searchAfter; - private final RestStatus restStatus; /** * Constructor for GetRuleResponse * @param rules - Rules get from the request * @param searchAfter - The sort value used for pagination. - * @param restStatus - Status of the GetRuleResponse */ - public GetRuleResponse(final Map rules, String searchAfter, RestStatus restStatus) { + public GetRuleResponse(final Map rules, String searchAfter) { this.rules = rules; this.searchAfter = searchAfter; - this.restStatus = restStatus; } /** @@ -62,14 +60,13 @@ public GetRuleResponse(final Map rules, String searchAfter, RestSt * @param in - The {@link StreamInput} instance to read from. */ public GetRuleResponse(StreamInput in) throws IOException { - this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString(), RestStatus.readFrom(in)); + this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString()); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeMap(rules, StreamOutput::writeString, (outStream, rule) -> rule.writeTo(outStream)); out.writeOptionalString(searchAfter); - RestStatus.writeTo(out, restStatus); } @Override @@ -93,11 +90,4 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws public Map getRules() { return rules; } - - /** - * restStatus getter - */ - public RestStatus getRestStatus() { - return restStatus; - } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java index 637fb68d7bb76..e373ad85282c2 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java @@ -10,6 +10,8 @@ import org.opensearch.action.ActionType; import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.rest.BaseRestHandler; @@ -36,22 +38,40 @@ * Rest action to get a Rule * @opensearch.experimental */ -public abstract class RestGetRuleAction extends BaseRestHandler { +@ExperimentalApi +public class RestGetRuleAction extends BaseRestHandler { + private final String name; + private final List routes; + private final FeatureType featureType; + private final ActionType getRuleAction; /** * field name used for pagination */ public static final String SEARCH_AFTER_STRING = "search_after"; /** - * Constructor for RestGetRuleAction + * constructor for RestGetRuleAction + * @param name - RestGetRuleAction name + * @param routes the list of REST routes this action handles + * @param featureType the feature type associated with the rule + * @param getRuleAction the action to execute for getting a rule */ - public RestGetRuleAction() {} + public RestGetRuleAction(String name, List routes, FeatureType featureType, ActionType getRuleAction) { + this.name = name; + this.routes = routes; + this.featureType = featureType; + this.getRuleAction = getRuleAction; + } @Override - public abstract String getName(); + public String getName() { + return name; + } @Override - public abstract List routes(); + public List routes() { + return routes; + } @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { @@ -60,15 +80,46 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli if (attributeName.equals(_ID_STRING) || attributeName.equals(SEARCH_AFTER_STRING)) { continue; } - String[] valuesArray = request.param(attributeName).split(","); - attributeFilters.put(getAttributeFromName(attributeName), new HashSet<>(Arrays.asList(valuesArray))); + Attribute attribute = featureType.getAttributeFromName(attributeName); + if (attribute == null) { + throw new IllegalArgumentException(attributeName + " is not a valid attribute under feature type " + featureType.getName()); + } + attributeFilters.put(attribute, parseAttributeValues(request.param(attributeName), attributeName)); } - final GetRuleRequest getRuleRequest = buildGetRuleRequest( + final GetRuleRequest getRuleRequest = new GetRuleRequest( request.param(_ID_STRING), attributeFilters, - request.param(SEARCH_AFTER_STRING) + request.param(SEARCH_AFTER_STRING), + featureType ); - return channel -> client.execute(retrieveGetRuleActionInstance(), getRuleRequest, getRuleResponse(channel)); + return channel -> client.execute(getRuleAction, getRuleRequest, getRuleResponse(channel)); + } + + /** + * Parses a comma-separated string of attribute values and validates each value. + * @param attributeValues - the comma-separated string representing attributeValues + * @param attributeName - attribute name + */ + private HashSet parseAttributeValues(String attributeValues, String attributeName) { + String[] valuesArray = attributeValues.split(","); + int maxNumberOfValuesPerAttribute = featureType.getMaxNumberOfValuesPerAttribute(); + if (valuesArray.length > maxNumberOfValuesPerAttribute) { + throw new IllegalArgumentException( + "The attribute value length for " + attributeName + " exceeds the maximum allowed of " + maxNumberOfValuesPerAttribute + ); + } + for (String value : valuesArray) { + if (value == null || value.trim().isEmpty() || value.length() > featureType.getMaxCharLengthPerAttributeValue()) { + throw new IllegalArgumentException( + "Invalid attribute value for: " + + attributeName + + " : String cannot be empty or over " + + featureType.getMaxCharLengthPerAttributeValue() + + " characters." + ); + } + } + return new HashSet<>(Arrays.asList(valuesArray)); } private RestResponseListener getRuleResponse(final RestChannel channel) { @@ -79,26 +130,4 @@ public RestResponse buildResponse(final GetRuleResponse response) throws Excepti } }; } - - /** - * Abstract method for subclasses to retrieve the Attribute corresponding - * to the attribute name. - * @param name - The name of the attribute to retrieve. - */ - protected abstract Attribute getAttributeFromName(String name); - - /** - * Abstract method for subclasses to provide specific ActionType Instance - */ - protected abstract > T retrieveGetRuleActionInstance(); - - /** - * Abstract method for subclasses to construct a {@link GetRuleRequest}. This method allows subclasses - * to define their own request-building logic depending on their specific needs. - * - * @param id - The ID of the rule to retrieve. - * @param attributeFilters - A map of {@link Attribute} keys to sets of string values for filtering. - * @param searchAfter - The pagination value to fetch the next set of results. - */ - protected abstract GetRuleRequest buildGetRuleRequest(String id, Map> attributeFilters, String searchAfter); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index 89aa81dfb02e4..7253098688b27 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -18,7 +18,6 @@ import org.opensearch.autotagging.Rule; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; -import org.opensearch.core.rest.RestStatus; import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; @@ -82,7 +81,7 @@ public void getRule(GetRuleRequest getRuleRequest, ActionListener> attributeFilters, String searchAfter, @@ -109,17 +108,17 @@ public void getRuleFromIndex( * @param searchResponse - Response received from index * @param listener - ActionListener for GetRuleResponse */ - void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { + private void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { List hits = Arrays.asList(searchResponse.getHits().getHits()); if (id != null && hits.isEmpty()) { logger.error("Rule with ID " + id + " not found."); - listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " doesn't exist in the .rules index.")); + listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " not found.")); return; } Map ruleMap = hits.stream() .collect(Collectors.toMap(SearchHit::getId, hit -> IndexStoredRuleParser.parseRule(hit.getSourceAsString(), featureType))); String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); - listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); + listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter)); } private ThreadContext.StoredContext getContext() { diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java index 4d2e808a22c2d..1965cf0d3d4df 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java @@ -19,10 +19,13 @@ import java.io.IOException; +import jdk.jfr.Experimental; + /** * Utility class for parsing index stored rules into Rule objects. * @opensearch.experimental */ +@Experimental public class IndexStoredRuleParser { /** @@ -44,8 +47,8 @@ public static Rule parseRule(String source, FeatureType featureType) { ) { return Rule.Builder.fromXContent(parser, featureType).build(); } catch (IOException e) { - logger.info("Issue met when parsing rule {}: {}", source, e.getMessage()); - throw new RuntimeException("Cannot parse rule from index: " + source); + logger.info("Issue met when parsing rule : {}", e.getMessage()); + throw new RuntimeException("Cannot parse rule from index."); } } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java index d43557a81b4f5..5b818a4feede8 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java @@ -16,12 +16,15 @@ import java.util.Map; import java.util.Set; +import jdk.jfr.Experimental; + import static org.opensearch.autotagging.Rule._ID_STRING; /** * Utility class that provides methods for the lifecycle of rules. * @opensearch.experimental */ +@Experimental public class IndexStoredRuleUtils { /** diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java index ca5355c1b8e91..7d441fd44fa6a 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java @@ -12,7 +12,6 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.common.xcontent.json.JsonXContent; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.test.OpenSearchTestCase; @@ -36,7 +35,7 @@ public class GetRuleResponseTests extends OpenSearchTestCase { public void testSerializationSingleRule() throws IOException { Map map = new HashMap<>(); map.put(_ID_ONE, ruleOne); - GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), null, RestStatus.OK); + GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), null); assertEquals(response.getRules(), map); BytesStreamOutput out = new BytesStreamOutput(); @@ -44,7 +43,6 @@ public void testSerializationSingleRule() throws IOException { StreamInput streamInput = out.bytes().streamInput(); GetRuleResponse otherResponse = new GetRuleResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); assertEqualRules(response.getRules(), otherResponse.getRules(), false); } @@ -52,7 +50,7 @@ public void testSerializationSingleRule() throws IOException { * Test case to verify the serialization and deserialization of GetRuleResponse when the result contains multiple rules */ public void testSerializationMultipleRule() throws IOException { - GetRuleResponse response = new GetRuleResponse(ruleMap(), SEARCH_AFTER, RestStatus.OK); + GetRuleResponse response = new GetRuleResponse(ruleMap(), SEARCH_AFTER); assertEquals(response.getRules(), ruleMap()); BytesStreamOutput out = new BytesStreamOutput(); @@ -60,7 +58,6 @@ public void testSerializationMultipleRule() throws IOException { StreamInput streamInput = out.bytes().streamInput(); GetRuleResponse otherResponse = new GetRuleResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); assertEquals(2, otherResponse.getRules().size()); assertEqualRules(response.getRules(), otherResponse.getRules(), false); } @@ -70,7 +67,7 @@ public void testSerializationMultipleRule() throws IOException { */ public void testSerializationNull() throws IOException { Map map = new HashMap<>(); - GetRuleResponse response = new GetRuleResponse(map, SEARCH_AFTER, RestStatus.OK); + GetRuleResponse response = new GetRuleResponse(map, SEARCH_AFTER); assertEquals(response.getRules(), map); BytesStreamOutput out = new BytesStreamOutput(); @@ -78,7 +75,6 @@ public void testSerializationNull() throws IOException { StreamInput streamInput = out.bytes().streamInput(); GetRuleResponse otherResponse = new GetRuleResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); assertEquals(0, otherResponse.getRules().size()); } @@ -88,7 +84,7 @@ public void testSerializationNull() throws IOException { public void testToXContentGetSingleRule() throws IOException { Map map = new HashMap<>(); map.put(_ID_ONE, ruleOne); - GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER, RestStatus.OK); + GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER); XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" @@ -115,7 +111,7 @@ public void testToXContentGetSingleRule() throws IOException { */ public void testToXContentGetZeroRule() throws IOException { XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - GetRuleResponse otherResponse = new GetRuleResponse(new HashMap<>(), null, RestStatus.OK); + GetRuleResponse otherResponse = new GetRuleResponse(new HashMap<>(), null); String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" + " \"rules\" : [ ]\n" + "}"; assertEquals(expected, actual); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index f335cb75332b8..9f30896a1086b 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -8,80 +8,52 @@ package org.opensearch.rule.service; -import org.apache.lucene.search.TotalHits; -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.search.SearchRequestBuilder; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.common.bytes.BytesArray; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.action.GetRuleResponse; -import org.opensearch.search.SearchHit; -import org.opensearch.search.SearchHits; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.client.Client; - -import java.util.HashMap; - -import org.mockito.ArgumentCaptor; - -import static org.opensearch.rule.utils.IndexStoredRuleParserTests.VALID_JSON; -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.setUpIndexStoredRulePersistenceService; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { - - public void testGetRuleByIdSuccess() { - IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - SearchResponse searchResponse = mock(SearchResponse.class); - SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); - when(searchResponse.getHits()).thenReturn(searchHits); - SearchHit hit = searchHits.getHits()[0]; - hit.sourceRef(new BytesArray(VALID_JSON)); - - ActionListener listener = mock(ActionListener.class); - rulePersistenceService.handleGetRuleResponse(_ID_ONE, searchResponse, listener); - - ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); - verify(listener).onResponse(responseCaptor.capture()); - GetRuleResponse response = responseCaptor.getValue(); - assertEquals(response.getRules().size(), 1); - assertEquals(RestStatus.OK, response.getRestStatus()); - } - - public void testGetRuleByIdNotFound() { - IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - SearchResponse searchResponse = mock(SearchResponse.class); - when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); - - ActionListener listener = mock(ActionListener.class); - rulePersistenceService.handleGetRuleResponse(_ID_ONE, searchResponse, listener); - - ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); - verify(listener).onFailure(exceptionCaptor.capture()); - Exception exception = exceptionCaptor.getValue(); - assertTrue(exception instanceof ResourceNotFoundException); - } - - public void testGetRuleWithAttributes() { - IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - ActionListener listener = mock(ActionListener.class); - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - Client client = rulePersistenceService.getClient(); - when(client.prepareSearch(TEST_INDEX_NAME)).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setQuery(any(QueryBuilder.class))).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); - rulePersistenceService.getRuleFromIndex(null, ATTRIBUTE_MAP, null, listener); - verify(client).prepareSearch(TEST_INDEX_NAME); - verify(searchRequestBuilder).setQuery(any()); - } + // + // public void testGetRuleByIdSuccess() { + // IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + // SearchResponse searchResponse = mock(SearchResponse.class); + // SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + // when(searchResponse.getHits()).thenReturn(searchHits); + // SearchHit hit = searchHits.getHits()[0]; + // hit.sourceRef(new BytesArray(VALID_JSON)); + // + // ActionListener listener = mock(ActionListener.class); + // rulePersistenceService.handleGetRuleResponse(_ID_ONE, searchResponse, listener); + // + // ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); + // verify(listener).onResponse(responseCaptor.capture()); + // GetRuleResponse response = responseCaptor.getValue(); + // assertEquals(response.getRules().size(), 1); + // } + // + // public void testGetRuleByIdNotFound() { + // IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + // SearchResponse searchResponse = mock(SearchResponse.class); + // when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); + // + // ActionListener listener = mock(ActionListener.class); + // rulePersistenceService.handleGetRuleResponse(_ID_ONE, searchResponse, listener); + // + // ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); + // verify(listener).onFailure(exceptionCaptor.capture()); + // Exception exception = exceptionCaptor.getValue(); + // assertTrue(exception instanceof ResourceNotFoundException); + // } + // + // public void testGetRuleWithAttributes() { + // IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + // ActionListener listener = mock(ActionListener.class); + // SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + // Client client = rulePersistenceService.getClient(); + // when(client.prepareSearch(TEST_INDEX_NAME)).thenReturn(searchRequestBuilder); + // when(searchRequestBuilder.setQuery(any(QueryBuilder.class))).thenReturn(searchRequestBuilder); + // when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); + // rulePersistenceService.getRuleFromIndex(null, ATTRIBUTE_MAP, null, listener); + // verify(client).prepareSearch(TEST_INDEX_NAME); + // verify(searchRequestBuilder).setQuery(any()); + // } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index c4e664f8ccdc2..c2474e77a0b3f 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -36,7 +36,9 @@ import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.rest.RestGetWorkloadGroupAction; import org.opensearch.plugin.wlm.rest.RestUpdateWorkloadGroupAction; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; import org.opensearch.plugin.wlm.rule.action.GetRuleAction; +import org.opensearch.plugin.wlm.rule.action.GetWlmRuleAction; import org.opensearch.plugin.wlm.rule.action.TransportGetRuleAction; import org.opensearch.plugin.wlm.rule.rest.RestGetRuleAction; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; @@ -46,6 +48,7 @@ import org.opensearch.repositories.RepositoriesService; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; +import org.opensearch.rule.rest.RestGetRuleAction; import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.script.ScriptService; import org.opensearch.threadpool.ThreadPool; @@ -56,6 +59,8 @@ import java.util.List; import java.util.function.Supplier; +import static org.opensearch.rest.RestRequest.Method.GET; + /** * Plugin class for WorkloadManagement */ @@ -122,7 +127,12 @@ public List getRestHandlers( new RestGetWorkloadGroupAction(), new RestDeleteWorkloadGroupAction(), new RestUpdateWorkloadGroupAction(), - new RestGetRuleAction() + new RestGetRuleAction( + "get_rule", + List.of(new RestHandler.Route(GET, "_wlm/rule/"), new RestHandler.Route(GET, "_wlm/rule/{_id}")), + QueryGroupFeatureType.INSTANCE, + GetWlmRuleAction.INSTANCE + ) ); } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java deleted file mode 100644 index bfe6dd570858f..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleAction.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.rest; - -import org.opensearch.action.ActionType; -import org.opensearch.autotagging.Attribute; -import org.opensearch.plugin.wlm.rule.QueryGroupAttribute; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.plugin.wlm.rule.action.GetWlmRuleAction; -import org.opensearch.rule.action.GetRuleRequest; -import org.opensearch.rule.action.GetRuleResponse; -import org.opensearch.rule.rest.RestGetRuleAction; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.opensearch.rest.RestRequest.Method.GET; - -/** - * Rest action to get workload management Rules - * @opensearch.experimental - */ -public class RestGetWlmRuleAction extends RestGetRuleAction { - - /** - * Constructor for RestGetWlmRuleAction - */ - public RestGetWlmRuleAction() { - super(); - } - - @Override - public String getName() { - return "get_rule"; - } - - @Override - public List routes() { - return List.of(new Route(GET, "_wlm/rule/"), new Route(GET, "_wlm/rule/{_id}")); - } - - @Override - protected Attribute getAttributeFromName(String name) { - return QueryGroupAttribute.fromName(name); - } - - @Override - @SuppressWarnings("unchecked") - protected > T retrieveGetRuleActionInstance() { - return (T) GetWlmRuleAction.INSTANCE; - } - - @Override - protected GetRuleRequest buildGetRuleRequest(String id, Map> attributeFilters, String searchAfter) { - return new GetRuleRequest(id, attributeFilters, searchAfter, QueryGroupFeatureType.INSTANCE); - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java deleted file mode 100644 index 1d82e4fea71e5..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/** - * Package for the rest classes related to rules in WorkloadManagementPlugin - */ -package org.opensearch.plugin.wlm.rule.rest; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleActionTests.java deleted file mode 100644 index a0f61cbaf3c8b..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestGetWlmRuleActionTests.java +++ /dev/null @@ -1,36 +0,0 @@ - -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.rest; - -import org.opensearch.rest.RestHandler; -import org.opensearch.test.OpenSearchTestCase; - -import java.util.List; - -import static org.opensearch.rest.RestRequest.Method.GET; - -public class RestGetWlmRuleActionTests extends OpenSearchTestCase { - /** - * Test case to validate the construction for RestGetRuleAction - */ - public void testConstruction() { - RestGetWlmRuleAction action = new RestGetWlmRuleAction(); - assertNotNull(action); - assertEquals("get_rule", action.getName()); - List routes = action.routes(); - assertEquals(2, routes.size()); - RestHandler.Route route = routes.get(0); - assertEquals(GET, route.getMethod()); - assertEquals("_wlm/rule/", route.getPath()); - route = routes.get(1); - assertEquals(GET, route.getMethod()); - assertEquals("_wlm/rule/{_id}", route.getPath()); - } -} diff --git a/server/src/main/java/org/opensearch/autotagging/RuleValidator.java b/server/src/main/java/org/opensearch/autotagging/RuleValidator.java index 9614761042081..fa38cad202c71 100644 --- a/server/src/main/java/org/opensearch/autotagging/RuleValidator.java +++ b/server/src/main/java/org/opensearch/autotagging/RuleValidator.java @@ -80,6 +80,10 @@ private boolean isNullOrEmpty(String str) { return str == null || str.isEmpty(); } + public static boolean isEmpty(String str) { + return str != null && str.isEmpty(); + } + private List validateFeatureType() { if (featureType == null) { return List.of("Couldn't identify which feature the rule belongs to. Rule feature can't be null."); From b4ec49be6b39ecb50e7415caa92aeb6fc5ec54aa Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Tue, 8 Apr 2025 17:27:05 -0700 Subject: [PATCH 12/28] refactor code and fix ut Signed-off-by: Kaushal Kumar --- .../org/opensearch/rule/RuleEntityParser.java | 27 +++ .../org/opensearch/rule/RuleQueryBuilder.java | 27 +++ .../IndexStoredRulePersistenceService.java | 77 +++---- .../IndexBasedRuleQueryBuilder.java} | 35 ++-- .../XContentRuleParser.java} | 34 ++-- .../opensearch/rule/utils/package-info.java | 12 -- .../IndexStoredRuleUtilsTests.java | 30 ++- ...ests.java => XContentRuleParserTests.java} | 19 +- ...ndexStoredRulePersistenceServiceTests.java | 192 ++++++++++++++---- .../opensearch/rule/utils/RuleTestUtils.java | 91 ++++++--- .../plugin/wlm/WorkloadManagementPlugin.java | 13 +- 11 files changed, 386 insertions(+), 171 deletions(-) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleEntityParser.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryBuilder.java rename libs/autotagging-commons/src/main/java/org/opensearch/rule/{utils/IndexStoredRuleUtils.java => storage/IndexBasedRuleQueryBuilder.java} (53%) rename libs/autotagging-commons/src/main/java/org/opensearch/rule/{utils/IndexStoredRuleParser.java => storage/XContentRuleParser.java} (59%) delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java rename libs/autotagging-commons/src/test/java/org/opensearch/rule/{utils => }/IndexStoredRuleUtilsTests.java (54%) rename libs/autotagging-commons/src/test/java/org/opensearch/rule/{utils/IndexStoredRuleParserTests.java => XContentRuleParserTests.java} (74%) diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleEntityParser.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleEntityParser.java new file mode 100644 index 0000000000000..8d352bd32eb61 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleEntityParser.java @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.autotagging.Rule; +import org.opensearch.common.annotation.ExperimentalApi; + +/** + * Interface to parse various string representation of Rule entity + * clients can use/implement as per their choice of storage for the Rule + */ +@ExperimentalApi +public interface RuleEntityParser { + /** + * Parses the src string into {@link Rule} object + * @param src String representation of Rule, it could be a XContentObject or something else based on + * where and how it is stored + * @return Rule + */ + Rule parse(String src); +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryBuilder.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryBuilder.java new file mode 100644 index 0000000000000..ff5f1435f61d7 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryBuilder.java @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.rule.action.GetRuleRequest; + +/** + * This interface is responsible for creating query objects which storage layer can use + * to query the backend + * @param + */ +@ExperimentalApi +public interface RuleQueryBuilder { + /** + * This method translates the {@link GetRuleRequest} to a storage engine specific query object + * @param request + * @return + */ + T buildQuery(GetRuleRequest request); +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index 7253098688b27..c885119e67b05 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -12,17 +12,16 @@ import org.apache.logging.log4j.Logger; import org.opensearch.ResourceNotFoundException; import org.opensearch.action.search.SearchRequestBuilder; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.FeatureType; import org.opensearch.autotagging.Rule; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; -import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.rule.RuleEntityParser; +import org.opensearch.rule.RuleQueryBuilder; import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; -import org.opensearch.rule.utils.IndexStoredRuleParser; -import org.opensearch.rule.utils.IndexStoredRuleUtils; import org.opensearch.search.SearchHit; import org.opensearch.search.sort.SortOrder; import org.opensearch.transport.client.Client; @@ -30,7 +29,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.stream.Collectors; import static org.opensearch.autotagging.Rule._ID_STRING; @@ -47,6 +45,8 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService private final Client client; private final FeatureType featureType; private final int maxRulesPerPage; + private final RuleEntityParser parser; + private final RuleQueryBuilder queryBuilder; private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); /** @@ -56,12 +56,23 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService * @param client - The OpenSearch client used to interact with the OpenSearch cluster. * @param featureType - The feature type associated with the stored rules. * @param maxRulesPerPage - The maximum number of rules that can be returned in a single get request. + * @param parser + * @param queryBuilder */ - public IndexStoredRulePersistenceService(String indexName, Client client, FeatureType featureType, int maxRulesPerPage) { + public IndexStoredRulePersistenceService( + String indexName, + Client client, + FeatureType featureType, + int maxRulesPerPage, + RuleEntityParser parser, + RuleQueryBuilder queryBuilder + ) { this.indexName = indexName; this.client = client; this.featureType = featureType; this.maxRulesPerPage = maxRulesPerPage; + this.parser = parser; + this.queryBuilder = queryBuilder; } /** @@ -70,53 +81,54 @@ public IndexStoredRulePersistenceService(String indexName, Client client, Featur * @param listener the listener for GetRuleResponse. */ public void getRule(GetRuleRequest getRuleRequest, ActionListener listener) { - getRuleFromIndex(getRuleRequest.getId(), getRuleRequest.getAttributeFilters(), getRuleRequest.getSearchAfter(), listener); + final QueryBuilder getQueryBuilder = queryBuilder.buildQuery(getRuleRequest) + .filter(QueryBuilders.existsQuery(featureType.getName())); + getRuleFromIndex(getRuleRequest.getId(), getQueryBuilder, getRuleRequest.getSearchAfter(), listener); } /** * Get rules from index. If id is provided, we only get a single rule. * Otherwise, we get all rules that satisfy the attributeFilters. - * @param id - The id of the rule to get. - * @param attributeFilters - A map containing the attributes that user want to filter on + * @param queryBuilder query object * @param searchAfter - The sort values from the last document of the previous page, used for pagination * @param listener - ActionListener for GetRuleResponse */ - private void getRuleFromIndex( - String id, - Map> attributeFilters, - String searchAfter, - ActionListener listener - ) { + private void getRuleFromIndex(String id, QueryBuilder queryBuilder, String searchAfter, ActionListener listener) { // Stash the current thread context when interacting with system index to perform // operations as the system itself, bypassing authorization checks. This ensures that // actions within this block are trusted and executed with system-level privileges. try (ThreadContext.StoredContext context = getContext()) { - BoolQueryBuilder boolQuery = IndexStoredRuleUtils.buildGetRuleQuery(id, attributeFilters, featureType); - SearchRequestBuilder searchRequest = client.prepareSearch(indexName).setQuery(boolQuery).setSize(maxRulesPerPage); + SearchRequestBuilder searchRequest = client.prepareSearch(indexName).setQuery(queryBuilder).setSize(maxRulesPerPage); if (searchAfter != null) { searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); } - searchRequest.execute(ActionListener.wrap(searchResponse -> handleGetRuleResponse(id, searchResponse, listener), e -> { + searchRequest.execute(ActionListener.wrap(searchResponse -> { + List hits = Arrays.asList(searchResponse.getHits().getHits()); + if (hasNoResults(id, listener, hits)) return; + handleGetRuleResponse(hits, listener); + }, e -> { logger.error("Failed to fetch all rules: {}", e.getMessage()); listener.onFailure(e); })); } } - /** - * Process searchResponse from index and send a GetRuleResponse - * @param searchResponse - Response received from index - * @param listener - ActionListener for GetRuleResponse - */ - private void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { - List hits = Arrays.asList(searchResponse.getHits().getHits()); + private static boolean hasNoResults(String id, ActionListener listener, List hits) { if (id != null && hits.isEmpty()) { logger.error("Rule with ID " + id + " not found."); listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " not found.")); - return; + return true; } - Map ruleMap = hits.stream() - .collect(Collectors.toMap(SearchHit::getId, hit -> IndexStoredRuleParser.parseRule(hit.getSourceAsString(), featureType))); + return false; + } + + /** + * Process searchResponse from index and send a GetRuleResponse + * @param hits - Response received from index + * @param listener - ActionListener for GetRuleResponse + */ + void handleGetRuleResponse(List hits, ActionListener listener) { + Map ruleMap = hits.stream().collect(Collectors.toMap(SearchHit::getId, hit -> parser.parse(hit.getSourceAsString()))); String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter)); } @@ -124,11 +136,4 @@ private void handleGetRuleResponse(String id, SearchResponse searchResponse, Act private ThreadContext.StoredContext getContext() { return client.threadPool().getThreadContext().stashContext(); } - - /** - * client getter - */ - public Client getClient() { - return client; - } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryBuilder.java similarity index 53% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryBuilder.java index 5b818a4feede8..a7e18b973391e 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryBuilder.java @@ -6,40 +6,38 @@ * compatible open source license. */ -package org.opensearch.rule.utils; +package org.opensearch.rule.storage; import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.QueryBuilder; import org.opensearch.index.query.QueryBuilders; +import org.opensearch.rule.RuleQueryBuilder; +import org.opensearch.rule.action.GetRuleRequest; import java.util.Map; import java.util.Set; -import jdk.jfr.Experimental; - import static org.opensearch.autotagging.Rule._ID_STRING; /** - * Utility class that provides methods for the lifecycle of rules. - * @opensearch.experimental + * This class is used to build opensearch index based query object */ -@Experimental -public class IndexStoredRuleUtils { +@ExperimentalApi +public class IndexBasedRuleQueryBuilder implements RuleQueryBuilder { /** - * constructor for IndexStoredRuleUtils + * Default constructor */ - public IndexStoredRuleUtils() {} + public IndexBasedRuleQueryBuilder() {} + + @Override + public QueryBuilder buildQuery(GetRuleRequest request) { + final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + final Map> attributeFilters = request.getAttributeFilters(); + final String id = request.getId(); - /** - * Builds a Boolean query to retrieve a rule by its ID or attribute filters. - * @param id The ID of the rule to search for. If null, no ID-based filtering is applied. - * @param attributeFilters A map of attributes and their corresponding filter values. This allows filtering by specific attribute values. - * @param featureType The feature type that is required in the query. - */ - public static BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters, FeatureType featureType) { - BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); if (id != null) { return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); } @@ -54,7 +52,6 @@ public static BoolQueryBuilder buildGetRuleQuery(String id, Map sut; + + public void setUp() throws Exception { + super.setUp(); + sut = new IndexBasedRuleQueryBuilder(); + } + public void testBuildGetRuleQuery_WithId() { - BoolQueryBuilder query = IndexStoredRuleUtils.buildGetRuleQuery( - _ID_ONE, - new HashMap<>(), - RuleTestUtils.MockRuleFeatureType.INSTANCE - ); + QueryBuilder query = sut.buildQuery(new GetRuleRequest(_ID_ONE, new HashMap<>(), null, RuleTestUtils.MockRuleFeatureType.INSTANCE)); assertNotNull(query); - assertEquals(1, query.must().size()); - QueryBuilder idQuery = query.must().get(0); + BoolQueryBuilder queryBuilder = (BoolQueryBuilder) query; + assertEquals(1, queryBuilder.must().size()); + QueryBuilder idQuery = queryBuilder.must().get(0); assertTrue(idQuery.toString().contains(_ID_ONE)); } public void testBuildGetRuleQuery_WithAttributes() { - BoolQueryBuilder query = IndexStoredRuleUtils.buildGetRuleQuery(null, ATTRIBUTE_MAP, RuleTestUtils.MockRuleFeatureType.INSTANCE); - assertNotNull(query); + QueryBuilder queryBuilder = sut.buildQuery( + new GetRuleRequest(null, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE) + ); + assertNotNull(queryBuilder); + BoolQueryBuilder query = (BoolQueryBuilder) queryBuilder; assertTrue(query.must().size() == 1); assertTrue(query.toString().contains(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE.getName())); assertTrue(query.toString().contains(ATTRIBUTE_VALUE_ONE)); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/XContentRuleParserTests.java similarity index 74% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java rename to libs/autotagging-commons/src/test/java/org/opensearch/rule/XContentRuleParserTests.java index 7cd37b783705a..99634366ee1ab 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/XContentRuleParserTests.java @@ -6,9 +6,11 @@ * compatible open source license. */ -package org.opensearch.rule.utils; +package org.opensearch.rule; import org.opensearch.autotagging.Rule; +import org.opensearch.rule.storage.XContentRuleParser; +import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; @@ -17,7 +19,7 @@ import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; -public class IndexStoredRuleParserTests extends OpenSearchTestCase { +public class XContentRuleParserTests extends OpenSearchTestCase { public static final String VALID_JSON = String.format(Locale.ROOT, """ { "description": "%s", @@ -34,19 +36,22 @@ public class IndexStoredRuleParserTests extends OpenSearchTestCase { "mock_attribute_three": ["attribute_value_one", "attribute_value_two"] } """; + RuleEntityParser sut; + + public void setUp() throws Exception { + super.setUp(); + sut = new XContentRuleParser(RuleTestUtils.MockRuleFeatureType.INSTANCE); + } public void testParseRule_Success() throws IOException { - Rule parsedRule = IndexStoredRuleParser.parseRule(VALID_JSON, RuleTestUtils.MockRuleFeatureType.INSTANCE); + Rule parsedRule = sut.parse(VALID_JSON); assertNotNull(parsedRule); assertEquals(DESCRIPTION_ONE, parsedRule.getDescription()); assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, parsedRule.getFeatureType()); } public void testParseRule_InvalidJson() { - Exception exception = assertThrows( - RuntimeException.class, - () -> IndexStoredRuleParser.parseRule(INVALID_JSON, RuleTestUtils.MockRuleFeatureType.INSTANCE) - ); + Exception exception = assertThrows(RuntimeException.class, () -> sut.parse(INVALID_JSON)); assertTrue(exception.getMessage().contains("mock_attribute_three is not a valid attribute within the mock_feature_type feature.")); } diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index 9f30896a1086b..fec1dd5fcf1b5 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -8,52 +8,156 @@ package org.opensearch.rule.service; +import org.apache.lucene.search.TotalHits; +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.search.SearchRequestBuilder; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.autotagging.Rule; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.metadata.Metadata; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.bytes.BytesArray; +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.RuleEntityParser; +import org.opensearch.rule.RuleQueryBuilder; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.search.SearchHit; +import org.opensearch.search.SearchHits; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.client.Client; + +import java.util.HashMap; + +import org.mockito.ArgumentCaptor; + +import static org.opensearch.rule.XContentRuleParserTests.VALID_JSON; +import static org.opensearch.rule.utils.RuleTestUtils.IndexStoredRulePersistenceBuilder; +import static org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; +import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { - // - // public void testGetRuleByIdSuccess() { - // IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - // SearchResponse searchResponse = mock(SearchResponse.class); - // SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); - // when(searchResponse.getHits()).thenReturn(searchHits); - // SearchHit hit = searchHits.getHits()[0]; - // hit.sourceRef(new BytesArray(VALID_JSON)); - // - // ActionListener listener = mock(ActionListener.class); - // rulePersistenceService.handleGetRuleResponse(_ID_ONE, searchResponse, listener); - // - // ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); - // verify(listener).onResponse(responseCaptor.capture()); - // GetRuleResponse response = responseCaptor.getValue(); - // assertEquals(response.getRules().size(), 1); - // } - // - // public void testGetRuleByIdNotFound() { - // IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - // SearchResponse searchResponse = mock(SearchResponse.class); - // when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); - // - // ActionListener listener = mock(ActionListener.class); - // rulePersistenceService.handleGetRuleResponse(_ID_ONE, searchResponse, listener); - // - // ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); - // verify(listener).onFailure(exceptionCaptor.capture()); - // Exception exception = exceptionCaptor.getValue(); - // assertTrue(exception instanceof ResourceNotFoundException); - // } - // - // public void testGetRuleWithAttributes() { - // IndexStoredRulePersistenceService rulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - // ActionListener listener = mock(ActionListener.class); - // SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - // Client client = rulePersistenceService.getClient(); - // when(client.prepareSearch(TEST_INDEX_NAME)).thenReturn(searchRequestBuilder); - // when(searchRequestBuilder.setQuery(any(QueryBuilder.class))).thenReturn(searchRequestBuilder); - // when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); - // rulePersistenceService.getRuleFromIndex(null, ATTRIBUTE_MAP, null, listener); - // verify(client).prepareSearch(TEST_INDEX_NAME); - // verify(searchRequestBuilder).setQuery(any()); - // } + + public static final int MAX_VALUES_PER_PAGE = 50; + + public void testGetRuleByIdSuccess() { + GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); + when(getRuleRequest.getId()).thenReturn(_ID_ONE); + when(getRuleRequest.getAttributeFilters()).thenReturn(new HashMap<>()); + QueryBuilder queryBuilder = mock(QueryBuilder.class); + RuleQueryBuilder mockRuleQueryBuilder = mock(RuleQueryBuilder.class); + RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); + Rule mockRule = mock(Rule.class); + + when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); + when(mockRuleQueryBuilder.buildQuery(getRuleRequest)).thenReturn(queryBuilder); + when(queryBuilder.filter(any())).thenReturn(queryBuilder); + + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + Client client = setUpMockClient(searchRequestBuilder); + + IndexStoredRulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceBuilder().indexName(TEST_INDEX_NAME) + .client(client) + .featureType(MockRuleFeatureType.INSTANCE) + .maxValuesPerPage(MAX_VALUES_PER_PAGE) + .parser(mockRuleEntityParser) + .queryBuilder(mockRuleQueryBuilder) + .build(); + + SearchResponse searchResponse = mock(SearchResponse.class); + SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + when(searchResponse.getHits()).thenReturn(searchHits); + SearchHit hit = searchHits.getHits()[0]; + hit.sourceRef(new BytesArray(VALID_JSON)); + + ActionListener listener = mock(ActionListener.class); + + doAnswer((invocation) -> { + ActionListener actionListener = invocation.getArgument(0); + actionListener.onResponse(searchResponse); + return null; + }).when(searchRequestBuilder).execute(any(ActionListener.class)); + + rulePersistenceService.getRule(getRuleRequest, listener); + + ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); + verify(listener).onResponse(responseCaptor.capture()); + GetRuleResponse response = responseCaptor.getValue(); + assertEquals(response.getRules().size(), 1); + } + + public void testGetRuleByIdNotFound() { + GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); + when(getRuleRequest.getId()).thenReturn(_ID_ONE); + QueryBuilder queryBuilder = mock(QueryBuilder.class); + RuleQueryBuilder mockRuleQueryBuilder = mock(RuleQueryBuilder.class); + RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); + Rule mockRule = mock(Rule.class); + + when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); + when(mockRuleQueryBuilder.buildQuery(getRuleRequest)).thenReturn(queryBuilder); + when(queryBuilder.filter(any())).thenReturn(queryBuilder); + + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + Client client = setUpMockClient(searchRequestBuilder); + + IndexStoredRulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceBuilder().indexName(TEST_INDEX_NAME) + .client(client) + .featureType(MockRuleFeatureType.INSTANCE) + .maxValuesPerPage(MAX_VALUES_PER_PAGE) + .parser(mockRuleEntityParser) + .queryBuilder(mockRuleQueryBuilder) + .build(); + + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); + + ActionListener listener = mock(ActionListener.class); + + doAnswer(invocationOnMock -> { + ActionListener actionListener = invocationOnMock.getArgument(0); + actionListener.onResponse(searchResponse); + return null; + }).when(searchRequestBuilder).execute(any(ActionListener.class)); + + rulePersistenceService.getRule(getRuleRequest, listener); + + ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); + verify(listener).onFailure(exceptionCaptor.capture()); + Exception exception = exceptionCaptor.getValue(); + assertTrue(exception instanceof ResourceNotFoundException); + } + + private Client setUpMockClient(SearchRequestBuilder searchRequestBuilder) { + Client client = mock(Client.class); + ClusterService clusterService = mock(ClusterService.class); + ClusterState clusterState = mock(ClusterState.class); + Metadata metadata = mock(Metadata.class); + ThreadPool threadPool = mock(ThreadPool.class); + + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + when(client.threadPool()).thenReturn(threadPool); + when(threadPool.getThreadContext()).thenReturn(threadContext); + when(clusterService.state()).thenReturn(clusterState); + when(clusterState.metadata()).thenReturn(metadata); + + when(client.prepareSearch(TEST_INDEX_NAME)).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setQuery(any(QueryBuilder.class))).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); + + return client; + } } diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index 689f86cd51cbb..5243d73a00587 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -12,14 +12,10 @@ import org.opensearch.autotagging.AutoTaggingRegistry; import org.opensearch.autotagging.FeatureType; import org.opensearch.autotagging.Rule; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.metadata.Metadata; -import org.opensearch.cluster.metadata.QueryGroup; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.RuleEntityParser; +import org.opensearch.rule.RuleQueryBuilder; import org.opensearch.rule.service.IndexStoredRulePersistenceService; -import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.client.Client; import java.util.Map; @@ -27,8 +23,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class RuleTestUtils { public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; @@ -68,21 +62,21 @@ public static Map ruleMap() { return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); } - public static IndexStoredRulePersistenceService setUpIndexStoredRulePersistenceService(Map queryGroupMap) { - Client client = mock(Client.class); - ClusterService clusterService = mock(ClusterService.class); - ClusterState clusterState = mock(ClusterState.class); - Metadata metadata = mock(Metadata.class); - ThreadPool threadPool = mock(ThreadPool.class); - - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - when(client.threadPool()).thenReturn(threadPool); - when(threadPool.getThreadContext()).thenReturn(threadContext); - when(clusterService.state()).thenReturn(clusterState); - when(clusterState.metadata()).thenReturn(metadata); - when(metadata.queryGroups()).thenReturn(queryGroupMap); - return new IndexStoredRulePersistenceService(TEST_INDEX_NAME, client, MockRuleFeatureType.INSTANCE, 50); - } + // public static IndexStoredRulePersistenceService setUpIndexStoredRulePersistenceService(Map queryGroupMap) { + // Client client = mock(Client.class); + // ClusterService clusterService = mock(ClusterService.class); + // ClusterState clusterState = mock(ClusterState.class); + // Metadata metadata = mock(Metadata.class); + // ThreadPool threadPool = mock(ThreadPool.class); + // + // ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + // when(client.threadPool()).thenReturn(threadPool); + // when(threadPool.getThreadContext()).thenReturn(threadContext); + // when(clusterService.state()).thenReturn(clusterState); + // when(clusterState.metadata()).thenReturn(metadata); + // when(metadata.queryGroups()).thenReturn(queryGroupMap); + // return new IndexStoredRulePersistenceService(TEST_INDEX_NAME, client, MockRuleFeatureType.INSTANCE, 50); + // } public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { assertEquals(mapOne.size(), mapTwo.size()); @@ -107,6 +101,55 @@ public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { } } + /** + * Used mainly for testing to avoid multiple methods to setup the mock + * this builder provides flexibility to inject use case specific mocks + */ + public static class IndexStoredRulePersistenceBuilder { + private String indexName; + private Client client; + private FeatureType featureType; + private int maxValuesPerPage; + private RuleQueryBuilder queryBuilder; + private RuleEntityParser parser; + + public IndexStoredRulePersistenceBuilder() {} + + public IndexStoredRulePersistenceBuilder indexName(String indexName) { + this.indexName = indexName; + return this; + } + + public IndexStoredRulePersistenceBuilder client(Client client) { + this.client = client; + return this; + } + + public IndexStoredRulePersistenceBuilder featureType(FeatureType featureType) { + this.featureType = featureType; + return this; + } + + public IndexStoredRulePersistenceBuilder maxValuesPerPage(int maxValuesPerPage) { + this.maxValuesPerPage = maxValuesPerPage; + return this; + } + + public IndexStoredRulePersistenceBuilder queryBuilder(RuleQueryBuilder queryBuilder) { + this.queryBuilder = queryBuilder; + return this; + } + + public IndexStoredRulePersistenceBuilder parser(RuleEntityParser parser) { + this.parser = parser; + return this; + } + + public IndexStoredRulePersistenceService build() { + return new IndexStoredRulePersistenceService(indexName, client, featureType, maxValuesPerPage, parser, queryBuilder); + } + } + public static class MockRuleFeatureType implements FeatureType { public static final MockRuleFeatureType INSTANCE = new MockRuleFeatureType(); diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index c2474e77a0b3f..c8720b2d11d5f 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -50,6 +50,8 @@ import org.opensearch.rest.RestHandler; import org.opensearch.rule.rest.RestGetRuleAction; import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.rule.storage.IndexBasedRuleQueryBuilder; +import org.opensearch.rule.storage.XContentRuleParser; import org.opensearch.script.ScriptService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.client.Client; @@ -93,7 +95,16 @@ public Collection createComponents( IndexNameExpressionResolver indexNameExpressionResolver, Supplier repositoriesServiceSupplier ) { - return List.of(new IndexStoredRulePersistenceService(INDEX_NAME, client, QueryGroupFeatureType.INSTANCE, MAX_RULES_PER_PAGE)); + return List.of( + new IndexStoredRulePersistenceService( + INDEX_NAME, + client, + QueryGroupFeatureType.INSTANCE, + MAX_RULES_PER_PAGE, + new XContentRuleParser(QueryGroupFeatureType.INSTANCE), + new IndexBasedRuleQueryBuilder() + ) + ); } @Override From a280686ab14763fcabdcc3e99de9aee66fd58fcd Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Tue, 8 Apr 2025 18:21:13 -0700 Subject: [PATCH 13/28] remove commented code Signed-off-by: Kaushal Kumar --- .../org/opensearch/rule/utils/RuleTestUtils.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index 5243d73a00587..aff02af837c8d 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -62,22 +62,6 @@ public static Map ruleMap() { return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); } - // public static IndexStoredRulePersistenceService setUpIndexStoredRulePersistenceService(Map queryGroupMap) { - // Client client = mock(Client.class); - // ClusterService clusterService = mock(ClusterService.class); - // ClusterState clusterState = mock(ClusterState.class); - // Metadata metadata = mock(Metadata.class); - // ThreadPool threadPool = mock(ThreadPool.class); - // - // ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - // when(client.threadPool()).thenReturn(threadPool); - // when(threadPool.getThreadContext()).thenReturn(threadContext); - // when(clusterService.state()).thenReturn(clusterState); - // when(clusterState.metadata()).thenReturn(metadata); - // when(metadata.queryGroups()).thenReturn(queryGroupMap); - // return new IndexStoredRulePersistenceService(TEST_INDEX_NAME, client, MockRuleFeatureType.INSTANCE, 50); - // } - public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { assertEquals(mapOne.size(), mapTwo.size()); for (Map.Entry entry : mapOne.entrySet()) { From 062c05c4421316bea6c8be2eaa9f5e6b97b40001 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Wed, 9 Apr 2025 17:49:59 -0700 Subject: [PATCH 14/28] address comments Signed-off-by: Kaushal Kumar --- ...{RuleQueryBuilder.java => RuleQueryMapper.java} | 4 ++-- .../service/IndexStoredRulePersistenceService.java | 8 ++++---- ...Builder.java => IndexBasedRuleQueryMapper.java} | 8 ++++---- .../opensearch/rule/IndexStoredRuleUtilsTests.java | 10 +++++----- .../IndexStoredRulePersistenceServiceTests.java | 14 +++++++------- .../org/opensearch/rule/utils/RuleTestUtils.java | 6 +++--- .../plugin/wlm/WorkloadManagementPlugin.java | 4 ++-- 7 files changed, 27 insertions(+), 27 deletions(-) rename libs/autotagging-commons/src/main/java/org/opensearch/rule/{RuleQueryBuilder.java => RuleQueryMapper.java} (88%) rename libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/{IndexBasedRuleQueryBuilder.java => IndexBasedRuleQueryMapper.java} (87%) diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryBuilder.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java similarity index 88% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryBuilder.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java index ff5f1435f61d7..9ff8380331b31 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryBuilder.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java @@ -17,11 +17,11 @@ * @param */ @ExperimentalApi -public interface RuleQueryBuilder { +public interface RuleQueryMapper { /** * This method translates the {@link GetRuleRequest} to a storage engine specific query object * @param request * @return */ - T buildQuery(GetRuleRequest request); + T getQuery(GetRuleRequest request); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index c885119e67b05..e534ff68d1c4a 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -19,7 +19,7 @@ import org.opensearch.index.query.QueryBuilder; import org.opensearch.index.query.QueryBuilders; import org.opensearch.rule.RuleEntityParser; -import org.opensearch.rule.RuleQueryBuilder; +import org.opensearch.rule.RuleQueryMapper; import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.search.SearchHit; @@ -46,7 +46,7 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService private final FeatureType featureType; private final int maxRulesPerPage; private final RuleEntityParser parser; - private final RuleQueryBuilder queryBuilder; + private final RuleQueryMapper queryBuilder; private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); /** @@ -65,7 +65,7 @@ public IndexStoredRulePersistenceService( FeatureType featureType, int maxRulesPerPage, RuleEntityParser parser, - RuleQueryBuilder queryBuilder + RuleQueryMapper queryBuilder ) { this.indexName = indexName; this.client = client; @@ -81,7 +81,7 @@ public IndexStoredRulePersistenceService( * @param listener the listener for GetRuleResponse. */ public void getRule(GetRuleRequest getRuleRequest, ActionListener listener) { - final QueryBuilder getQueryBuilder = queryBuilder.buildQuery(getRuleRequest) + final QueryBuilder getQueryBuilder = queryBuilder.getQuery(getRuleRequest) .filter(QueryBuilders.existsQuery(featureType.getName())); getRuleFromIndex(getRuleRequest.getId(), getQueryBuilder, getRuleRequest.getSearchAfter(), listener); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryBuilder.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java similarity index 87% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryBuilder.java rename to libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java index a7e18b973391e..98640b504dcf0 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryBuilder.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java @@ -13,7 +13,7 @@ import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilder; import org.opensearch.index.query.QueryBuilders; -import org.opensearch.rule.RuleQueryBuilder; +import org.opensearch.rule.RuleQueryMapper; import org.opensearch.rule.action.GetRuleRequest; import java.util.Map; @@ -25,15 +25,15 @@ * This class is used to build opensearch index based query object */ @ExperimentalApi -public class IndexBasedRuleQueryBuilder implements RuleQueryBuilder { +public class IndexBasedRuleQueryMapper implements RuleQueryMapper { /** * Default constructor */ - public IndexBasedRuleQueryBuilder() {} + public IndexBasedRuleQueryMapper() {} @Override - public QueryBuilder buildQuery(GetRuleRequest request) { + public QueryBuilder getQuery(GetRuleRequest request) { final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); final Map> attributeFilters = request.getAttributeFilters(); final String id = request.getId(); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java index a9e2752d443f1..37202d718d4d5 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java @@ -11,7 +11,7 @@ import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilder; import org.opensearch.rule.action.GetRuleRequest; -import org.opensearch.rule.storage.IndexBasedRuleQueryBuilder; +import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; @@ -22,15 +22,15 @@ import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; public class IndexStoredRuleUtilsTests extends OpenSearchTestCase { - RuleQueryBuilder sut; + RuleQueryMapper sut; public void setUp() throws Exception { super.setUp(); - sut = new IndexBasedRuleQueryBuilder(); + sut = new IndexBasedRuleQueryMapper(); } public void testBuildGetRuleQuery_WithId() { - QueryBuilder query = sut.buildQuery(new GetRuleRequest(_ID_ONE, new HashMap<>(), null, RuleTestUtils.MockRuleFeatureType.INSTANCE)); + QueryBuilder query = sut.getQuery(new GetRuleRequest(_ID_ONE, new HashMap<>(), null, RuleTestUtils.MockRuleFeatureType.INSTANCE)); assertNotNull(query); BoolQueryBuilder queryBuilder = (BoolQueryBuilder) query; assertEquals(1, queryBuilder.must().size()); @@ -39,7 +39,7 @@ public void testBuildGetRuleQuery_WithId() { } public void testBuildGetRuleQuery_WithAttributes() { - QueryBuilder queryBuilder = sut.buildQuery( + QueryBuilder queryBuilder = sut.getQuery( new GetRuleRequest(null, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE) ); assertNotNull(queryBuilder); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index fec1dd5fcf1b5..245a4eae2e4f2 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -22,7 +22,7 @@ import org.opensearch.core.common.bytes.BytesArray; import org.opensearch.index.query.QueryBuilder; import org.opensearch.rule.RuleEntityParser; -import org.opensearch.rule.RuleQueryBuilder; +import org.opensearch.rule.RuleQueryMapper; import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.search.SearchHit; @@ -58,12 +58,12 @@ public void testGetRuleByIdSuccess() { when(getRuleRequest.getId()).thenReturn(_ID_ONE); when(getRuleRequest.getAttributeFilters()).thenReturn(new HashMap<>()); QueryBuilder queryBuilder = mock(QueryBuilder.class); - RuleQueryBuilder mockRuleQueryBuilder = mock(RuleQueryBuilder.class); + RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); Rule mockRule = mock(Rule.class); when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); - when(mockRuleQueryBuilder.buildQuery(getRuleRequest)).thenReturn(queryBuilder); + when(mockRuleQueryMapper.getQuery(getRuleRequest)).thenReturn(queryBuilder); when(queryBuilder.filter(any())).thenReturn(queryBuilder); SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); @@ -74,7 +74,7 @@ public void testGetRuleByIdSuccess() { .featureType(MockRuleFeatureType.INSTANCE) .maxValuesPerPage(MAX_VALUES_PER_PAGE) .parser(mockRuleEntityParser) - .queryBuilder(mockRuleQueryBuilder) + .queryBuilder(mockRuleQueryMapper) .build(); SearchResponse searchResponse = mock(SearchResponse.class); @@ -103,12 +103,12 @@ public void testGetRuleByIdNotFound() { GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); when(getRuleRequest.getId()).thenReturn(_ID_ONE); QueryBuilder queryBuilder = mock(QueryBuilder.class); - RuleQueryBuilder mockRuleQueryBuilder = mock(RuleQueryBuilder.class); + RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); Rule mockRule = mock(Rule.class); when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); - when(mockRuleQueryBuilder.buildQuery(getRuleRequest)).thenReturn(queryBuilder); + when(mockRuleQueryMapper.getQuery(getRuleRequest)).thenReturn(queryBuilder); when(queryBuilder.filter(any())).thenReturn(queryBuilder); SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); @@ -119,7 +119,7 @@ public void testGetRuleByIdNotFound() { .featureType(MockRuleFeatureType.INSTANCE) .maxValuesPerPage(MAX_VALUES_PER_PAGE) .parser(mockRuleEntityParser) - .queryBuilder(mockRuleQueryBuilder) + .queryBuilder(mockRuleQueryMapper) .build(); SearchResponse searchResponse = mock(SearchResponse.class); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index aff02af837c8d..8d6196526092d 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -14,7 +14,7 @@ import org.opensearch.autotagging.Rule; import org.opensearch.index.query.QueryBuilder; import org.opensearch.rule.RuleEntityParser; -import org.opensearch.rule.RuleQueryBuilder; +import org.opensearch.rule.RuleQueryMapper; import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.transport.client.Client; @@ -94,7 +94,7 @@ public static class IndexStoredRulePersistenceBuilder { private Client client; private FeatureType featureType; private int maxValuesPerPage; - private RuleQueryBuilder queryBuilder; + private RuleQueryMapper queryBuilder; private RuleEntityParser parser; public IndexStoredRulePersistenceBuilder() {} @@ -119,7 +119,7 @@ public IndexStoredRulePersistenceBuilder maxValuesPerPage(int maxValuesPerPage) return this; } - public IndexStoredRulePersistenceBuilder queryBuilder(RuleQueryBuilder queryBuilder) { + public IndexStoredRulePersistenceBuilder queryBuilder(RuleQueryMapper queryBuilder) { this.queryBuilder = queryBuilder; return this; } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index c8720b2d11d5f..66c8e6e9b3fa4 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -50,7 +50,7 @@ import org.opensearch.rest.RestHandler; import org.opensearch.rule.rest.RestGetRuleAction; import org.opensearch.rule.service.IndexStoredRulePersistenceService; -import org.opensearch.rule.storage.IndexBasedRuleQueryBuilder; +import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.storage.XContentRuleParser; import org.opensearch.script.ScriptService; import org.opensearch.threadpool.ThreadPool; @@ -102,7 +102,7 @@ public Collection createComponents( QueryGroupFeatureType.INSTANCE, MAX_RULES_PER_PAGE, new XContentRuleParser(QueryGroupFeatureType.INSTANCE), - new IndexBasedRuleQueryBuilder() + new IndexBasedRuleQueryMapper() ) ); } From 55b8da10c4a9d172893f35f4ed8a2e30c6051551 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Wed, 9 Apr 2025 19:40:37 -0700 Subject: [PATCH 15/28] change method name Signed-off-by: Kaushal Kumar --- .../org/opensearch/rule/RuleQueryMapper.java | 2 +- .../IndexStoredRulePersistenceService.java | 3 +- .../storage/IndexBasedRuleQueryMapper.java | 2 +- .../rule/IndexStoredRuleUtilsTests.java | 6 +-- ...ndexStoredRulePersistenceServiceTests.java | 35 ++++++------ .../opensearch/rule/utils/RuleTestUtils.java | 54 ------------------- 6 files changed, 23 insertions(+), 79 deletions(-) diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java index 9ff8380331b31..f0ee052790b4b 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java @@ -23,5 +23,5 @@ public interface RuleQueryMapper { * @param request * @return */ - T getQuery(GetRuleRequest request); + T from(GetRuleRequest request); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index e534ff68d1c4a..0c102995c652a 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -81,8 +81,7 @@ public IndexStoredRulePersistenceService( * @param listener the listener for GetRuleResponse. */ public void getRule(GetRuleRequest getRuleRequest, ActionListener listener) { - final QueryBuilder getQueryBuilder = queryBuilder.getQuery(getRuleRequest) - .filter(QueryBuilders.existsQuery(featureType.getName())); + final QueryBuilder getQueryBuilder = queryBuilder.from(getRuleRequest).filter(QueryBuilders.existsQuery(featureType.getName())); getRuleFromIndex(getRuleRequest.getId(), getQueryBuilder, getRuleRequest.getSearchAfter(), listener); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java index 98640b504dcf0..4f79974cddb89 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java @@ -33,7 +33,7 @@ public class IndexBasedRuleQueryMapper implements RuleQueryMapper public IndexBasedRuleQueryMapper() {} @Override - public QueryBuilder getQuery(GetRuleRequest request) { + public QueryBuilder from(GetRuleRequest request) { final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); final Map> attributeFilters = request.getAttributeFilters(); final String id = request.getId(); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java index 37202d718d4d5..0542cd722095f 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java @@ -30,7 +30,7 @@ public void setUp() throws Exception { } public void testBuildGetRuleQuery_WithId() { - QueryBuilder query = sut.getQuery(new GetRuleRequest(_ID_ONE, new HashMap<>(), null, RuleTestUtils.MockRuleFeatureType.INSTANCE)); + QueryBuilder query = sut.from(new GetRuleRequest(_ID_ONE, new HashMap<>(), null, RuleTestUtils.MockRuleFeatureType.INSTANCE)); assertNotNull(query); BoolQueryBuilder queryBuilder = (BoolQueryBuilder) query; assertEquals(1, queryBuilder.must().size()); @@ -39,9 +39,7 @@ public void testBuildGetRuleQuery_WithId() { } public void testBuildGetRuleQuery_WithAttributes() { - QueryBuilder queryBuilder = sut.getQuery( - new GetRuleRequest(null, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE) - ); + QueryBuilder queryBuilder = sut.from(new GetRuleRequest(null, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE)); assertNotNull(queryBuilder); BoolQueryBuilder query = (BoolQueryBuilder) queryBuilder; assertTrue(query.must().size() == 1); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index 245a4eae2e4f2..53444c20b6bb3 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -36,7 +36,6 @@ import org.mockito.ArgumentCaptor; import static org.opensearch.rule.XContentRuleParserTests.VALID_JSON; -import static org.opensearch.rule.utils.RuleTestUtils.IndexStoredRulePersistenceBuilder; import static org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; @@ -63,19 +62,20 @@ public void testGetRuleByIdSuccess() { Rule mockRule = mock(Rule.class); when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); - when(mockRuleQueryMapper.getQuery(getRuleRequest)).thenReturn(queryBuilder); + when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); when(queryBuilder.filter(any())).thenReturn(queryBuilder); SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); Client client = setUpMockClient(searchRequestBuilder); - IndexStoredRulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceBuilder().indexName(TEST_INDEX_NAME) - .client(client) - .featureType(MockRuleFeatureType.INSTANCE) - .maxValuesPerPage(MAX_VALUES_PER_PAGE) - .parser(mockRuleEntityParser) - .queryBuilder(mockRuleQueryMapper) - .build(); + RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( + TEST_INDEX_NAME, + client, + MockRuleFeatureType.INSTANCE, + MAX_VALUES_PER_PAGE, + mockRuleEntityParser, + mockRuleQueryMapper + ); SearchResponse searchResponse = mock(SearchResponse.class); SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); @@ -108,19 +108,20 @@ public void testGetRuleByIdNotFound() { Rule mockRule = mock(Rule.class); when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); - when(mockRuleQueryMapper.getQuery(getRuleRequest)).thenReturn(queryBuilder); + when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); when(queryBuilder.filter(any())).thenReturn(queryBuilder); SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); Client client = setUpMockClient(searchRequestBuilder); - IndexStoredRulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceBuilder().indexName(TEST_INDEX_NAME) - .client(client) - .featureType(MockRuleFeatureType.INSTANCE) - .maxValuesPerPage(MAX_VALUES_PER_PAGE) - .parser(mockRuleEntityParser) - .queryBuilder(mockRuleQueryMapper) - .build(); + RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( + TEST_INDEX_NAME, + client, + MockRuleFeatureType.INSTANCE, + MAX_VALUES_PER_PAGE, + mockRuleEntityParser, + mockRuleQueryMapper + ); SearchResponse searchResponse = mock(SearchResponse.class); when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index 8d6196526092d..f6210e2d70899 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -12,11 +12,6 @@ import org.opensearch.autotagging.AutoTaggingRegistry; import org.opensearch.autotagging.FeatureType; import org.opensearch.autotagging.Rule; -import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.RuleEntityParser; -import org.opensearch.rule.RuleQueryMapper; -import org.opensearch.rule.service.IndexStoredRulePersistenceService; -import org.opensearch.transport.client.Client; import java.util.Map; import java.util.Set; @@ -85,55 +80,6 @@ public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { } } - /** - * Used mainly for testing to avoid multiple methods to setup the mock - * this builder provides flexibility to inject use case specific mocks - */ - public static class IndexStoredRulePersistenceBuilder { - private String indexName; - private Client client; - private FeatureType featureType; - private int maxValuesPerPage; - private RuleQueryMapper queryBuilder; - private RuleEntityParser parser; - - public IndexStoredRulePersistenceBuilder() {} - - public IndexStoredRulePersistenceBuilder indexName(String indexName) { - this.indexName = indexName; - return this; - } - - public IndexStoredRulePersistenceBuilder client(Client client) { - this.client = client; - return this; - } - - public IndexStoredRulePersistenceBuilder featureType(FeatureType featureType) { - this.featureType = featureType; - return this; - } - - public IndexStoredRulePersistenceBuilder maxValuesPerPage(int maxValuesPerPage) { - this.maxValuesPerPage = maxValuesPerPage; - return this; - } - - public IndexStoredRulePersistenceBuilder queryBuilder(RuleQueryMapper queryBuilder) { - this.queryBuilder = queryBuilder; - return this; - } - - public IndexStoredRulePersistenceBuilder parser(RuleEntityParser parser) { - this.parser = parser; - return this; - } - - public IndexStoredRulePersistenceService build() { - return new IndexStoredRulePersistenceService(indexName, client, featureType, maxValuesPerPage, parser, queryBuilder); - } - } - public static class MockRuleFeatureType implements FeatureType { public static final MockRuleFeatureType INSTANCE = new MockRuleFeatureType(); From 98f54aa8ad5edb53869cf509eea4044037133cda Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Mon, 14 Apr 2025 10:17:15 -0700 Subject: [PATCH 16/28] fix merge conflicts Signed-off-by: Kaushal Kumar --- .../plugin/wlm/WorkloadManagementPlugin.java | 1 - .../action/CreateWorkloadGroupAction.java | 2 +- .../action/CreateWorkloadGroupRequest.java | 2 +- .../action/CreateWorkloadGroupResponse.java | 2 +- .../action/DeleteWorkloadGroupAction.java | 2 +- .../action/DeleteWorkloadGroupRequest.java | 2 +- .../action/GetWorkloadGroupAction.java | 2 +- .../action/GetWorkloadGroupRequest.java | 2 +- .../action/GetWorkloadGroupResponse.java | 2 +- .../action/TransportCreateWorkloadGroupAction.java | 6 +----- .../action/TransportDeleteWorkloadGroupAction.java | 6 +----- .../action/TransportGetWorkloadGroupAction.java | 6 +----- .../action/TransportUpdateWorkloadGroupAction.java | 6 +----- .../action/UpdateWorkloadGroupAction.java | 2 +- .../action/UpdateWorkloadGroupRequest.java | 0 .../action/UpdateWorkloadGroupResponse.java | 2 +- .../wlm/{querygroup => }/action/package-info.java | 2 +- .../rest/RestCreateWorkloadGroupAction.java | 8 +------- .../rest/RestDeleteWorkloadGroupAction.java | 2 +- .../rest/RestGetWorkloadGroupAction.java | 8 +------- .../rest/RestUpdateWorkloadGroupAction.java | 8 +------- .../plugin/wlm/{querygroup => }/rest/package-info.java | 2 +- .../wlm/service/WorkloadGroupPersistenceService.java | 10 +--------- .../wlm/{querygroup => }/service/package-info.java | 2 +- .../opensearch/plugin/wlm/WorkloadGroupTestUtils.java | 2 +- .../action/CreateWorkloadGroupRequestTests.java | 2 +- .../action/CreateWorkloadGroupResponseTests.java | 2 +- .../action/DeleteWorkloadGroupRequestTests.java | 2 +- .../action/GetWorkloadGroupRequestTests.java | 2 +- .../action/GetWorkloadGroupResponseTests.java | 2 +- .../TransportDeleteWorkloadGroupActionTests.java | 6 +----- .../action/TransportGetWorkloadGroupActionTests.java | 2 +- .../action/UpdateWorkloadGroupRequestTests.java | 2 +- .../action/UpdateWorkloadGroupResponseTests.java | 2 +- .../action/WorkloadGroupActionTestUtils.java | 0 .../rest/RestDeleteWorkloadGroupActionTests.java | 7 +------ .../service/WorkloadGroupPersistenceServiceTests.java | 0 37 files changed, 33 insertions(+), 85 deletions(-) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/CreateWorkloadGroupAction.java (94%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/CreateWorkloadGroupRequest.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/CreateWorkloadGroupResponse.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/DeleteWorkloadGroupAction.java (94%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/DeleteWorkloadGroupRequest.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/GetWorkloadGroupAction.java (94%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/GetWorkloadGroupRequest.java (96%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/GetWorkloadGroupResponse.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/TransportCreateWorkloadGroupAction.java (87%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/TransportDeleteWorkloadGroupAction.java (88%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/TransportGetWorkloadGroupAction.java (89%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/TransportUpdateWorkloadGroupAction.java (87%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/UpdateWorkloadGroupAction.java (94%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/UpdateWorkloadGroupRequest.java (100%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/UpdateWorkloadGroupResponse.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/action/package-info.java (84%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/rest/RestCreateWorkloadGroupAction.java (82%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/rest/RestDeleteWorkloadGroupAction.java (97%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/rest/RestGetWorkloadGroupAction.java (80%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/rest/RestUpdateWorkloadGroupAction.java (82%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/rest/package-info.java (85%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/{querygroup => }/service/package-info.java (84%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/CreateWorkloadGroupRequestTests.java (96%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/CreateWorkloadGroupResponseTests.java (98%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/DeleteWorkloadGroupRequestTests.java (96%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/GetWorkloadGroupRequestTests.java (97%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/GetWorkloadGroupResponseTests.java (99%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/TransportDeleteWorkloadGroupActionTests.java (84%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/TransportGetWorkloadGroupActionTests.java (97%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/UpdateWorkloadGroupRequestTests.java (98%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/UpdateWorkloadGroupResponseTests.java (98%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/action/WorkloadGroupActionTestUtils.java (100%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/rest/RestDeleteWorkloadGroupActionTests.java (88%) rename plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/{querygroup => }/service/WorkloadGroupPersistenceServiceTests.java (100%) diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index 66c8e6e9b3fa4..efde7962b050a 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -48,7 +48,6 @@ import org.opensearch.repositories.RepositoriesService; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; -import org.opensearch.rule.rest.RestGetRuleAction; import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.storage.XContentRuleParser; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupAction.java index 433305f7e9bf6..ca9784ebc7e4b 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.ActionType; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequest.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequest.java index b31cc6f0fb1d2..ad932667b25e8 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponse.java index d765b3ed14b65..b33214e042398 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.core.action.ActionResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupAction.java index 54755758a15a3..39b47d69776f4 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.ActionType; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequest.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequest.java index 73a6cc0e1dcd7..940a3815b1662 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.action.support.clustermanager.AcknowledgedRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupAction.java index 28f35ba2f18b4..ee1b40a2f9bbc 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.ActionType; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequest.java similarity index 96% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequest.java index 28ab53849824e..4b8a5f85fd236 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.action.support.clustermanager.ClusterManagerNodeReadRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponse.java index 22b66bca9ae56..ab8f773088a37 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.core.action.ActionResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java similarity index 87% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java index ae401af9769ee..2039f1cb590ff 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; @@ -17,11 +17,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java similarity index 88% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java index 40c82b9c0a56f..2bfbadba4d51d 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; @@ -19,11 +19,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java similarity index 89% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java index ce64e737337cd..bb2fbab047343 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -23,11 +23,7 @@ import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.rest.RestStatus; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.java import org.opensearch.search.pipeline.SearchPipelineService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java similarity index 87% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java index b29896c0a0b1f..ef639d44b4155 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; @@ -17,11 +17,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupAction.java index 6e49008ff2fae..b4f8e1ce90126 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.ActionType; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequest.java similarity index 100% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequest.java diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponse.java index 2f9d543d5b1f9..9b8fccbdb5346 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.core.action.ActionResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/package-info.java similarity index 84% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/package-info.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/package-info.java index 472b41716b44d..df30f55a99b3c 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/package-info.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/package-info.java @@ -9,4 +9,4 @@ /** * Package for the action classes related to query groups in WorkloadManagementPlugin */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java similarity index 82% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java index 94d4d82cfbb8e..5ef59602f7893 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java @@ -6,20 +6,14 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.rest; +package org.opensearch.plugin.wlm.rest; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java index e3b5b8c30ea3b..d0d82f43679fa 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.rest; +package org.opensearch.plugin.wlm.rest; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java similarity index 80% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java index 50dd7e0ea50db..818531352f4d3 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java @@ -6,19 +6,13 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.rest; +package org.opensearch.plugin.wlm.rest; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.GetWorkloadGroupAction; import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupResponse; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java similarity index 82% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java index 1294529d857cb..db77dc5963037 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java @@ -6,20 +6,14 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.rest; +package org.opensearch.plugin.wlm.rest; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/package-info.java similarity index 85% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/package-info.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/package-info.java index a51d67a6cb3b7..889f3e107db07 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/package-info.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/package-info.java @@ -9,4 +9,4 @@ /** * Package for the rest classes related to query groups in WorkloadManagementPlugin */ -package org.opensearch.plugin.wlm.querygroup.rest; +package org.opensearch.plugin.wlm.rest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java index acd9fa93b3143..35a7dc7f3219f 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.service; +package org.opensearch.plugin.wlm.service; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -27,19 +27,11 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.action.ActionListener; import org.opensearch.core.rest.RestStatus; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; import org.opensearch.wlm.MutableWorkloadGroupFragment; -======== -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; -import org.opensearch.wlm.MutableQueryGroupFragment; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.java import org.opensearch.wlm.ResourceType; import java.util.Collection; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/package-info.java similarity index 84% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/package-info.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/package-info.java index 3758c9fcd9b81..e8c88ee656dc7 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/package-info.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/package-info.java @@ -9,4 +9,4 @@ /** * Package for the service classes related to query groups in WorkloadManagementPlugin */ -package org.opensearch.plugin.wlm.querygroup.service; +package org.opensearch.plugin.wlm.service; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java index dac26c3c0f929..bac644a172c1e 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup; +package org.opensearch.plugin.wlm; import org.opensearch.cluster.ClusterName; import org.opensearch.cluster.ClusterState; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java similarity index 96% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java index 272f4db09109e..31d3ea00b7bda 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java index 033e1a67cc012..d25050341f997 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java similarity index 96% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java index 2df70252f9f55..a7fa0939583c5 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.ActionRequestValidationException; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java similarity index 97% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java index 52e1880cf9a4a..832761d5084bb 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java similarity index 99% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java index f9d77de883e73..dc0aeabc7a033 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java similarity index 84% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java index 00aa957371e74..7ffa33aa8a80a 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; @@ -14,11 +14,7 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.action.ActionListener; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.java import org.opensearch.test.OpenSearchTestCase; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java similarity index 97% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java index b3aa0dceee78e..cf12d9f6408cf 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.ResourceNotFoundException; import org.opensearch.action.support.ActionFilters; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java index c982d5837d8eb..e8d883da5c6eb 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java index ff27c74becc5b..97b9b9029373f 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/WorkloadGroupActionTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/WorkloadGroupActionTestUtils.java similarity index 100% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/WorkloadGroupActionTestUtils.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/WorkloadGroupActionTestUtils.java diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java similarity index 88% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java index 4269c6d64ab97..8ce5c869f4481 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java @@ -6,18 +6,13 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.rest; +package org.opensearch.plugin.wlm.rest; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; import org.opensearch.common.CheckedConsumer; import org.opensearch.common.unit.TimeValue; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -======== -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; ->>>>>>>> eaf11b7f929 (add get rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestHandler; import org.opensearch.rest.RestRequest; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/service/WorkloadGroupPersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceServiceTests.java similarity index 100% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/service/WorkloadGroupPersistenceServiceTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceServiceTests.java From 05a8747db7a1a71cff8fe45637c235d2a3b256f2 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Wed, 16 Apr 2025 11:18:01 -0700 Subject: [PATCH 17/28] rename queryGroup to workloadGroup Signed-off-by: Kaushal Kumar --- .../org/opensearch/rule/RuleAttribute.java | 47 ++++++++++++++ .../plugin/wlm/WorkloadManagementPlugin.java | 15 +++-- .../plugin/wlm/rule/QueryGroupAttribute.java | 61 ------------------- ...ype.java => WorkloadGroupFeatureType.java} | 18 +++--- .../attribute_extractor/IndicesExtractor.java | 4 +- 5 files changed, 67 insertions(+), 78 deletions(-) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleAttribute.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/{QueryGroupFeatureType.java => WorkloadGroupFeatureType.java} (72%) diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleAttribute.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleAttribute.java new file mode 100644 index 0000000000000..9603751d7e37c --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleAttribute.java @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.autotagging.Attribute; + +/** + * Generic Rule attributes that features can use out of the use by using the lib. + * @opensearch.experimental + */ +public enum RuleAttribute implements Attribute { + /** + * Represents the index_pattern attribute in RuleAttribute + */ + INDEX_PATTERN("index_pattern"); + + private final String name; + + RuleAttribute(String name) { + this.name = name; + validateAttribute(); + } + + @Override + public String getName() { + return name; + } + + /** + * Retrieves the RuleAttribute from a name string + * @param name - attribute name + */ + public static RuleAttribute fromName(String name) { + for (RuleAttribute attr : RuleAttribute.values()) { + if (attr.getName().equals(name)) { + return attr; + } + } + throw new IllegalArgumentException("Unknown RuleAttribute: " + name); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index efde7962b050a..bce8f9d19d6a5 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -36,11 +36,9 @@ import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.rest.RestGetWorkloadGroupAction; import org.opensearch.plugin.wlm.rest.RestUpdateWorkloadGroupAction; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.plugin.wlm.rule.action.GetRuleAction; +import org.opensearch.plugin.wlm.rule.WorkloadGroupFeatureType; import org.opensearch.plugin.wlm.rule.action.GetWlmRuleAction; -import org.opensearch.plugin.wlm.rule.action.TransportGetRuleAction; -import org.opensearch.plugin.wlm.rule.rest.RestGetRuleAction; +import org.opensearch.plugin.wlm.rule.action.TransportGetWlmRuleAction; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; import org.opensearch.plugins.ActionPlugin; import org.opensearch.plugins.Plugin; @@ -48,6 +46,7 @@ import org.opensearch.repositories.RepositoriesService; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; +import org.opensearch.rule.rest.RestGetRuleAction; import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.storage.XContentRuleParser; @@ -98,9 +97,9 @@ public Collection createComponents( new IndexStoredRulePersistenceService( INDEX_NAME, client, - QueryGroupFeatureType.INSTANCE, + WorkloadGroupFeatureType.INSTANCE, MAX_RULES_PER_PAGE, - new XContentRuleParser(QueryGroupFeatureType.INSTANCE), + new XContentRuleParser(WorkloadGroupFeatureType.INSTANCE), new IndexBasedRuleQueryMapper() ) ); @@ -113,7 +112,7 @@ public Collection createComponents( new ActionPlugin.ActionHandler<>(GetWorkloadGroupAction.INSTANCE, TransportGetWorkloadGroupAction.class), new ActionPlugin.ActionHandler<>(DeleteWorkloadGroupAction.INSTANCE, TransportDeleteWorkloadGroupAction.class), new ActionPlugin.ActionHandler<>(UpdateWorkloadGroupAction.INSTANCE, TransportUpdateWorkloadGroupAction.class), - new ActionPlugin.ActionHandler<>(GetRuleAction.INSTANCE, TransportGetRuleAction.class) + new ActionPlugin.ActionHandler<>(GetWlmRuleAction.INSTANCE, TransportGetWlmRuleAction.class) ); } @@ -140,7 +139,7 @@ public List getRestHandlers( new RestGetRuleAction( "get_rule", List.of(new RestHandler.Route(GET, "_wlm/rule/"), new RestHandler.Route(GET, "_wlm/rule/{_id}")), - QueryGroupFeatureType.INSTANCE, + WorkloadGroupFeatureType.INSTANCE, GetWlmRuleAction.INSTANCE ) ); diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java deleted file mode 100644 index 5357a344da407..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule; - -import org.opensearch.autotagging.Attribute; - -import java.util.HashMap; -import java.util.Map; - -/** - * Attributes specific to the query group feature. - * @opensearch.experimental - */ -public enum QueryGroupAttribute implements Attribute { - /** - * Represents the index_pattern attribute in QueryGroupAttribute - */ - INDEX_PATTERN("index_pattern"); - - private final String name; - - QueryGroupAttribute(String name) { - this.name = name; - validateAttribute(); - } - - @Override - public String getName() { - return name; - } - - /** - * Retrieves the QueryGroupAttribute from a name string - * @param name - attribute name - */ - public static QueryGroupAttribute fromName(String name) { - for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { - if (attr.getName().equals(name)) { - return attr; - } - } - throw new IllegalArgumentException("Unknown QueryGroupAttribute: " + name); - } - - /** - * Converts the QueryGroupAttribute values into a map with attribute names as keys. - */ - public static Map toMap() { - Map map = new HashMap<>(); - for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { - map.put(attr.getName(), attr); - } - return map; - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java similarity index 72% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java index 42f45d3d7c5d6..9b20d59178939 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java @@ -11,27 +11,31 @@ import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.AutoTaggingRegistry; import org.opensearch.autotagging.FeatureType; +import org.opensearch.rule.RuleAttribute; import java.util.Map; /** - * Represents a feature type specific to the query group feature + * Represents a feature type specific to the workload group feature * @opensearch.experimental */ -public class QueryGroupFeatureType implements FeatureType { +public class WorkloadGroupFeatureType implements FeatureType { /** * The instance for QueryGroupFeatureType */ - public static final QueryGroupFeatureType INSTANCE = new QueryGroupFeatureType(); + public static final WorkloadGroupFeatureType INSTANCE = new WorkloadGroupFeatureType(); /** - * Name for QueryGroupFeatureType + * Name for WorkloadGroupFeatureType */ - public static final String NAME = "query_group"; + public static final String NAME = "workload_group"; private static final int MAX_ATTRIBUTE_VALUES = 10; private static final int MAX_ATTRIBUTE_VALUE_LENGTH = 100; - private static final Map ALLOWED_ATTRIBUTES = QueryGroupAttribute.toMap(); + private static final Map ALLOWED_ATTRIBUTES = Map.of( + RuleAttribute.INDEX_PATTERN.getName(), + RuleAttribute.INDEX_PATTERN + ); - private QueryGroupFeatureType() {} + private WorkloadGroupFeatureType() {} static { INSTANCE.registerFeatureType(); diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/attribute_extractor/IndicesExtractor.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/attribute_extractor/IndicesExtractor.java index a3230ac919eb1..828d59820d841 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/attribute_extractor/IndicesExtractor.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/attribute_extractor/IndicesExtractor.java @@ -10,6 +10,7 @@ import org.opensearch.action.IndicesRequest; import org.opensearch.autotagging.Attribute; +import org.opensearch.rule.RuleAttribute; import org.opensearch.rule.attribute_extractor.AttributeExtractor; import java.util.List; @@ -30,8 +31,7 @@ public IndicesExtractor(IndicesRequest indicesRequest) { @Override public Attribute getAttribute() { - // TODO: this will be replaced by WLM defined index_pattern attribute - return null; + return RuleAttribute.INDEX_PATTERN; } @Override From 3ed6f9452d3783ec85af6477aeb3f60ac333f0d2 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Wed, 16 Apr 2025 14:20:23 -0700 Subject: [PATCH 18/28] add guice binding related changes Signed-off-by: Kaushal Kumar --- .../plugin/wlm/WorkloadManagementPluginModule.java | 5 +++++ .../plugin/wlm/rule/action/TransportGetWlmRuleAction.java | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java index bb0f4c7e90122..18a3d604dca9a 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java @@ -10,7 +10,11 @@ import org.opensearch.common.inject.AbstractModule; import org.opensearch.common.inject.Singleton; +import org.opensearch.common.inject.name.Names; +import org.opensearch.plugin.wlm.rule.WorkloadGroupFeatureType; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.rule.service.RulePersistenceService; /** * Guice Module to manage WorkloadManagement related objects @@ -27,5 +31,6 @@ protected void configure() { // Bind WorkloadGroupPersistenceService as a singleton to ensure a single instance is used, // preventing multiple throttling key registrations in the constructor. bind(WorkloadGroupPersistenceService.class).in(Singleton.class); + bind(RulePersistenceService.class).annotatedWith(Names.named(WorkloadGroupFeatureType.NAME)).to(IndexStoredRulePersistenceService.class); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java index 0f8f3c3f4628c..a074e4a0b570c 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java @@ -11,7 +11,9 @@ import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.HandledTransportAction; import org.opensearch.common.inject.Inject; +import org.opensearch.common.inject.name.Named; import org.opensearch.core.action.ActionListener; +import org.opensearch.plugin.wlm.rule.WorkloadGroupFeatureType; import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.rule.service.RulePersistenceService; @@ -36,7 +38,7 @@ public class TransportGetWlmRuleAction extends HandledTransportAction Date: Fri, 18 Apr 2025 23:00:30 -0700 Subject: [PATCH 19/28] refactor code to create a generic rule framework structure Signed-off-by: Kaushal Kumar --- .../rule/action/GetRuleRequestTests.java | 53 -------- modules/autotagging-commons/build.gradle | 21 ++++ .../autotagging-commons/common}/build.gradle | 9 +- .../licenses/commons-collections-LICENSE.txt | 0 .../licenses/commons-collections-NOTICE.txt | 0 .../commons-collections4-4.4.jar.sha1 | 0 .../org/opensearch/rule}/GetRuleRequest.java | 28 +++-- .../org/opensearch/rule}/GetRuleResponse.java | 6 +- .../org/opensearch/rule/RuleAttribute.java | 2 +- .../org/opensearch/rule/RuleEntityParser.java | 2 +- .../rule}/RulePersistenceService.java | 4 +- .../org/opensearch/rule/RuleQueryMapper.java | 1 - .../AttributeExtractor.java | 2 +- .../attribute_extractor/package-info.java | 0 .../rule}/autotagging/Attribute.java | 6 +- .../autotagging/AutoTaggingRegistry.java | 14 ++- .../rule}/autotagging/FeatureType.java | 43 ++++++- .../opensearch/rule}/autotagging/Rule.java | 100 +++++++++++++++- .../rule}/autotagging/RuleValidator.java | 21 +++- .../rule}/autotagging/package-info.java | 2 +- .../org/opensearch/rule}/package-info.java | 5 +- .../IndexStoredRulePersistenceService.java | 17 ++- .../opensearch/rule/service/package-info.java | 0 .../rule/storage/AttributeValueStore.java | 0 .../storage/AttributeValueStoreFactory.java | 4 +- .../storage/DefaultAttributeValueStore.java | 0 .../storage/IndexBasedRuleQueryMapper.java | 6 +- .../rule/storage/XContentRuleParser.java | 4 +- .../opensearch/rule/storage/package-info.java | 0 .../rule/IndexStoredRuleUtilsTests.java | 17 ++- .../rule/XContentRuleParserTests.java | 8 +- ...ndexStoredRulePersistenceServiceTests.java | 10 +- .../AttributeValueStoreFactoryTests.java | 16 +-- .../storage/AttributeValueStoreTests.java | 0 .../opensearch/rule/utils/RuleTestUtils.java | 56 +-------- modules/autotagging-commons/spi/build.gradle | 26 ++++ .../rule/spi/RuleFrameworkExtension.java | 33 +++++ .../org/opensearch/rule/spi/package-info.java | 11 ++ .../rule/InMemoryRuleProcessingService.java | 6 +- .../opensearch/rule/RuleFrameworkPlugin.java | 80 +++++++++++++ .../rule/RulePersistenceServiceRegistry.java | 47 ++++++++ .../opensearch/rule/action/GetRuleAction.java | 18 +-- .../rule/action/TransportGetRuleAction.java | 30 ++--- .../opensearch/rule/action/package-info.java | 0 .../org/opensearch/rule/package-info.java | 0 .../rule/rest/RestGetRuleAction.java | 58 ++++----- .../opensearch/rule/rest/package-info.java | 0 .../InMemoryRuleProcessingServiceTests.java | 6 +- .../rule/action/GetRuleRequestTests.java | 113 ++++++++++++++++++ .../rule/action/GetRuleResponseTests.java | 31 ++++- .../autotagging/AutoTaggingRegistryTests.java | 8 +- .../rule}/autotagging/FeatureTypeTests.java | 10 +- .../rule}/autotagging/RuleTests.java | 8 +- .../rule}/autotagging/RuleValidatorTests.java | 14 +-- plugins/workload-management/build.gradle | 5 +- .../plugin/wlm/WorkloadManagementPlugin.java | 54 +++++---- .../wlm/WorkloadManagementPluginModule.java | 5 - .../wlm/rule/WorkloadGroupFeatureType.java | 10 +- .../attribute_extractor/IndicesExtractor.java | 2 +- ...opensearch.rule.spi.RuleFrameworkExtension | 9 ++ 60 files changed, 738 insertions(+), 303 deletions(-) delete mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java create mode 100644 modules/autotagging-commons/build.gradle rename {libs/autotagging-commons => modules/autotagging-commons/common}/build.gradle (67%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/licenses/commons-collections-LICENSE.txt (100%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/licenses/commons-collections-NOTICE.txt (100%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/licenses/commons-collections4-4.4.jar.sha1 (100%) rename {libs/autotagging-commons/src/main/java/org/opensearch/rule/action => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/GetRuleRequest.java (83%) rename {libs/autotagging-commons/src/main/java/org/opensearch/rule/action => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/GetRuleResponse.java (95%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/RuleAttribute.java (95%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/RuleEntityParser.java (94%) rename {libs/autotagging-commons/src/main/java/org/opensearch/rule/service => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/RulePersistenceService.java (83%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/RuleQueryMapper.java (93%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/attribute_extractor/AttributeExtractor.java (93%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/attribute_extractor/package-info.java (100%) rename {server/src/main/java/org/opensearch => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/autotagging/Attribute.java (94%) rename {server/src/main/java/org/opensearch => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/autotagging/AutoTaggingRegistry.java (90%) rename {server/src/main/java/org/opensearch => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/autotagging/FeatureType.java (73%) rename {server/src/main/java/org/opensearch => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/autotagging/Rule.java (83%) rename {server/src/main/java/org/opensearch => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/autotagging/RuleValidator.java (93%) rename {server/src/main/java/org/opensearch => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/autotagging/package-info.java (86%) rename {plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/package-info.java (62%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java (91%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/service/package-info.java (100%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/storage/AttributeValueStore.java (100%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/storage/AttributeValueStoreFactory.java (94%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/storage/DefaultAttributeValueStore.java (100%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java (91%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/storage/XContentRuleParser.java (94%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/main/java/org/opensearch/rule/storage/package-info.java (100%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java (67%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/test/java/org/opensearch/rule/XContentRuleParserTests.java (88%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java (95%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/test/java/org/opensearch/rule/storage/AttributeValueStoreFactoryTests.java (57%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/test/java/org/opensearch/rule/storage/AttributeValueStoreTests.java (100%) rename {libs/autotagging-commons => modules/autotagging-commons/common}/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java (54%) create mode 100644 modules/autotagging-commons/spi/build.gradle create mode 100644 modules/autotagging-commons/spi/src/main/java/org/opensearch/rule/spi/RuleFrameworkExtension.java create mode 100644 modules/autotagging-commons/spi/src/main/java/org/opensearch/rule/spi/package-info.java rename {libs => modules}/autotagging-commons/src/main/java/org/opensearch/rule/InMemoryRuleProcessingService.java (96%) create mode 100644 modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java create mode 100644 modules/autotagging-commons/src/main/java/org/opensearch/rule/RulePersistenceServiceRegistry.java rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java => modules/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleAction.java (53%) rename plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java => modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java (51%) rename {libs => modules}/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java (100%) rename {libs => modules}/autotagging-commons/src/main/java/org/opensearch/rule/package-info.java (100%) rename {libs => modules}/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java (72%) rename {libs => modules}/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java (100%) rename {libs => modules}/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java (97%) create mode 100644 modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java rename {libs => modules}/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java (77%) rename {server/src/test/java/org/opensearch => modules/autotagging-commons/src/test/java/org/opensearch/rule}/autotagging/AutoTaggingRegistryTests.java (85%) rename {server/src/test/java/org/opensearch => modules/autotagging-commons/src/test/java/org/opensearch/rule}/autotagging/FeatureTypeTests.java (76%) rename {server/src/test/java/org/opensearch => modules/autotagging-commons/src/test/java/org/opensearch/rule}/autotagging/RuleTests.java (95%) rename {server/src/test/java/org/opensearch => modules/autotagging-commons/src/test/java/org/opensearch/rule}/autotagging/RuleValidatorTests.java (90%) create mode 100644 plugins/workload-management/src/main/resources/META-INF/services/org.opensearch.rule.spi.RuleFrameworkExtension diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java deleted file mode 100644 index 110e51b777be4..0000000000000 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.action; - -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.utils.RuleTestUtils; -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.util.HashMap; - -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; -import static org.opensearch.rule.utils.RuleTestUtils.SEARCH_AFTER; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; - -public class GetRuleRequestTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of GetRuleRequest - */ - public void testSerialization() throws IOException { - GetRuleRequest request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE); - assertEquals(_ID_ONE, request.getId()); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - GetRuleRequest otherRequest = new GetRuleRequest(streamInput); - assertEquals(request.getId(), otherRequest.getId()); - assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); - } - - /** - * Test case to verify the serialization and deserialization of GetRuleRequest when name is null - */ - public void testSerializationWithNull() throws IOException { - GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER, MockRuleFeatureType.INSTANCE); - assertNull(request.getId()); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - GetRuleRequest otherRequest = new GetRuleRequest(streamInput); - assertEquals(request.getId(), otherRequest.getId()); - assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); - } -} diff --git a/modules/autotagging-commons/build.gradle b/modules/autotagging-commons/build.gradle new file mode 100644 index 0000000000000..47ee9ff75b980 --- /dev/null +++ b/modules/autotagging-commons/build.gradle @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + + +opensearchplugin { + description = 'OpenSearch Rule Framework plugin' + classname = 'org.opensearch.rule.RuleFrameworkPlugin' +} + +dependencies { + api project("spi") + api project("common") + testImplementation(project(":test:framework")) { + exclude group: 'org.opensearch', module: 'opensearch-core' + } +} diff --git a/libs/autotagging-commons/build.gradle b/modules/autotagging-commons/common/build.gradle similarity index 67% rename from libs/autotagging-commons/build.gradle rename to modules/autotagging-commons/common/build.gradle index cf3a75440c299..0dffb80015647 100644 --- a/libs/autotagging-commons/build.gradle +++ b/modules/autotagging-commons/common/build.gradle @@ -6,15 +6,22 @@ * compatible open source license. */ +apply plugin: 'opensearch.build' +apply plugin: 'opensearch.publish' + +description = 'OpenSearch Rule framework common constructs which spi and module shares' + dependencies { api 'org.apache.commons:commons-collections4:4.4' - api project(":server") + implementation project(":libs:opensearch-common") + compileOnly project(":server") testImplementation(project(":test:framework")) { exclude group: 'org.opensearch', module: 'opensearch-core' } } + tasks.named("dependencyLicenses").configure { mapping from: /commons-collections.*/, to: 'commons-collections' } diff --git a/libs/autotagging-commons/licenses/commons-collections-LICENSE.txt b/modules/autotagging-commons/common/licenses/commons-collections-LICENSE.txt similarity index 100% rename from libs/autotagging-commons/licenses/commons-collections-LICENSE.txt rename to modules/autotagging-commons/common/licenses/commons-collections-LICENSE.txt diff --git a/libs/autotagging-commons/licenses/commons-collections-NOTICE.txt b/modules/autotagging-commons/common/licenses/commons-collections-NOTICE.txt similarity index 100% rename from libs/autotagging-commons/licenses/commons-collections-NOTICE.txt rename to modules/autotagging-commons/common/licenses/commons-collections-NOTICE.txt diff --git a/libs/autotagging-commons/licenses/commons-collections4-4.4.jar.sha1 b/modules/autotagging-commons/common/licenses/commons-collections4-4.4.jar.sha1 similarity index 100% rename from libs/autotagging-commons/licenses/commons-collections4-4.4.jar.sha1 rename to modules/autotagging-commons/common/licenses/commons-collections4-4.4.jar.sha1 diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleRequest.java similarity index 83% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleRequest.java index 95a7f3ef9829f..9cdebb782edc9 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleRequest.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleRequest.java @@ -6,25 +6,23 @@ * compatible open source license. */ -package org.opensearch.rule.action; +package org.opensearch.rule; import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.Rule; +import org.opensearch.rule.autotagging.RuleValidator; import java.io.IOException; import java.util.HashSet; import java.util.Map; import java.util.Set; -import static org.opensearch.autotagging.Rule._ID_STRING; -import static org.opensearch.autotagging.RuleValidator.isEmpty; -import static org.opensearch.rule.rest.RestGetRuleAction.SEARCH_AFTER_STRING; - /** * A request for get Rule * Example Request: @@ -69,11 +67,11 @@ public GetRuleRequest(StreamInput in) throws IOException { @Override public ActionRequestValidationException validate() { - if (isEmpty(id)) { - throw new IllegalArgumentException(_ID_STRING + " cannot be empty."); + if (RuleValidator.isEmpty(id)) { + throw new IllegalArgumentException(Rule._ID_STRING + " cannot be empty."); } - if (isEmpty(searchAfter)) { - throw new IllegalArgumentException(SEARCH_AFTER_STRING + " cannot be empty."); + if (RuleValidator.isEmpty(searchAfter)) { + throw new IllegalArgumentException("search_after cannot be empty."); } return null; } @@ -107,4 +105,12 @@ public Map> getAttributeFilters() { public String getSearchAfter() { return searchAfter; } + + /** + * FeatureType getter + * @return + */ + public FeatureType getFeatureType() { + return featureType; + } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java similarity index 95% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java index 40eef52c26d6b..e3c0bb49043a7 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java @@ -6,9 +6,8 @@ * compatible open source license. */ -package org.opensearch.rule.action; +package org.opensearch.rule; -import org.opensearch.autotagging.Rule; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.StreamInput; @@ -16,11 +15,12 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.rule.autotagging.Rule; import java.io.IOException; import java.util.Map; -import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.autotagging.Rule._ID_STRING; /** * Response for the get API for Rule. diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleAttribute.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleAttribute.java similarity index 95% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleAttribute.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleAttribute.java index 9603751d7e37c..cd1e76f22d9d0 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleAttribute.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleAttribute.java @@ -8,7 +8,7 @@ package org.opensearch.rule; -import org.opensearch.autotagging.Attribute; +import org.opensearch.rule.autotagging.Attribute; /** * Generic Rule attributes that features can use out of the use by using the lib. diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleEntityParser.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleEntityParser.java similarity index 94% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleEntityParser.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleEntityParser.java index 8d352bd32eb61..dcc1b8ae1f681 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleEntityParser.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleEntityParser.java @@ -8,8 +8,8 @@ package org.opensearch.rule; -import org.opensearch.autotagging.Rule; import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.rule.autotagging.Rule; /** * Interface to parse various string representation of Rule entity diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java similarity index 83% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java index adcccfc429210..5d585b8541a51 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java @@ -6,11 +6,9 @@ * compatible open source license. */ -package org.opensearch.rule.service; +package org.opensearch.rule; import org.opensearch.core.action.ActionListener; -import org.opensearch.rule.action.GetRuleRequest; -import org.opensearch.rule.action.GetRuleResponse; /** * Interface for a service that handles rule persistence CRUD operations. diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleQueryMapper.java similarity index 93% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleQueryMapper.java index f0ee052790b4b..62dce30d04109 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/RuleQueryMapper.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleQueryMapper.java @@ -9,7 +9,6 @@ package org.opensearch.rule; import org.opensearch.common.annotation.ExperimentalApi; -import org.opensearch.rule.action.GetRuleRequest; /** * This interface is responsible for creating query objects which storage layer can use diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/attribute_extractor/AttributeExtractor.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/attribute_extractor/AttributeExtractor.java similarity index 93% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/attribute_extractor/AttributeExtractor.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/attribute_extractor/AttributeExtractor.java index 3e13ea54fad34..186211c65a76e 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/attribute_extractor/AttributeExtractor.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/attribute_extractor/AttributeExtractor.java @@ -8,7 +8,7 @@ package org.opensearch.rule.attribute_extractor; -import org.opensearch.autotagging.Attribute; +import org.opensearch.rule.autotagging.Attribute; /** * This interface defines the contract for extracting the attributes for Rule based auto-tagging feature diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/attribute_extractor/package-info.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/attribute_extractor/package-info.java similarity index 100% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/attribute_extractor/package-info.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/attribute_extractor/package-info.java diff --git a/server/src/main/java/org/opensearch/autotagging/Attribute.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Attribute.java similarity index 94% rename from server/src/main/java/org/opensearch/autotagging/Attribute.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Attribute.java index 61dfc7e704c20..76aa31d7d00f0 100644 --- a/server/src/main/java/org/opensearch/autotagging/Attribute.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Attribute.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; @@ -23,6 +23,10 @@ * @opensearch.experimental */ public interface Attribute extends Writeable { + /** + * Returns the attribute string representation + * @return + */ String getName(); /** diff --git a/server/src/main/java/org/opensearch/autotagging/AutoTaggingRegistry.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/AutoTaggingRegistry.java similarity index 90% rename from server/src/main/java/org/opensearch/autotagging/AutoTaggingRegistry.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/AutoTaggingRegistry.java index 394b89922dd2b..9cfc5ccb1e342 100644 --- a/server/src/main/java/org/opensearch/autotagging/AutoTaggingRegistry.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/AutoTaggingRegistry.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; import org.opensearch.ResourceNotFoundException; @@ -26,8 +26,20 @@ public class AutoTaggingRegistry { * The registration of FeatureType should only be done during boot-up. */ public static final Map featureTypesRegistryMap = new HashMap<>(); + /** + * Max chars a feature type can assume + */ public static final int MAX_FEATURE_TYPE_NAME_LENGTH = 30; + /** + * Make the class un-initialisable + */ + private AutoTaggingRegistry() {} + + /** + * Registers the new feature type + * @param featureType + */ public static void registerFeatureType(FeatureType featureType) { validateFeatureType(featureType); String name = featureType.getName(); diff --git a/server/src/main/java/org/opensearch/autotagging/FeatureType.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/FeatureType.java similarity index 73% rename from server/src/main/java/org/opensearch/autotagging/FeatureType.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/FeatureType.java index b446f62f6d764..c752f917264de 100644 --- a/server/src/main/java/org/opensearch/autotagging/FeatureType.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/FeatureType.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; @@ -28,9 +28,19 @@ * @opensearch.experimental */ public interface FeatureType extends Writeable { + /** + * Default value for max attribute values + */ int DEFAULT_MAX_ATTRIBUTE_VALUES = 10; + /** + * Default value for max number of chars in a single value + */ int DEFAULT_MAX_ATTRIBUTE_VALUE_LENGTH = 100; + /** + * Returns name + * @return + */ String getName(); /** @@ -39,16 +49,32 @@ public interface FeatureType extends Writeable { */ Map getAllowedAttributesRegistry(); + /** + * returns max attribute values + * @return + */ default int getMaxNumberOfValuesPerAttribute() { return DEFAULT_MAX_ATTRIBUTE_VALUES; } + /** + * returns value for max number of chars in a single value + * @return + */ default int getMaxCharLengthPerAttributeValue() { return DEFAULT_MAX_ATTRIBUTE_VALUE_LENGTH; } + /** + * makes the feature type usable and available to framework plugin + */ void registerFeatureType(); + /** + * checks the validity of the input attribute + * @param attribute + * @return + */ default boolean isValidAttribute(Attribute attribute) { return getAllowedAttributesRegistry().containsValue(attribute); } @@ -67,7 +93,22 @@ default void writeTo(StreamOutput out) throws IOException { out.writeString(getName()); } + /** + * parses the FeatureType using StreamInput + * @param in + * @return + * @throws IOException + */ static FeatureType from(StreamInput in) throws IOException { return AutoTaggingRegistry.getFeatureType(in.readString()); } + + /** + * Returns the instance for the passed param + * @param name + * @return + */ + static FeatureType from(String name) { + return AutoTaggingRegistry.getFeatureType(name); + } } diff --git a/server/src/main/java/org/opensearch/autotagging/Rule.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java similarity index 83% rename from server/src/main/java/org/opensearch/autotagging/Rule.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java index 0e64e977124d5..e1b003f0085c6 100644 --- a/server/src/main/java/org/opensearch/autotagging/Rule.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java @@ -6,10 +6,8 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.core.common.io.stream.Writeable; @@ -46,11 +44,27 @@ public class Rule implements Writeable, ToXContentObject { private final String featureValue; private final String updatedAt; private final RuleValidator ruleValidator; + /** + * id field + */ public static final String _ID_STRING = "_id"; + /** + * description field + */ public static final String DESCRIPTION_STRING = "description"; + /** + * updated_at field + */ public static final String UPDATED_AT_STRING = "updated_at"; - public static final Logger logger = LogManager.getLogger(Rule.class); + /** + * Main constructor + * @param description + * @param attributeMap + * @param featureType + * @param featureValue + * @param updatedAt + */ public Rule( String description, Map> attributeMap, @@ -67,6 +81,11 @@ public Rule( this.ruleValidator.validate(); } + /** + * constructor to init the object from StreamInput + * @param in + * @throws IOException + */ public Rule(StreamInput in) throws IOException { description = in.readString(); featureType = FeatureType.from(in); @@ -86,26 +105,53 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(updatedAt); } + /** + * static utility method to parse the Rule object + * @param parser + * @param featureType + * @return + * @throws IOException + */ public static Rule fromXContent(final XContentParser parser, FeatureType featureType) throws IOException { return Builder.fromXContent(parser, featureType).build(); } + /** + * description getter + * @return + */ public String getDescription() { return description; } + /** + * feature value getter + * @return + */ public String getFeatureValue() { return featureValue; } + /** + * updatedAt getter + * @return + */ public String getUpdatedAt() { return updatedAt; } + /** + * FeatureType getter + * @return + */ public FeatureType getFeatureType() { return featureType; } + /** + * attribute map getter + * @return + */ public Map> getAttributeMap() { return attributeMap; } @@ -166,6 +212,13 @@ public static class Builder { private Builder() {} + /** + * Parses the Rule object from XContentParser + * @param parser + * @param featureType + * @return + * @throws IOException + */ public static Builder fromXContent(XContentParser parser, FeatureType featureType) throws IOException { if (parser.currentToken() == null) { parser.nextToken(); @@ -197,7 +250,7 @@ public static Builder fromXContent(XContentParser parser, FeatureType featureTyp return builder.attributeMap(attributeMap1); } - public static void fromXContentParseArray( + private static void fromXContentParseArray( XContentParser parser, String fieldName, FeatureType featureType, @@ -218,39 +271,76 @@ public static void fromXContentParseArray( attributeMap.put(attribute, attributeValueSet); } + /** + * sets the description + * @param description + * @return + */ public Builder description(String description) { this.description = description; return this; } + /** + * sets the feature value + * @param featureValue + * @return + */ public Builder featureValue(String featureValue) { this.featureValue = featureValue; return this; } + /** + * Sets the attribute map + * @param attributeMap + * @return + */ public Builder attributeMap(Map> attributeMap) { this.attributeMap = attributeMap; return this; } + /** + * sets the feature type + * @param featureType + * @return + */ public Builder featureType(FeatureType featureType) { this.featureType = featureType; return this; } + /** + * sets the updatedAt + * @param updatedAt + * @return + */ public Builder updatedAt(String updatedAt) { this.updatedAt = updatedAt; return this; } + /** + * Builds the Rule object + * @return + */ public Rule build() { return new Rule(description, attributeMap, featureType, featureValue, updatedAt); } + /** + * Returns feature type for Rule + * @return + */ public String getFeatureValue() { return featureValue; } + /** + * Returns attribute map + * @return + */ public Map> getAttributeMap() { return attributeMap; } diff --git a/server/src/main/java/org/opensearch/autotagging/RuleValidator.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java similarity index 93% rename from server/src/main/java/org/opensearch/autotagging/RuleValidator.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java index fa38cad202c71..3314598e8211a 100644 --- a/server/src/main/java/org/opensearch/autotagging/RuleValidator.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; import org.opensearch.common.ValidationException; import org.joda.time.Instant; @@ -31,8 +31,19 @@ public class RuleValidator { private final String featureValue; private final String updatedAt; private final FeatureType featureType; + /** + * Max description length + */ public static final int MAX_DESCRIPTION_LENGTH = 256; + /** + * deafult constructor + * @param description + * @param attributeMap + * @param featureValue + * @param updatedAt + * @param featureType + */ public RuleValidator( String description, Map> attributeMap, @@ -47,6 +58,9 @@ public RuleValidator( this.featureType = featureType; } + /** + * validates the rule object fields + */ public void validate() { List errorMessages = new ArrayList<>(); errorMessages.addAll(validateStringFields()); @@ -80,6 +94,11 @@ private boolean isNullOrEmpty(String str) { return str == null || str.isEmpty(); } + /** + * Utility method which checks the empty string in context of Rule + * @param str + * @return + */ public static boolean isEmpty(String str) { return str != null && str.isEmpty(); } diff --git a/server/src/main/java/org/opensearch/autotagging/package-info.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/package-info.java similarity index 86% rename from server/src/main/java/org/opensearch/autotagging/package-info.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/package-info.java index 1c0794c18241b..d93f3be6493c3 100644 --- a/server/src/main/java/org/opensearch/autotagging/package-info.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/package-info.java @@ -10,4 +10,4 @@ * This package contains auto tagging constructs */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/package-info.java similarity index 62% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/package-info.java index b9fb278dae5b0..8dc3a4a68af26 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/package-info.java @@ -7,6 +7,7 @@ */ /** - * Package for the action classes related to rules in WorkloadManagementPlugin + * Holds the common constructs for Rule Framework */ -package org.opensearch.plugin.wlm.rule.action; + +package org.opensearch.rule; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java similarity index 91% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index 0c102995c652a..52fe043182e5b 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -12,16 +12,16 @@ import org.apache.logging.log4j.Logger; import org.opensearch.ResourceNotFoundException; import org.opensearch.action.search.SearchRequestBuilder; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.index.query.QueryBuilder; import org.opensearch.index.query.QueryBuilders; +import org.opensearch.rule.GetRuleRequest; +import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; +import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; -import org.opensearch.rule.action.GetRuleRequest; -import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.autotagging.Rule; import org.opensearch.search.SearchHit; import org.opensearch.search.sort.SortOrder; import org.opensearch.transport.client.Client; @@ -31,7 +31,7 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.autotagging.Rule._ID_STRING; /** * This class encapsulates the logic to manage the lifecycle of rules at index level @@ -43,7 +43,6 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService */ private final String indexName; private final Client client; - private final FeatureType featureType; private final int maxRulesPerPage; private final RuleEntityParser parser; private final RuleQueryMapper queryBuilder; @@ -54,7 +53,6 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService * This service handles persistence and retrieval of stored rules within an OpenSearch index. * @param indexName - The name of the OpenSearch index where the rules are stored. * @param client - The OpenSearch client used to interact with the OpenSearch cluster. - * @param featureType - The feature type associated with the stored rules. * @param maxRulesPerPage - The maximum number of rules that can be returned in a single get request. * @param parser * @param queryBuilder @@ -62,14 +60,12 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService public IndexStoredRulePersistenceService( String indexName, Client client, - FeatureType featureType, int maxRulesPerPage, RuleEntityParser parser, RuleQueryMapper queryBuilder ) { this.indexName = indexName; this.client = client; - this.featureType = featureType; this.maxRulesPerPage = maxRulesPerPage; this.parser = parser; this.queryBuilder = queryBuilder; @@ -81,7 +77,8 @@ public IndexStoredRulePersistenceService( * @param listener the listener for GetRuleResponse. */ public void getRule(GetRuleRequest getRuleRequest, ActionListener listener) { - final QueryBuilder getQueryBuilder = queryBuilder.from(getRuleRequest).filter(QueryBuilders.existsQuery(featureType.getName())); + final QueryBuilder getQueryBuilder = queryBuilder.from(getRuleRequest) + .filter(QueryBuilders.existsQuery(getRuleRequest.getFeatureType().getName())); getRuleFromIndex(getRuleRequest.getId(), getQueryBuilder, getRuleRequest.getSearchAfter(), listener); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/package-info.java similarity index 100% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/package-info.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/AttributeValueStore.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/AttributeValueStore.java similarity index 100% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/AttributeValueStore.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/AttributeValueStore.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/AttributeValueStoreFactory.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/AttributeValueStoreFactory.java similarity index 94% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/AttributeValueStoreFactory.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/AttributeValueStoreFactory.java index 8cda4bd26fdf0..e12e95bfdf3f6 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/AttributeValueStoreFactory.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/AttributeValueStoreFactory.java @@ -8,8 +8,8 @@ package org.opensearch.rule.storage; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.FeatureType; import java.util.HashMap; import java.util.Map; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/DefaultAttributeValueStore.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/DefaultAttributeValueStore.java similarity index 100% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/DefaultAttributeValueStore.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/DefaultAttributeValueStore.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java similarity index 91% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java index 4f79974cddb89..6f57ef478b577 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java @@ -8,18 +8,18 @@ package org.opensearch.rule.storage; -import org.opensearch.autotagging.Attribute; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilder; import org.opensearch.index.query.QueryBuilders; +import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.RuleQueryMapper; -import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.autotagging.Attribute; import java.util.Map; import java.util.Set; -import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.autotagging.Rule._ID_STRING; /** * This class is used to build opensearch index based query object diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/XContentRuleParser.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/XContentRuleParser.java similarity index 94% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/XContentRuleParser.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/XContentRuleParser.java index cadd1682aced1..2fca880bff4f8 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/XContentRuleParser.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/XContentRuleParser.java @@ -10,14 +10,14 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.xcontent.DeprecationHandler; import org.opensearch.core.xcontent.MediaTypeRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.core.xcontent.XContentParser; import org.opensearch.rule.RuleEntityParser; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.Rule; import java.io.IOException; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/package-info.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/package-info.java similarity index 100% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/storage/package-info.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/package-info.java diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java similarity index 67% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java index 0542cd722095f..46aaf6770b17c 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java @@ -10,17 +10,12 @@ import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.util.HashMap; -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; - public class IndexStoredRuleUtilsTests extends OpenSearchTestCase { RuleQueryMapper sut; @@ -30,20 +25,24 @@ public void setUp() throws Exception { } public void testBuildGetRuleQuery_WithId() { - QueryBuilder query = sut.from(new GetRuleRequest(_ID_ONE, new HashMap<>(), null, RuleTestUtils.MockRuleFeatureType.INSTANCE)); + QueryBuilder query = sut.from( + new GetRuleRequest(RuleTestUtils._ID_ONE, new HashMap<>(), null, RuleTestUtils.MockRuleFeatureType.INSTANCE) + ); assertNotNull(query); BoolQueryBuilder queryBuilder = (BoolQueryBuilder) query; assertEquals(1, queryBuilder.must().size()); QueryBuilder idQuery = queryBuilder.must().get(0); - assertTrue(idQuery.toString().contains(_ID_ONE)); + assertTrue(idQuery.toString().contains(RuleTestUtils._ID_ONE)); } public void testBuildGetRuleQuery_WithAttributes() { - QueryBuilder queryBuilder = sut.from(new GetRuleRequest(null, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE)); + QueryBuilder queryBuilder = sut.from( + new GetRuleRequest(null, RuleTestUtils.ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE) + ); assertNotNull(queryBuilder); BoolQueryBuilder query = (BoolQueryBuilder) queryBuilder; assertTrue(query.must().size() == 1); assertTrue(query.toString().contains(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE.getName())); - assertTrue(query.toString().contains(ATTRIBUTE_VALUE_ONE)); + assertTrue(query.toString().contains(RuleTestUtils.ATTRIBUTE_VALUE_ONE)); } } diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/XContentRuleParserTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java similarity index 88% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/XContentRuleParserTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java index 99634366ee1ab..e7b33a260a360 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/XContentRuleParserTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java @@ -8,7 +8,7 @@ package org.opensearch.rule; -import org.opensearch.autotagging.Rule; +import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.storage.XContentRuleParser; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; @@ -17,8 +17,6 @@ import java.time.Instant; import java.util.Locale; -import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; - public class XContentRuleParserTests extends OpenSearchTestCase { public static final String VALID_JSON = String.format(Locale.ROOT, """ { @@ -27,7 +25,7 @@ public class XContentRuleParserTests extends OpenSearchTestCase { "mock_attribute_one": ["attribute_value_one", "attribute_value_two"], "updated_at": "%s" } - """, DESCRIPTION_ONE, Instant.now().toString()); + """, RuleTestUtils.DESCRIPTION_ONE, Instant.now().toString()); private static final String INVALID_JSON = """ { @@ -46,7 +44,7 @@ public void setUp() throws Exception { public void testParseRule_Success() throws IOException { Rule parsedRule = sut.parse(VALID_JSON); assertNotNull(parsedRule); - assertEquals(DESCRIPTION_ONE, parsedRule.getDescription()); + assertEquals(RuleTestUtils.DESCRIPTION_ONE, parsedRule.getDescription()); assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, parsedRule.getFeatureType()); } diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java similarity index 95% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index 53444c20b6bb3..c76cb3d7d7121 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -12,7 +12,6 @@ import org.opensearch.ResourceNotFoundException; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; -import org.opensearch.autotagging.Rule; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.Metadata; import org.opensearch.cluster.service.ClusterService; @@ -21,10 +20,12 @@ import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesArray; import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.GetRuleRequest; +import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; +import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; -import org.opensearch.rule.action.GetRuleRequest; -import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.autotagging.Rule; import org.opensearch.search.SearchHit; import org.opensearch.search.SearchHits; import org.opensearch.test.OpenSearchTestCase; @@ -36,7 +37,6 @@ import org.mockito.ArgumentCaptor; import static org.opensearch.rule.XContentRuleParserTests.VALID_JSON; -import static org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; import static org.mockito.ArgumentMatchers.anyString; @@ -71,7 +71,6 @@ public void testGetRuleByIdSuccess() { RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( TEST_INDEX_NAME, client, - MockRuleFeatureType.INSTANCE, MAX_VALUES_PER_PAGE, mockRuleEntityParser, mockRuleQueryMapper @@ -117,7 +116,6 @@ public void testGetRuleByIdNotFound() { RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( TEST_INDEX_NAME, client, - MockRuleFeatureType.INSTANCE, MAX_VALUES_PER_PAGE, mockRuleEntityParser, mockRuleQueryMapper diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/storage/AttributeValueStoreFactoryTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/storage/AttributeValueStoreFactoryTests.java similarity index 57% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/storage/AttributeValueStoreFactoryTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/storage/AttributeValueStoreFactoryTests.java index 5cdc128c50620..ef0bb6c9d6aca 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/storage/AttributeValueStoreFactoryTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/storage/AttributeValueStoreFactoryTests.java @@ -8,9 +8,9 @@ package org.opensearch.rule.storage; -import org.opensearch.autotagging.Attribute; -import org.opensearch.rule.InMemoryRuleProcessingServiceTests.TestAttribute; -import org.opensearch.rule.InMemoryRuleProcessingServiceTests.WLMFeatureType; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.utils.RuleTestUtils.MockRuleAttributes; +import org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; import org.opensearch.test.OpenSearchTestCase; public class AttributeValueStoreFactoryTests extends OpenSearchTestCase { @@ -19,20 +19,22 @@ public class AttributeValueStoreFactoryTests extends OpenSearchTestCase { @Override public void setUp() throws Exception { super.setUp(); - sut = new AttributeValueStoreFactory(WLMFeatureType.WLM, DefaultAttributeValueStore::new); + sut = new AttributeValueStoreFactory(MockRuleFeatureType.INSTANCE, DefaultAttributeValueStore::new); } public void testFeatureLevelStoreInitialisation() { - for (Attribute attribute : WLMFeatureType.WLM.getAllowedAttributesRegistry().values()) { + for (Attribute attribute : MockRuleFeatureType.INSTANCE.getAllowedAttributesRegistry().values()) { assertTrue(sut.getAttributeValueStore(attribute) instanceof DefaultAttributeValueStore); } } public void testValidGetAttributeValueStore() { - assertTrue(sut.getAttributeValueStore(TestAttribute.TEST_ATTRIBUTE) instanceof DefaultAttributeValueStore); + assertTrue( + sut.getAttributeValueStore(MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE) instanceof DefaultAttributeValueStore + ); } public void testInValidGetAttributeValueStore() { - assertThrows(IllegalArgumentException.class, () -> { sut.getAttributeValueStore(TestAttribute.INVALID_ATTRIBUTE); }); + assertThrows(IllegalArgumentException.class, () -> { sut.getAttributeValueStore(MockRuleAttributes.INVALID_ATTRIBUTE); }); } } diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/storage/AttributeValueStoreTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/storage/AttributeValueStoreTests.java similarity index 100% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/storage/AttributeValueStoreTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/storage/AttributeValueStoreTests.java diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java similarity index 54% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index f6210e2d70899..3b655fe209a9a 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -8,17 +8,13 @@ package org.opensearch.rule.utils; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.AutoTaggingRegistry; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.AutoTaggingRegistry; +import org.opensearch.rule.autotagging.FeatureType; import java.util.Map; import java.util.Set; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - public class RuleTestUtils { public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; @@ -28,7 +24,6 @@ public class RuleTestUtils { public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two"; public static final String DESCRIPTION_ONE = "description_1"; public static final String DESCRIPTION_TWO = "description_2"; - public static final String SEARCH_AFTER = "search_after_id"; public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; public static final String FEATURE_TYPE_NAME = "mock_feature_type"; @@ -37,48 +32,8 @@ public class RuleTestUtils { MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_ONE) ); - public static final Rule ruleOne = Rule.builder() - .description(DESCRIPTION_ONE) - .featureType(MockRuleFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_ONE) - .attributeMap(ATTRIBUTE_MAP) - .updatedAt(TIMESTAMP_ONE) - .build(); - - public static final Rule ruleTwo = Rule.builder() - .description(DESCRIPTION_TWO) - .featureType(MockRuleFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_TWO) - .attributeMap(Map.of(MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, Set.of(ATTRIBUTE_VALUE_TWO))) - .updatedAt(TIMESTAMP_TWO) - .build(); - - public static Map ruleMap() { - return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); - } - public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { - assertEquals(mapOne.size(), mapTwo.size()); - for (Map.Entry entry : mapOne.entrySet()) { - String id = entry.getKey(); - assertTrue(mapTwo.containsKey(id)); - Rule one = mapOne.get(id); - Rule two = mapTwo.get(id); - assertEqualRule(one, two, ruleUpdated); - } - } - - public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { - if (ruleUpdated) { - assertEquals(one.getDescription(), two.getDescription()); - assertEquals(one.getFeatureType(), two.getFeatureType()); - assertEquals(one.getFeatureValue(), two.getFeatureValue()); - assertEquals(one.getAttributeMap(), two.getAttributeMap()); - assertEquals(one.getAttributeMap(), two.getAttributeMap()); - } else { - assertEquals(one, two); - } - } + public static final String INVALID_ATTRIBUTE = "invalid_attribute"; public static class MockRuleFeatureType implements FeatureType { @@ -113,7 +68,8 @@ public void registerFeatureType() { public enum MockRuleAttributes implements Attribute { MOCK_RULE_ATTRIBUTE_ONE(ATTRIBUTE_VALUE_ONE), - MOCK_RULE_ATTRIBUTE_TWO(ATTRIBUTE_VALUE_TWO); + MOCK_RULE_ATTRIBUTE_TWO(ATTRIBUTE_VALUE_TWO), + INVALID_ATTRIBUTE(RuleTestUtils.INVALID_ATTRIBUTE); ; private final String name; diff --git a/modules/autotagging-commons/spi/build.gradle b/modules/autotagging-commons/spi/build.gradle new file mode 100644 index 0000000000000..a91160c612f56 --- /dev/null +++ b/modules/autotagging-commons/spi/build.gradle @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +apply plugin: 'opensearch.build' +apply plugin: 'opensearch.publish' + + +base { + group = 'org.opensearch.plugin' + archivesName = 'autotagging-commons-spi' +} + +dependencies { + api project(':modules:autotagging-commons:common') +} + +disableTasks("forbiddenApisMain") + +testingConventions { + enabled = false +} diff --git a/modules/autotagging-commons/spi/src/main/java/org/opensearch/rule/spi/RuleFrameworkExtension.java b/modules/autotagging-commons/spi/src/main/java/org/opensearch/rule/spi/RuleFrameworkExtension.java new file mode 100644 index 0000000000000..6197fa9e03093 --- /dev/null +++ b/modules/autotagging-commons/spi/src/main/java/org/opensearch/rule/spi/RuleFrameworkExtension.java @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.spi; + +import org.opensearch.rule.RulePersistenceService; +import org.opensearch.rule.autotagging.FeatureType; + +import java.util.function.Supplier; + +/** + * This interface exposes methods for the RuleFrameworkPlugin to extract framework related + * implementations from the consumer plugins of this extension + */ +public interface RuleFrameworkExtension { + /** + * This method is used to flow implementation from consumer plugins into framework plugin + * @return the plugin specific implementation of RulePersistenceService + */ + Supplier getRulePersistenceServiceSupplier(); + + /** + * It tells the framework its FeatureType which can be used by Transport classes to handle the + * consumer specific persistence + * @return + */ + FeatureType getFeatureType(); +} diff --git a/modules/autotagging-commons/spi/src/main/java/org/opensearch/rule/spi/package-info.java b/modules/autotagging-commons/spi/src/main/java/org/opensearch/rule/spi/package-info.java new file mode 100644 index 0000000000000..c9ea0158ddd22 --- /dev/null +++ b/modules/autotagging-commons/spi/src/main/java/org/opensearch/rule/spi/package-info.java @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ +/** + * Contains extension points for framework plugin + */ +package org.opensearch.rule.spi; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/InMemoryRuleProcessingService.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/InMemoryRuleProcessingService.java similarity index 96% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/InMemoryRuleProcessingService.java rename to modules/autotagging-commons/src/main/java/org/opensearch/rule/InMemoryRuleProcessingService.java index 219f6fa5e1999..8f8b81268e5a7 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/InMemoryRuleProcessingService.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/InMemoryRuleProcessingService.java @@ -8,10 +8,10 @@ package org.opensearch.rule; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; import org.opensearch.rule.attribute_extractor.AttributeExtractor; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.storage.AttributeValueStore; import org.opensearch.rule.storage.AttributeValueStoreFactory; diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java new file mode 100644 index 0000000000000..49812b61e43f6 --- /dev/null +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.action.ActionRequest; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.node.DiscoveryNodes; +import org.opensearch.common.inject.Module; +import org.opensearch.common.settings.ClusterSettings; +import org.opensearch.common.settings.IndexScopedSettings; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.settings.SettingsFilter; +import org.opensearch.core.action.ActionResponse; +import org.opensearch.plugins.ActionPlugin; +import org.opensearch.plugins.ExtensiblePlugin; +import org.opensearch.plugins.Plugin; +import org.opensearch.rest.RestController; +import org.opensearch.rest.RestHandler; +import org.opensearch.rule.action.GetRuleAction; +import org.opensearch.rule.action.TransportGetRuleAction; +import org.opensearch.rule.autotagging.AutoTaggingRegistry; +import org.opensearch.rule.rest.RestGetRuleAction; +import org.opensearch.rule.spi.RuleFrameworkExtension; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Supplier; + +/** + * This plugin provides the central APIs which can provide CRUD support to all consumers of Rule framework + */ +public class RuleFrameworkPlugin extends Plugin implements ExtensiblePlugin, ActionPlugin { + private final RulePersistenceServiceRegistry rulePersistenceServiceRegistry = new RulePersistenceServiceRegistry(); + private final List ruleFrameworkExtensions = new ArrayList<>(); + + @Override + public List> getActions() { + // We are consuming the extensions at this place to ensure that the RulePersistenceService is initialised + ruleFrameworkExtensions.forEach(this::consumeFrameworkExtension); + return List.of(new ActionPlugin.ActionHandler<>(GetRuleAction.INSTANCE, TransportGetRuleAction.class)); + } + + @Override + public List getRestHandlers( + Settings settings, + RestController restController, + ClusterSettings clusterSettings, + IndexScopedSettings indexScopedSettings, + SettingsFilter settingsFilter, + IndexNameExpressionResolver indexNameExpressionResolver, + Supplier nodesInCluster + ) { + return List.of(new RestGetRuleAction()); + } + + @Override + public Collection createGuiceModules() { + return List.of(b -> { b.bind(RulePersistenceServiceRegistry.class).toInstance(rulePersistenceServiceRegistry); }); + } + + @Override + public void loadExtensions(ExtensionLoader loader) { + ruleFrameworkExtensions.addAll(loader.loadExtensions(RuleFrameworkExtension.class)); + } + + private void consumeFrameworkExtension(RuleFrameworkExtension ruleFrameworkExtension) { + AutoTaggingRegistry.registerFeatureType(ruleFrameworkExtension.getFeatureType()); + rulePersistenceServiceRegistry.register( + ruleFrameworkExtension.getFeatureType(), + ruleFrameworkExtension.getRulePersistenceServiceSupplier().get() + ); + } +} diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RulePersistenceServiceRegistry.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RulePersistenceServiceRegistry.java new file mode 100644 index 0000000000000..ab5e8baa13ac0 --- /dev/null +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RulePersistenceServiceRegistry.java @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.rule.autotagging.FeatureType; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This class manages implementations of {@link RulePersistenceService} + */ +public class RulePersistenceServiceRegistry { + private final Map rulePersistenceServices = new ConcurrentHashMap<>(); + + /** + * default constructor + */ + public RulePersistenceServiceRegistry() {} + + /** + * This method is used to register the concrete implementations of RulePersistenceService + * @param featureType + * @param rulePersistenceService + */ + public void register(FeatureType featureType, RulePersistenceService rulePersistenceService) { + if (rulePersistenceServices.put(featureType.getName(), rulePersistenceService) != null) { + throw new IllegalArgumentException("Duplicate rule persistence service: " + featureType.getName()); + } + } + + /** + * It is used to get feature type specific {@link RulePersistenceService} implementation + */ + public RulePersistenceService getRulePersistenceService(FeatureType featureType) { + if (!rulePersistenceServices.containsKey(featureType.getName())) { + throw new IllegalArgumentException("Unknown feature type: " + featureType.getName()); + } + return rulePersistenceServices.get(featureType.getName()); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleAction.java similarity index 53% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java rename to modules/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleAction.java index 080d417f1319d..e59eabf682510 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/GetWlmRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleAction.java @@ -6,31 +6,31 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rule.action; +package org.opensearch.rule.action; import org.opensearch.action.ActionType; -import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.GetRuleResponse; /** - * Action type for getting Rules in workload management + * Action type for getting Rules * @opensearch.experimental */ -public class GetWlmRuleAction extends ActionType { +public class GetRuleAction extends ActionType { /** * An instance of GetWlmRuleAction */ - public static final GetWlmRuleAction INSTANCE = new GetWlmRuleAction(); + public static final GetRuleAction INSTANCE = new GetRuleAction(); /** - * Name for GetWlmRuleAction + * Name for GetRuleAction */ - public static final String NAME = "cluster:admin/opensearch/wlm/rule/_get"; + public static final String NAME = "cluster:admin/opensearch/rule/_get"; /** - * Default constructor for GetWlmRuleAction + * Default constructor for GetRuleAction */ - private GetWlmRuleAction() { + private GetRuleAction() { super(NAME, GetRuleResponse::new); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java similarity index 51% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java rename to modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java index a074e4a0b570c..94321e5d40713 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportGetWlmRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java @@ -6,46 +6,48 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rule.action; +package org.opensearch.rule.action; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.HandledTransportAction; import org.opensearch.common.inject.Inject; -import org.opensearch.common.inject.name.Named; import org.opensearch.core.action.ActionListener; -import org.opensearch.plugin.wlm.rule.WorkloadGroupFeatureType; -import org.opensearch.rule.action.GetRuleRequest; -import org.opensearch.rule.action.GetRuleResponse; -import org.opensearch.rule.service.RulePersistenceService; +import org.opensearch.rule.GetRuleRequest; +import org.opensearch.rule.GetRuleResponse; +import org.opensearch.rule.RulePersistenceService; +import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; /** - * Transport action to get workload management Rules + * Transport action to get Rules * @opensearch.experimental */ -public class TransportGetWlmRuleAction extends HandledTransportAction { +public class TransportGetRuleAction extends HandledTransportAction { - private final RulePersistenceService rulePersistenceService; + private final RulePersistenceServiceRegistry rulePersistenceServiceRegistry; /** * Constructor for TransportGetWlmRuleAction * @param transportService - a {@link TransportService} object * @param actionFilters - a {@link ActionFilters} object - * @param rulePersistenceService - a {@link RulePersistenceService} object + * @param rulePersistenceServiceRegistry - a {@link RulePersistenceServiceRegistry} object */ @Inject - public TransportGetWlmRuleAction( + public TransportGetRuleAction( TransportService transportService, ActionFilters actionFilters, - @Named(WorkloadGroupFeatureType.NAME) RulePersistenceService rulePersistenceService + RulePersistenceServiceRegistry rulePersistenceServiceRegistry ) { - super(GetWlmRuleAction.NAME, transportService, actionFilters, GetRuleRequest::new); - this.rulePersistenceService = rulePersistenceService; + super(GetRuleAction.NAME, transportService, actionFilters, GetRuleRequest::new); + this.rulePersistenceServiceRegistry = rulePersistenceServiceRegistry; } @Override protected void doExecute(Task task, GetRuleRequest request, ActionListener listener) { + final RulePersistenceService rulePersistenceService = rulePersistenceServiceRegistry.getRulePersistenceService( + request.getFeatureType() + ); rulePersistenceService.getRule(request, listener); } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java similarity index 100% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java rename to modules/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/package-info.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/package-info.java similarity index 100% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/package-info.java rename to modules/autotagging-commons/src/main/java/org/opensearch/rule/package-info.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java similarity index 72% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java rename to modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java index e373ad85282c2..c42352c5f0b2e 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java @@ -8,20 +8,21 @@ package org.opensearch.rule.rest; -import org.opensearch.action.ActionType; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestHandler; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.rule.action.GetRuleRequest; -import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.GetRuleRequest; +import org.opensearch.rule.GetRuleResponse; +import org.opensearch.rule.action.GetRuleAction; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.transport.client.node.NodeClient; import java.io.IOException; @@ -31,8 +32,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; -import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.rest.RestRequest.Method.GET; +import static org.opensearch.rule.autotagging.Rule._ID_STRING; /** * Rest action to get a Rule @@ -40,51 +43,48 @@ */ @ExperimentalApi public class RestGetRuleAction extends BaseRestHandler { - private final String name; - private final List routes; - private final FeatureType featureType; - private final ActionType getRuleAction; /** * field name used for pagination */ public static final String SEARCH_AFTER_STRING = "search_after"; + public static final String FEATURE_TYPE = "featureType"; /** * constructor for RestGetRuleAction - * @param name - RestGetRuleAction name - * @param routes the list of REST routes this action handles - * @param featureType the feature type associated with the rule - * @param getRuleAction the action to execute for getting a rule */ - public RestGetRuleAction(String name, List routes, FeatureType featureType, ActionType getRuleAction) { - this.name = name; - this.routes = routes; - this.featureType = featureType; - this.getRuleAction = getRuleAction; - } + public RestGetRuleAction() {} @Override public String getName() { - return name; + return "get_rule"; } @Override public List routes() { - return routes; + return List.of(new RestHandler.Route(GET, "_rules/{featureType}/"), new RestHandler.Route(GET, "_rules/{featureType}/{_id}")); } @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { final Map> attributeFilters = new HashMap<>(); - for (String attributeName : request.params().keySet()) { - if (attributeName.equals(_ID_STRING) || attributeName.equals(SEARCH_AFTER_STRING)) { - continue; - } + + if (!request.hasParam(FEATURE_TYPE)) { + throw new IllegalArgumentException("Invalid route."); + } + + final FeatureType featureType = FeatureType.from(request.param(FEATURE_TYPE)); + final List requestParams = request.params() + .keySet() + .stream() + .filter(key -> !key.equals(FEATURE_TYPE) && !key.equals(_ID_STRING) && !key.equals(SEARCH_AFTER_STRING)) + .collect(Collectors.toList()); + + for (String attributeName : requestParams) { Attribute attribute = featureType.getAttributeFromName(attributeName); if (attribute == null) { throw new IllegalArgumentException(attributeName + " is not a valid attribute under feature type " + featureType.getName()); } - attributeFilters.put(attribute, parseAttributeValues(request.param(attributeName), attributeName)); + attributeFilters.put(attribute, parseAttributeValues(request.param(attributeName), attributeName, featureType)); } final GetRuleRequest getRuleRequest = new GetRuleRequest( request.param(_ID_STRING), @@ -92,7 +92,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli request.param(SEARCH_AFTER_STRING), featureType ); - return channel -> client.execute(getRuleAction, getRuleRequest, getRuleResponse(channel)); + return channel -> client.execute(GetRuleAction.INSTANCE, getRuleRequest, getRuleResponse(channel)); } /** @@ -100,7 +100,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli * @param attributeValues - the comma-separated string representing attributeValues * @param attributeName - attribute name */ - private HashSet parseAttributeValues(String attributeValues, String attributeName) { + private HashSet parseAttributeValues(String attributeValues, String attributeName, FeatureType featureType) { String[] valuesArray = attributeValues.split(","); int maxNumberOfValuesPerAttribute = featureType.getMaxNumberOfValuesPerAttribute(); if (valuesArray.length > maxNumberOfValuesPerAttribute) { diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java similarity index 100% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java rename to modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java similarity index 97% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java rename to modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java index d12900a79b121..a2c99f197b15a 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java @@ -8,11 +8,11 @@ package org.opensearch.rule; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.rule.attribute_extractor.AttributeExtractor; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.storage.DefaultAttributeValueStore; import org.opensearch.test.OpenSearchTestCase; diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java new file mode 100644 index 0000000000000..6bdbc81029048 --- /dev/null +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java @@ -0,0 +1,113 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.rule.GetRuleRequest; +import org.opensearch.rule.InMemoryRuleProcessingServiceTests; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.Rule; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.rule.InMemoryRuleProcessingServiceTests.WLMFeatureType; + +public class GetRuleRequestTests extends OpenSearchTestCase { + /** + * Test case to verify the serialization and deserialization of GetRuleRequest + */ + public void testSerialization() throws IOException { + GetRuleRequest request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, null, WLMFeatureType.WLM); + assertEquals(_ID_ONE, request.getId()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + GetRuleRequest otherRequest = new GetRuleRequest(streamInput); + assertEquals(request.getId(), otherRequest.getId()); + assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); + } + + /** + * Test case to verify the serialization and deserialization of GetRuleRequest when name is null + */ + public void testSerializationWithNull() throws IOException { + GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER, WLMFeatureType.WLM); + assertNull(request.getId()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + GetRuleRequest otherRequest = new GetRuleRequest(streamInput); + assertEquals(request.getId(), otherRequest.getId()); + assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); + } + + public static final String _ID_ONE = "id_1"; + public static final String SEARCH_AFTER = "search_after"; + public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; + public static final String FEATURE_VALUE_ONE = "feature_value_one"; + public static final String FEATURE_VALUE_TWO = "feature_value_two"; + public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; + public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two"; + public static final String DESCRIPTION_ONE = "description_1"; + public static final String DESCRIPTION_TWO = "description_2"; + public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; + public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; + public static final Map> ATTRIBUTE_MAP = Map.of( + InMemoryRuleProcessingServiceTests.TestAttribute.TEST_ATTRIBUTE, + Set.of(ATTRIBUTE_VALUE_ONE) + ); + + public static final Rule ruleOne = Rule.builder() + .description(DESCRIPTION_ONE) + .featureType(WLMFeatureType.WLM) + .featureValue(FEATURE_VALUE_ONE) + .attributeMap(ATTRIBUTE_MAP) + .updatedAt(TIMESTAMP_ONE) + .build(); + + public static final Rule ruleTwo = Rule.builder() + .description(DESCRIPTION_TWO) + .featureType(WLMFeatureType.WLM) + .featureValue(FEATURE_VALUE_TWO) + .attributeMap(Map.of(InMemoryRuleProcessingServiceTests.TestAttribute.TEST_ATTRIBUTE, Set.of(ATTRIBUTE_VALUE_TWO))) + .updatedAt(TIMESTAMP_TWO) + .build(); + + public static Map ruleMap() { + return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); + } + + public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { + assertEquals(mapOne.size(), mapTwo.size()); + for (Map.Entry entry : mapOne.entrySet()) { + String id = entry.getKey(); + assertTrue(mapTwo.containsKey(id)); + Rule one = mapOne.get(id); + Rule two = mapTwo.get(id); + assertEqualRule(one, two, ruleUpdated); + } + } + + public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { + if (ruleUpdated) { + assertEquals(one.getDescription(), two.getDescription()); + assertEquals(one.getFeatureType(), two.getFeatureType()); + assertEquals(one.getFeatureValue(), two.getFeatureValue()); + assertEquals(one.getAttributeMap(), two.getAttributeMap()); + assertEquals(one.getAttributeMap(), two.getAttributeMap()); + } else { + assertEquals(one, two); + } + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java similarity index 77% rename from libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java rename to modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java index 7d441fd44fa6a..019f49f71600a 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java @@ -8,26 +8,45 @@ package org.opensearch.rule.action; -import org.opensearch.autotagging.Rule; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.common.xcontent.json.JsonXContent; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.rule.GetRuleResponse; +import org.opensearch.rule.InMemoryRuleProcessingServiceTests; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.Rule; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.Set; -import static org.opensearch.rule.utils.RuleTestUtils.SEARCH_AFTER; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRules; -import static org.opensearch.rule.utils.RuleTestUtils.ruleMap; -import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; +import static org.opensearch.rule.action.GetRuleRequestTests.SEARCH_AFTER; +import static org.opensearch.rule.action.GetRuleRequestTests._ID_ONE; +import static org.opensearch.rule.action.GetRuleRequestTests.assertEqualRules; +import static org.opensearch.rule.action.GetRuleRequestTests.ruleMap; import static org.mockito.Mockito.mock; public class GetRuleResponseTests extends OpenSearchTestCase { + public static final String FEATURE_VALUE_ONE = "feature_value_one"; + public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; + public static final String DESCRIPTION_ONE = "description_1"; + public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; + static final Map> ATTRIBUTE_MAP = Map.of( + InMemoryRuleProcessingServiceTests.TestAttribute.TEST_ATTRIBUTE, + Set.of(ATTRIBUTE_VALUE_ONE) + ); + + public static final Rule ruleOne = Rule.builder() + .description(DESCRIPTION_ONE) + .featureType(InMemoryRuleProcessingServiceTests.WLMFeatureType.WLM) + .featureValue(FEATURE_VALUE_ONE) + .attributeMap(ATTRIBUTE_MAP) + .updatedAt(TIMESTAMP_ONE) + .build(); /** * Test case to verify the serialization and deserialization of GetRuleResponse diff --git a/server/src/test/java/org/opensearch/autotagging/AutoTaggingRegistryTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/AutoTaggingRegistryTests.java similarity index 85% rename from server/src/test/java/org/opensearch/autotagging/AutoTaggingRegistryTests.java rename to modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/AutoTaggingRegistryTests.java index 8bd240dad99e6..eee1d527dc6e9 100644 --- a/server/src/test/java/org/opensearch/autotagging/AutoTaggingRegistryTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/AutoTaggingRegistryTests.java @@ -6,15 +6,15 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; import org.opensearch.ResourceNotFoundException; import org.opensearch.test.OpenSearchTestCase; import org.junit.BeforeClass; -import static org.opensearch.autotagging.AutoTaggingRegistry.MAX_FEATURE_TYPE_NAME_LENGTH; -import static org.opensearch.autotagging.RuleTests.INVALID_FEATURE; -import static org.opensearch.autotagging.RuleTests.TEST_FEATURE_TYPE; +import static org.opensearch.rule.autotagging.AutoTaggingRegistry.MAX_FEATURE_TYPE_NAME_LENGTH; +import static org.opensearch.rule.autotagging.RuleTests.INVALID_FEATURE; +import static org.opensearch.rule.autotagging.RuleTests.TEST_FEATURE_TYPE; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/server/src/test/java/org/opensearch/autotagging/FeatureTypeTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/FeatureTypeTests.java similarity index 76% rename from server/src/test/java/org/opensearch/autotagging/FeatureTypeTests.java rename to modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/FeatureTypeTests.java index e8cf46818c515..168487f14dc62 100644 --- a/server/src/test/java/org/opensearch/autotagging/FeatureTypeTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/FeatureTypeTests.java @@ -6,17 +6,17 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; -import static org.opensearch.autotagging.RuleTests.FEATURE_TYPE; -import static org.opensearch.autotagging.RuleTests.INVALID_ATTRIBUTE; -import static org.opensearch.autotagging.RuleTests.TEST_ATTR1_NAME; -import static org.opensearch.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_1; +import static org.opensearch.rule.autotagging.RuleTests.FEATURE_TYPE; +import static org.opensearch.rule.autotagging.RuleTests.INVALID_ATTRIBUTE; +import static org.opensearch.rule.autotagging.RuleTests.TEST_ATTR1_NAME; +import static org.opensearch.rule.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_1; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; diff --git a/server/src/test/java/org/opensearch/autotagging/RuleTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleTests.java similarity index 95% rename from server/src/test/java/org/opensearch/autotagging/RuleTests.java rename to modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleTests.java index 5f27942639126..4ae89b496a1b3 100644 --- a/server/src/test/java/org/opensearch/autotagging/RuleTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; import org.opensearch.common.xcontent.json.JsonXContent; import org.opensearch.core.common.io.stream.Writeable; @@ -20,9 +20,9 @@ import java.util.Map; import java.util.Set; -import static org.opensearch.autotagging.Rule._ID_STRING; -import static org.opensearch.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_1; -import static org.opensearch.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_2; +import static org.opensearch.rule.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_1; +import static org.opensearch.rule.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_2; public class RuleTests extends AbstractSerializingTestCase { public static final String TEST_ATTR1_NAME = "test_attr1"; diff --git a/server/src/test/java/org/opensearch/autotagging/RuleValidatorTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java similarity index 90% rename from server/src/test/java/org/opensearch/autotagging/RuleValidatorTests.java rename to modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java index 8fbf16cd34c52..b24f9daa034c6 100644 --- a/server/src/test/java/org/opensearch/autotagging/RuleValidatorTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.autotagging; +package org.opensearch.rule.autotagging; import org.opensearch.test.OpenSearchTestCase; @@ -16,12 +16,12 @@ import java.util.Map; import java.util.Set; -import static org.opensearch.autotagging.RuleTests.ATTRIBUTE_MAP; -import static org.opensearch.autotagging.RuleTests.DESCRIPTION; -import static org.opensearch.autotagging.RuleTests.FEATURE_TYPE; -import static org.opensearch.autotagging.RuleTests.FEATURE_VALUE; -import static org.opensearch.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_1; -import static org.opensearch.autotagging.RuleTests.UPDATED_AT; +import static org.opensearch.rule.autotagging.RuleTests.ATTRIBUTE_MAP; +import static org.opensearch.rule.autotagging.RuleTests.DESCRIPTION; +import static org.opensearch.rule.autotagging.RuleTests.FEATURE_TYPE; +import static org.opensearch.rule.autotagging.RuleTests.FEATURE_VALUE; +import static org.opensearch.rule.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_1; +import static org.opensearch.rule.autotagging.RuleTests.UPDATED_AT; public class RuleValidatorTests extends OpenSearchTestCase { diff --git a/plugins/workload-management/build.gradle b/plugins/workload-management/build.gradle index 5396a74361b77..81c3d3652e96c 100644 --- a/plugins/workload-management/build.gradle +++ b/plugins/workload-management/build.gradle @@ -9,6 +9,7 @@ * GitHub history for details. */ +apply plugin: 'opensearch.opensearchplugin' apply plugin: 'opensearch.yaml-rest-test' apply plugin: 'opensearch.java-rest-test' apply plugin: 'opensearch.internal-cluster-test' @@ -16,8 +17,10 @@ apply plugin: 'opensearch.internal-cluster-test' opensearchplugin { description = 'OpenSearch Workload Management Plugin.' classname = 'org.opensearch.plugin.wlm.WorkloadManagementPlugin' + extendedPlugins = ['autotagging-commons'] } dependencies { - api project(":libs:opensearch-autotagging-commons") + implementation project(':modules:autotagging-commons:common') + compileOnly project(':modules:autotagging-commons:spi') } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index bce8f9d19d6a5..3187b7d9fdd49 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java @@ -37,8 +37,6 @@ import org.opensearch.plugin.wlm.rest.RestGetWorkloadGroupAction; import org.opensearch.plugin.wlm.rest.RestUpdateWorkloadGroupAction; import org.opensearch.plugin.wlm.rule.WorkloadGroupFeatureType; -import org.opensearch.plugin.wlm.rule.action.GetWlmRuleAction; -import org.opensearch.plugin.wlm.rule.action.TransportGetWlmRuleAction; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; import org.opensearch.plugins.ActionPlugin; import org.opensearch.plugins.Plugin; @@ -46,8 +44,10 @@ import org.opensearch.repositories.RepositoriesService; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; -import org.opensearch.rule.rest.RestGetRuleAction; +import org.opensearch.rule.RulePersistenceService; +import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.rule.spi.RuleFrameworkExtension; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.storage.XContentRuleParser; import org.opensearch.script.ScriptService; @@ -56,15 +56,14 @@ import org.opensearch.watcher.ResourceWatcherService; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.function.Supplier; -import static org.opensearch.rest.RestRequest.Method.GET; - /** * Plugin class for WorkloadManagement */ -public class WorkloadManagementPlugin extends Plugin implements ActionPlugin, SystemIndexPlugin { +public class WorkloadManagementPlugin extends Plugin implements ActionPlugin, SystemIndexPlugin, RuleFrameworkExtension { /** * The name of the index where rules are stored. */ @@ -74,6 +73,8 @@ public class WorkloadManagementPlugin extends Plugin implements ActionPlugin, Sy */ public static final int MAX_RULES_PER_PAGE = 50; + private final RulePersistenceServiceHolder rulePersistenceServiceHolder = new RulePersistenceServiceHolder(); + /** * Default constructor */ @@ -93,16 +94,14 @@ public Collection createComponents( IndexNameExpressionResolver indexNameExpressionResolver, Supplier repositoriesServiceSupplier ) { - return List.of( - new IndexStoredRulePersistenceService( - INDEX_NAME, - client, - WorkloadGroupFeatureType.INSTANCE, - MAX_RULES_PER_PAGE, - new XContentRuleParser(WorkloadGroupFeatureType.INSTANCE), - new IndexBasedRuleQueryMapper() - ) + RulePersistenceServiceHolder.rulePersistenceService = new IndexStoredRulePersistenceService( + INDEX_NAME, + client, + MAX_RULES_PER_PAGE, + new XContentRuleParser(WorkloadGroupFeatureType.INSTANCE), + new IndexBasedRuleQueryMapper() ); + return Collections.emptyList(); } @Override @@ -111,8 +110,7 @@ public Collection createComponents( new ActionPlugin.ActionHandler<>(CreateWorkloadGroupAction.INSTANCE, TransportCreateWorkloadGroupAction.class), new ActionPlugin.ActionHandler<>(GetWorkloadGroupAction.INSTANCE, TransportGetWorkloadGroupAction.class), new ActionPlugin.ActionHandler<>(DeleteWorkloadGroupAction.INSTANCE, TransportDeleteWorkloadGroupAction.class), - new ActionPlugin.ActionHandler<>(UpdateWorkloadGroupAction.INSTANCE, TransportUpdateWorkloadGroupAction.class), - new ActionPlugin.ActionHandler<>(GetWlmRuleAction.INSTANCE, TransportGetWlmRuleAction.class) + new ActionPlugin.ActionHandler<>(UpdateWorkloadGroupAction.INSTANCE, TransportUpdateWorkloadGroupAction.class) ); } @@ -135,13 +133,7 @@ public List getRestHandlers( new RestCreateWorkloadGroupAction(), new RestGetWorkloadGroupAction(), new RestDeleteWorkloadGroupAction(), - new RestUpdateWorkloadGroupAction(), - new RestGetRuleAction( - "get_rule", - List.of(new RestHandler.Route(GET, "_wlm/rule/"), new RestHandler.Route(GET, "_wlm/rule/{_id}")), - WorkloadGroupFeatureType.INSTANCE, - GetWlmRuleAction.INSTANCE - ) + new RestUpdateWorkloadGroupAction() ); } @@ -154,4 +146,18 @@ public List> getSettings() { public Collection createGuiceModules() { return List.of(new WorkloadManagementPluginModule()); } + + @Override + public Supplier getRulePersistenceServiceSupplier() { + return () -> RulePersistenceServiceHolder.rulePersistenceService; + } + + @Override + public FeatureType getFeatureType() { + return WorkloadGroupFeatureType.INSTANCE; + } + + static class RulePersistenceServiceHolder { + private static RulePersistenceService rulePersistenceService; + } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java index 18a3d604dca9a..bb0f4c7e90122 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java @@ -10,11 +10,7 @@ import org.opensearch.common.inject.AbstractModule; import org.opensearch.common.inject.Singleton; -import org.opensearch.common.inject.name.Names; -import org.opensearch.plugin.wlm.rule.WorkloadGroupFeatureType; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -import org.opensearch.rule.service.IndexStoredRulePersistenceService; -import org.opensearch.rule.service.RulePersistenceService; /** * Guice Module to manage WorkloadManagement related objects @@ -31,6 +27,5 @@ protected void configure() { // Bind WorkloadGroupPersistenceService as a singleton to ensure a single instance is used, // preventing multiple throttling key registrations in the constructor. bind(WorkloadGroupPersistenceService.class).in(Singleton.class); - bind(RulePersistenceService.class).annotatedWith(Names.named(WorkloadGroupFeatureType.NAME)).to(IndexStoredRulePersistenceService.class); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java index 9b20d59178939..fcad6f33397f3 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java @@ -8,10 +8,10 @@ package org.opensearch.plugin.wlm.rule; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.AutoTaggingRegistry; -import org.opensearch.autotagging.FeatureType; import org.opensearch.rule.RuleAttribute; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.AutoTaggingRegistry; +import org.opensearch.rule.autotagging.FeatureType; import java.util.Map; @@ -37,10 +37,6 @@ public class WorkloadGroupFeatureType implements FeatureType { private WorkloadGroupFeatureType() {} - static { - INSTANCE.registerFeatureType(); - } - @Override public String getName() { return NAME; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/attribute_extractor/IndicesExtractor.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/attribute_extractor/IndicesExtractor.java index 828d59820d841..e556e2984777e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/attribute_extractor/IndicesExtractor.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/attribute_extractor/IndicesExtractor.java @@ -9,9 +9,9 @@ package org.opensearch.plugin.wlm.rule.attribute_extractor; import org.opensearch.action.IndicesRequest; -import org.opensearch.autotagging.Attribute; import org.opensearch.rule.RuleAttribute; import org.opensearch.rule.attribute_extractor.AttributeExtractor; +import org.opensearch.rule.autotagging.Attribute; import java.util.List; diff --git a/plugins/workload-management/src/main/resources/META-INF/services/org.opensearch.rule.spi.RuleFrameworkExtension b/plugins/workload-management/src/main/resources/META-INF/services/org.opensearch.rule.spi.RuleFrameworkExtension new file mode 100644 index 0000000000000..71c636200b0d8 --- /dev/null +++ b/plugins/workload-management/src/main/resources/META-INF/services/org.opensearch.rule.spi.RuleFrameworkExtension @@ -0,0 +1,9 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# + +org.opensearch.plugin.wlm.WorkloadManagementPlugin From 099616c8c63e83907e7591da8a20becd6d56980a Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Mon, 21 Apr 2025 01:31:14 -0700 Subject: [PATCH 20/28] fix javadoc Signed-off-by: Ruirui Zhang --- .../main/java/org/opensearch/rule/RuleFrameworkPlugin.java | 6 ++++++ .../org/opensearch/rule/RulePersistenceServiceRegistry.java | 1 + .../java/org/opensearch/rule/rest/RestGetRuleAction.java | 3 +++ 3 files changed, 10 insertions(+) diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java index 49812b61e43f6..98f4bc25312c8 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java @@ -37,6 +37,12 @@ * This plugin provides the central APIs which can provide CRUD support to all consumers of Rule framework */ public class RuleFrameworkPlugin extends Plugin implements ExtensiblePlugin, ActionPlugin { + + /** + * constructor for RuleFrameworkPlugin + */ + private RuleFrameworkPlugin() {} + private final RulePersistenceServiceRegistry rulePersistenceServiceRegistry = new RulePersistenceServiceRegistry(); private final List ruleFrameworkExtensions = new ArrayList<>(); diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RulePersistenceServiceRegistry.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RulePersistenceServiceRegistry.java index ab5e8baa13ac0..57f47f1a6ad0f 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RulePersistenceServiceRegistry.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RulePersistenceServiceRegistry.java @@ -37,6 +37,7 @@ public void register(FeatureType featureType, RulePersistenceService rulePersist /** * It is used to get feature type specific {@link RulePersistenceService} implementation + * @param featureType - the type of feature to retrieve the persistence service for */ public RulePersistenceService getRulePersistenceService(FeatureType featureType) { if (!rulePersistenceServices.containsKey(featureType.getName())) { diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java index c42352c5f0b2e..62a070610252e 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java @@ -47,6 +47,9 @@ public class RestGetRuleAction extends BaseRestHandler { * field name used for pagination */ public static final String SEARCH_AFTER_STRING = "search_after"; + /** + * field name to specify feature type + */ public static final String FEATURE_TYPE = "featureType"; /** From 8f2734992a2eebc9e4a1df7c7ea43be4fdf94e37 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Mon, 21 Apr 2025 03:26:32 -0700 Subject: [PATCH 21/28] fix UT Signed-off-by: Ruirui Zhang --- .../IndexStoredRulePersistenceServiceTests.java | 3 +++ .../org/opensearch/rule/utils/RuleTestUtils.java | 1 - .../org/opensearch/rule/RuleFrameworkPlugin.java | 2 +- .../rule/InMemoryRuleProcessingServiceTests.java | 16 +++++++++------- .../rule/action/GetRuleResponseTests.java | 8 ++++---- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index c76cb3d7d7121..71c495d895900 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -26,6 +26,7 @@ import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; import org.opensearch.rule.autotagging.Rule; +import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.search.SearchHit; import org.opensearch.search.SearchHits; import org.opensearch.test.OpenSearchTestCase; @@ -90,6 +91,7 @@ public void testGetRuleByIdSuccess() { return null; }).when(searchRequestBuilder).execute(any(ActionListener.class)); + when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); rulePersistenceService.getRule(getRuleRequest, listener); ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); @@ -132,6 +134,7 @@ public void testGetRuleByIdNotFound() { return null; }).when(searchRequestBuilder).execute(any(ActionListener.class)); + when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); rulePersistenceService.getRule(getRuleRequest, listener); ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index 3b655fe209a9a..26a1be152e7b6 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -70,7 +70,6 @@ public enum MockRuleAttributes implements Attribute { MOCK_RULE_ATTRIBUTE_ONE(ATTRIBUTE_VALUE_ONE), MOCK_RULE_ATTRIBUTE_TWO(ATTRIBUTE_VALUE_TWO), INVALID_ATTRIBUTE(RuleTestUtils.INVALID_ATTRIBUTE); - ; private final String name; diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java index 98f4bc25312c8..d57840fcb6549 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java @@ -41,7 +41,7 @@ public class RuleFrameworkPlugin extends Plugin implements ExtensiblePlugin, Act /** * constructor for RuleFrameworkPlugin */ - private RuleFrameworkPlugin() {} + public RuleFrameworkPlugin() {} private final RulePersistenceServiceRegistry rulePersistenceServiceRegistry = new RulePersistenceServiceRegistry(); private final List ruleFrameworkExtensions = new ArrayList<>(); diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java index a2c99f197b15a..20a53c345edf7 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java @@ -8,15 +8,14 @@ package org.opensearch.rule; -import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.rule.attribute_extractor.AttributeExtractor; import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.AutoTaggingRegistry; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.storage.DefaultAttributeValueStore; import org.opensearch.test.OpenSearchTestCase; -import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Optional; @@ -124,9 +123,13 @@ public Iterable extract() { public enum WLMFeatureType implements FeatureType { WLM; + static { + WLM.registerFeatureType(); + } + @Override public String getName() { - return ""; + return "wlm"; } @Override @@ -135,7 +138,9 @@ public Map getAllowedAttributesRegistry() { } @Override - public void registerFeatureType() {} + public void registerFeatureType() { + AutoTaggingRegistry.registerFeatureType(WLM); + } } public enum TestAttribute implements Attribute { @@ -155,8 +160,5 @@ public String getName() { @Override public void validateAttribute() {} - - @Override - public void writeTo(StreamOutput out) throws IOException {} } } diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java index 019f49f71600a..4af9082f4db25 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java @@ -109,17 +109,17 @@ public void testToXContentGetSingleRule() throws IOException { String expected = "{\n" + " \"rules\" : [\n" + " {\n" - + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + + " \"_id\" : \"id_1\",\n" + " \"description\" : \"description_1\",\n" - + " \"mock_attribute_one\" : [\n" + + " \"test_attribute\" : [\n" + " \"mock_attribute_one\"\n" + " ],\n" - + " \"mock_feature_type\" : \"feature_value_one\",\n" + + " \"wlm\" : \"feature_value_one\",\n" + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + " }\n" + " ],\n" + " \"search_after\" : [\n" - + " \"search_after_id\"\n" + + " \"search_after\"\n" + " ]\n" + "}"; assertEquals(expected, actual); From 5e2209c43d9efc6f1a70ab96be33eacf94b9d437 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Mon, 21 Apr 2025 10:28:15 -0700 Subject: [PATCH 22/28] restructure tests Signed-off-by: Kaushal Kumar --- .../rule/action/GetRuleRequestTests.java | 21 +++++++++++-------- .../rule/action/GetRuleResponseTests.java | 10 ++++----- .../autotagging/AutoTaggingRegistryTests.java | 0 .../rule/autotagging/FeatureTypeTests.java | 0 .../rule/autotagging/RuleTests.java | 0 .../rule/autotagging/RuleValidatorTests.java | 0 .../opensearch/rule/utils/RuleTestUtils.java | 6 ------ 7 files changed, 17 insertions(+), 20 deletions(-) rename modules/autotagging-commons/{ => common}/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java (87%) rename modules/autotagging-commons/{ => common}/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java (94%) rename modules/autotagging-commons/{ => common}/src/test/java/org/opensearch/rule/autotagging/AutoTaggingRegistryTests.java (100%) rename modules/autotagging-commons/{ => common}/src/test/java/org/opensearch/rule/autotagging/FeatureTypeTests.java (100%) rename modules/autotagging-commons/{ => common}/src/test/java/org/opensearch/rule/autotagging/RuleTests.java (100%) rename modules/autotagging-commons/{ => common}/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java (100%) diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java similarity index 87% rename from modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java index 6bdbc81029048..12b74eb309034 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java @@ -11,9 +11,9 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.rule.GetRuleRequest; -import org.opensearch.rule.InMemoryRuleProcessingServiceTests; import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.Rule; +import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; @@ -21,14 +21,12 @@ import java.util.Map; import java.util.Set; -import static org.opensearch.rule.InMemoryRuleProcessingServiceTests.WLMFeatureType; - public class GetRuleRequestTests extends OpenSearchTestCase { /** * Test case to verify the serialization and deserialization of GetRuleRequest */ public void testSerialization() throws IOException { - GetRuleRequest request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, null, WLMFeatureType.WLM); + GetRuleRequest request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE); assertEquals(_ID_ONE, request.getId()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); @@ -42,7 +40,12 @@ public void testSerialization() throws IOException { * Test case to verify the serialization and deserialization of GetRuleRequest when name is null */ public void testSerializationWithNull() throws IOException { - GetRuleRequest request = new GetRuleRequest((String) null, new HashMap<>(), SEARCH_AFTER, WLMFeatureType.WLM); + GetRuleRequest request = new GetRuleRequest( + (String) null, + new HashMap<>(), + SEARCH_AFTER, + RuleTestUtils.MockRuleFeatureType.INSTANCE + ); assertNull(request.getId()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); @@ -64,13 +67,13 @@ public void testSerializationWithNull() throws IOException { public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; public static final Map> ATTRIBUTE_MAP = Map.of( - InMemoryRuleProcessingServiceTests.TestAttribute.TEST_ATTRIBUTE, + RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_ONE) ); public static final Rule ruleOne = Rule.builder() .description(DESCRIPTION_ONE) - .featureType(WLMFeatureType.WLM) + .featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE) .featureValue(FEATURE_VALUE_ONE) .attributeMap(ATTRIBUTE_MAP) .updatedAt(TIMESTAMP_ONE) @@ -78,9 +81,9 @@ public void testSerializationWithNull() throws IOException { public static final Rule ruleTwo = Rule.builder() .description(DESCRIPTION_TWO) - .featureType(WLMFeatureType.WLM) + .featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE) .featureValue(FEATURE_VALUE_TWO) - .attributeMap(Map.of(InMemoryRuleProcessingServiceTests.TestAttribute.TEST_ATTRIBUTE, Set.of(ATTRIBUTE_VALUE_TWO))) + .attributeMap(Map.of(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, Set.of(ATTRIBUTE_VALUE_TWO))) .updatedAt(TIMESTAMP_TWO) .build(); diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java similarity index 94% rename from modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java index 4af9082f4db25..f01bb94fab276 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java @@ -14,9 +14,9 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.rule.GetRuleResponse; -import org.opensearch.rule.InMemoryRuleProcessingServiceTests; import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.Rule; +import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; @@ -36,13 +36,13 @@ public class GetRuleResponseTests extends OpenSearchTestCase { public static final String DESCRIPTION_ONE = "description_1"; public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; static final Map> ATTRIBUTE_MAP = Map.of( - InMemoryRuleProcessingServiceTests.TestAttribute.TEST_ATTRIBUTE, + RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_ONE) ); public static final Rule ruleOne = Rule.builder() .description(DESCRIPTION_ONE) - .featureType(InMemoryRuleProcessingServiceTests.WLMFeatureType.WLM) + .featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE) .featureValue(FEATURE_VALUE_ONE) .attributeMap(ATTRIBUTE_MAP) .updatedAt(TIMESTAMP_ONE) @@ -111,10 +111,10 @@ public void testToXContentGetSingleRule() throws IOException { + " {\n" + " \"_id\" : \"id_1\",\n" + " \"description\" : \"description_1\",\n" - + " \"test_attribute\" : [\n" + + " \"mock_attribute_one\" : [\n" + " \"mock_attribute_one\"\n" + " ],\n" - + " \"wlm\" : \"feature_value_one\",\n" + + " \"mock_feature_type\" : \"feature_value_one\",\n" + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + " }\n" + " ],\n" diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/AutoTaggingRegistryTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/AutoTaggingRegistryTests.java similarity index 100% rename from modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/AutoTaggingRegistryTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/AutoTaggingRegistryTests.java diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/FeatureTypeTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/FeatureTypeTests.java similarity index 100% rename from modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/FeatureTypeTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/FeatureTypeTests.java diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleTests.java similarity index 100% rename from modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleTests.java diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java similarity index 100% rename from modules/autotagging-commons/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java rename to modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index 26a1be152e7b6..6ec75e4b942ff 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -17,15 +17,9 @@ public class RuleTestUtils { public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; - public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; - public static final String FEATURE_VALUE_ONE = "feature_value_one"; - public static final String FEATURE_VALUE_TWO = "feature_value_two"; public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two"; public static final String DESCRIPTION_ONE = "description_1"; - public static final String DESCRIPTION_TWO = "description_2"; - public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; - public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; public static final String FEATURE_TYPE_NAME = "mock_feature_type"; public static final String TEST_INDEX_NAME = ".test_index_for_rule"; public static final Map> ATTRIBUTE_MAP = Map.of( From 37ac46546bcf138b462feb0110c5d1b41d23dbde Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Mon, 21 Apr 2025 14:06:24 -0700 Subject: [PATCH 23/28] rebase with mainline Signed-off-by: Kaushal Kumar --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6e8774db9034..d95bcf4e81b0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased 3.x] ### Added +- [Rule based auto-tagging] Add get rule API ([#17336](https://github.com/opensearch-project/OpenSearch/pull/17336)) - Add multi-threaded writer support in pull-based ingestion ([#17912](https://github.com/opensearch-project/OpenSearch/pull/17912)) - Implement parallel shard refresh behind cluster settings ([#17782](https://github.com/opensearch-project/OpenSearch/pull/17782)) From ebfdf436e3ab1bfec0b1ff487d8419c5668559b1 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Tue, 22 Apr 2025 00:59:25 -0700 Subject: [PATCH 24/28] fix gradlew file Signed-off-by: Ruirui Zhang --- plugins/workload-management/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/workload-management/build.gradle b/plugins/workload-management/build.gradle index 81c3d3652e96c..7ac16405b2458 100644 --- a/plugins/workload-management/build.gradle +++ b/plugins/workload-management/build.gradle @@ -17,10 +17,10 @@ apply plugin: 'opensearch.internal-cluster-test' opensearchplugin { description = 'OpenSearch Workload Management Plugin.' classname = 'org.opensearch.plugin.wlm.WorkloadManagementPlugin' - extendedPlugins = ['autotagging-commons'] + extendedPlugins = [] // Remove autotagging-commons since it's not a plugin } dependencies { implementation project(':modules:autotagging-commons:common') - compileOnly project(':modules:autotagging-commons:spi') + implementation project(':modules:autotagging-commons:spi') } From a2ef82077bcc789f4d9d6fe8871a855e87c2537a Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Tue, 22 Apr 2025 03:23:26 -0700 Subject: [PATCH 25/28] add UT Signed-off-by: Ruirui Zhang --- .../opensearch/rule/RuleAttributeTests.java | 28 +++++++++++ .../rule/action/GetRuleRequestTests.java | 10 ++++ .../rule/RuleFrameworkPluginTests.java | 49 +++++++++++++++++++ .../RulePersistenceServiceRegistryTests.java | 48 ++++++++++++++++++ .../rule/rest/RestGetRuleActionTests.java | 26 ++++++++++ .../rule/WorkloadGroupFeatureTypeTests.java | 47 ++++++++++++++++++ 6 files changed, 208 insertions(+) create mode 100644 modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleAttributeTests.java create mode 100644 modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java create mode 100644 modules/autotagging-commons/src/test/java/org/opensearch/rule/RulePersistenceServiceRegistryTests.java create mode 100644 modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestGetRuleActionTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleAttributeTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleAttributeTests.java new file mode 100644 index 0000000000000..53492d020e205 --- /dev/null +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleAttributeTests.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.test.OpenSearchTestCase; + +public class RuleAttributeTests extends OpenSearchTestCase { + + public void testGetName() { + RuleAttribute attribute = RuleAttribute.INDEX_PATTERN; + assertEquals("index_pattern", attribute.getName()); + } + + public void testFromName() { + RuleAttribute attribute = RuleAttribute.fromName("index_pattern"); + assertEquals(RuleAttribute.INDEX_PATTERN, attribute); + } + + public void testFromName_throwsException() { + assertThrows(IllegalArgumentException.class, () -> RuleAttribute.fromName("invalid_attribute")); + } +} diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java index 12b74eb309034..a451a58356606 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java @@ -28,6 +28,9 @@ public class GetRuleRequestTests extends OpenSearchTestCase { public void testSerialization() throws IOException { GetRuleRequest request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE); assertEquals(_ID_ONE, request.getId()); + assertNull(request.validate()); + assertNull(request.getSearchAfter()); + assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, request.getFeatureType()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); @@ -55,6 +58,13 @@ public void testSerializationWithNull() throws IOException { assertEquals(request.getAttributeFilters(), otherRequest.getAttributeFilters()); } + public void testValidate() { + GetRuleRequest request = new GetRuleRequest("", ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertThrows(IllegalArgumentException.class, request::validate); + request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, "", RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertThrows(IllegalArgumentException.class, request::validate); + } + public static final String _ID_ONE = "id_1"; public static final String SEARCH_AFTER = "search_after"; public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java new file mode 100644 index 0000000000000..fd4c5d18cf2cf --- /dev/null +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.action.ActionRequest; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.node.DiscoveryNodes; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.action.ActionResponse; +import org.opensearch.plugins.ActionPlugin; +import org.opensearch.rest.RestHandler; +import org.opensearch.rule.action.GetRuleAction; +import org.opensearch.rule.rest.RestGetRuleAction; +import org.opensearch.test.OpenSearchTestCase; + +import java.util.List; + +import static org.mockito.Mockito.mock; + +public class RuleFrameworkPluginTests extends OpenSearchTestCase { + RuleFrameworkPlugin plugin = new RuleFrameworkPlugin();; + + public void testGetActions() { + List> handlers = plugin.getActions(); + assertEquals(1, handlers.size()); + assertEquals(GetRuleAction.INSTANCE.name(), handlers.get(0).getAction().name()); + } + + public void testGetRestHandlers() { + Settings settings = Settings.EMPTY; + RestHandler handler = plugin.getRestHandlers( + settings, + mock(org.opensearch.rest.RestController.class), + null, + null, + null, + mock(IndexNameExpressionResolver.class), + () -> mock(DiscoveryNodes.class) + ).get(0); + + assertTrue(handler instanceof RestGetRuleAction); + } +} diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/RulePersistenceServiceRegistryTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/RulePersistenceServiceRegistryTests.java new file mode 100644 index 0000000000000..116ad7a730c58 --- /dev/null +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/RulePersistenceServiceRegistryTests.java @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.test.OpenSearchTestCase; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class RulePersistenceServiceRegistryTests extends OpenSearchTestCase { + RulePersistenceServiceRegistry registry = new RulePersistenceServiceRegistry();; + FeatureType mockFeatureType = mock(FeatureType.class);; + RulePersistenceService mockService = mock(RulePersistenceService.class); + + public void testRegisterAndGetService() { + when(mockFeatureType.getName()).thenReturn("test_feature"); + registry.register(mockFeatureType, mockService); + RulePersistenceService retrievedService = registry.getRulePersistenceService(mockFeatureType); + assertSame(mockService, retrievedService); + } + + public void testRegisterDuplicateService() { + when(mockFeatureType.getName()).thenReturn("duplicate_feature"); + registry.register(mockFeatureType, mockService); + RulePersistenceService anotherService = mock(RulePersistenceService.class); + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + () -> registry.register(mockFeatureType, anotherService) + ); + assertTrue(ex.getMessage().contains("Duplicate rule persistence service: duplicate_feature")); + } + + public void testGetRulePersistenceService_UnknownFeature() { + when(mockFeatureType.getName()).thenReturn("unknown_feature"); + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + () -> registry.getRulePersistenceService(mockFeatureType) + ); + assertTrue(ex.getMessage().contains("Unknown feature type: unknown_feature")); + } +} diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestGetRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestGetRuleActionTests.java new file mode 100644 index 0000000000000..726924593e2b8 --- /dev/null +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestGetRuleActionTests.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.rest; + +import org.opensearch.test.OpenSearchTestCase; + +public class RestGetRuleActionTests extends OpenSearchTestCase { + RestGetRuleAction action = new RestGetRuleAction();; + + public void testGetName() { + assertEquals("get_rule", action.getName()); + } + + public void testRoutes() { + var routes = action.routes(); + assertEquals(2, routes.size()); + assertTrue(routes.stream().anyMatch(r -> r.getPath().equals("_rules/{featureType}/"))); + assertTrue(routes.stream().anyMatch(r -> r.getPath().equals("_rules/{featureType}/{_id}"))); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java new file mode 100644 index 0000000000000..b0ac1d78edbac --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule; + +import org.opensearch.rule.RuleAttribute; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.AutoTaggingRegistry; +import org.opensearch.test.OpenSearchTestCase; + +import java.util.Map; + +public class WorkloadGroupFeatureTypeTests extends OpenSearchTestCase { + private WorkloadGroupFeatureType featureType; + + public void setUp() throws Exception { + super.setUp(); + featureType = WorkloadGroupFeatureType.INSTANCE; + } + + public void testGetName_returnsCorrectName() { + assertEquals("workload_group", featureType.getName()); + } + + public void testMaxNumberOfValuesPerAttribute() { + assertEquals(10, featureType.getMaxNumberOfValuesPerAttribute()); + } + + public void testMaxCharLengthPerAttributeValue() { + assertEquals(100, featureType.getMaxCharLengthPerAttributeValue()); + } + + public void testGetAllowedAttributesRegistry_containsIndexPattern() { + Map allowedAttributes = featureType.getAllowedAttributesRegistry(); + assertTrue(allowedAttributes.containsKey("index_pattern")); + assertEquals(RuleAttribute.INDEX_PATTERN, allowedAttributes.get("index_pattern")); + } + + public void testRegisterFeatureType() { + AutoTaggingRegistry.registerFeatureType(featureType); + } +} From 5394f0d1992cdb4dd17222751d0ae1c5a5ebc8f0 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Tue, 22 Apr 2025 11:11:27 -0700 Subject: [PATCH 26/28] add action UTs Signed-off-by: Kaushal Kumar --- .../rule/rest/RestGetRuleAction.java | 3 +- .../rule/action/GetRuleActionTests.java | 22 ++++++++++ .../action/TransportGetRuleActionTests.java | 42 +++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleActionTests.java create mode 100644 modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java index 62a070610252e..f1bd56927c41f 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java @@ -32,7 +32,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import static org.opensearch.rest.RestRequest.Method.GET; import static org.opensearch.rule.autotagging.Rule._ID_STRING; @@ -80,7 +79,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli .keySet() .stream() .filter(key -> !key.equals(FEATURE_TYPE) && !key.equals(_ID_STRING) && !key.equals(SEARCH_AFTER_STRING)) - .collect(Collectors.toList()); + .toList(); for (String attributeName : requestParams) { Attribute attribute = featureType.getAttributeFromName(attributeName); diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleActionTests.java new file mode 100644 index 0000000000000..982e5ca50b0be --- /dev/null +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/GetRuleActionTests.java @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.core.common.io.stream.Writeable; +import org.opensearch.test.OpenSearchTestCase; + +public class GetRuleActionTests extends OpenSearchTestCase { + public void testGetName() { + assertEquals("cluster:admin/opensearch/rule/_get", GetRuleAction.NAME); + } + + public void testGetResponseReader() { + assertTrue(GetRuleAction.INSTANCE.getResponseReader() instanceof Writeable.Reader); + } +} diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java new file mode 100644 index 0000000000000..01202bd7ddcd7 --- /dev/null +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.action.support.ActionFilters; +import org.opensearch.rule.GetRuleRequest; +import org.opensearch.rule.RulePersistenceService; +import org.opensearch.rule.RulePersistenceServiceRegistry; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.TransportService; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class TransportGetRuleActionTests extends OpenSearchTestCase { + TransportGetRuleAction sut; + + public void testExecute() { + RulePersistenceServiceRegistry rulePersistenceServiceRegistry = mock(RulePersistenceServiceRegistry.class); + TransportService transportService = mock(TransportService.class); + ActionFilters actiionFilters = mock(ActionFilters.class); + RulePersistenceService rulePersistenceService = mock(RulePersistenceService.class); + GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); + when(getRuleRequest.getFeatureType()).thenReturn(null); + + when(rulePersistenceServiceRegistry.getRulePersistenceService(any())).thenReturn(rulePersistenceService); + doNothing().when(rulePersistenceService).getRule(any(), any()); + sut = new TransportGetRuleAction(transportService, actiionFilters, rulePersistenceServiceRegistry); + sut.doExecute(null, getRuleRequest, null); + verify(rulePersistenceService, times(1)).getRule(any(), any()); + } +} From 783ce6186c69e801a9b7c32e0dbbc8b9a0b435d5 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Tue, 22 Apr 2025 12:54:51 -0700 Subject: [PATCH 27/28] correct the comment Signed-off-by: Kaushal Kumar --- .../opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java index fcad6f33397f3..1dce67ee4e72d 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java @@ -21,7 +21,7 @@ */ public class WorkloadGroupFeatureType implements FeatureType { /** - * The instance for QueryGroupFeatureType + * The instance for WorkloadGroupFeatureType */ public static final WorkloadGroupFeatureType INSTANCE = new WorkloadGroupFeatureType(); /** From d6b3e7924638811e932c56c917d594b8417ca3ed Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Tue, 22 Apr 2025 19:12:19 -0700 Subject: [PATCH 28/28] add more UT Signed-off-by: Ruirui Zhang --- .../rule/XContentRuleParserTests.java | 1 - .../action/TransportGetRuleActionTests.java | 4 +- .../wlm/WorkloadManagementPluginTests.java | 115 ++++++++++++++++++ .../rule/WorkloadGroupFeatureTypeTests.java | 7 +- 4 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadManagementPluginTests.java diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java index e7b33a260a360..67b7cb8f54c53 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java @@ -52,5 +52,4 @@ public void testParseRule_InvalidJson() { Exception exception = assertThrows(RuntimeException.class, () -> sut.parse(INVALID_JSON)); assertTrue(exception.getMessage().contains("mock_attribute_three is not a valid attribute within the mock_feature_type feature.")); } - } diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java index 01202bd7ddcd7..369af17ed581f 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java @@ -28,14 +28,14 @@ public class TransportGetRuleActionTests extends OpenSearchTestCase { public void testExecute() { RulePersistenceServiceRegistry rulePersistenceServiceRegistry = mock(RulePersistenceServiceRegistry.class); TransportService transportService = mock(TransportService.class); - ActionFilters actiionFilters = mock(ActionFilters.class); + ActionFilters actionFilters = mock(ActionFilters.class); RulePersistenceService rulePersistenceService = mock(RulePersistenceService.class); GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); when(getRuleRequest.getFeatureType()).thenReturn(null); when(rulePersistenceServiceRegistry.getRulePersistenceService(any())).thenReturn(rulePersistenceService); doNothing().when(rulePersistenceService).getRule(any(), any()); - sut = new TransportGetRuleAction(transportService, actiionFilters, rulePersistenceServiceRegistry); + sut = new TransportGetRuleAction(transportService, actionFilters, rulePersistenceServiceRegistry); sut.doExecute(null, getRuleRequest, null); verify(rulePersistenceService, times(1)).getRule(any(), any()); } diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadManagementPluginTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadManagementPluginTests.java new file mode 100644 index 0000000000000..6838102ac3bf1 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadManagementPluginTests.java @@ -0,0 +1,115 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm; + +import org.opensearch.action.ActionRequest; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.node.DiscoveryNodes; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.action.ActionResponse; +import org.opensearch.core.common.io.stream.NamedWriteableRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.env.Environment; +import org.opensearch.indices.SystemIndexDescriptor; +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; +import org.opensearch.plugin.wlm.rest.RestCreateWorkloadGroupAction; +import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; +import org.opensearch.plugin.wlm.rest.RestGetWorkloadGroupAction; +import org.opensearch.plugin.wlm.rest.RestUpdateWorkloadGroupAction; +import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +import org.opensearch.plugins.ActionPlugin; +import org.opensearch.repositories.RepositoriesService; +import org.opensearch.rest.RestController; +import org.opensearch.rest.RestHandler; +import org.opensearch.rule.RulePersistenceService; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.script.ScriptService; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.client.Client; +import org.opensearch.watcher.ResourceWatcherService; + +import java.util.Collection; +import java.util.List; + +import static org.mockito.Mockito.mock; + +public class WorkloadManagementPluginTests extends OpenSearchTestCase { + WorkloadManagementPlugin plugin = new WorkloadManagementPlugin(); + + public void testGetActionsReturnsHandlers() { + List> actions = plugin.getActions(); + assertEquals(4, actions.size()); + assertEquals(CreateWorkloadGroupAction.INSTANCE.name(), actions.get(0).getAction().name()); + } + + public void testGetRestHandlersReturnsHandlers() { + List handlers = plugin.getRestHandlers( + Settings.EMPTY, + mock(RestController.class), + null, + null, + null, + null, + () -> mock(DiscoveryNodes.class) + ); + + assertEquals(4, handlers.size()); + assertTrue(handlers.stream().anyMatch(h -> h instanceof RestCreateWorkloadGroupAction)); + assertTrue(handlers.stream().anyMatch(h -> h instanceof RestGetWorkloadGroupAction)); + assertTrue(handlers.stream().anyMatch(h -> h instanceof RestDeleteWorkloadGroupAction)); + assertTrue(handlers.stream().anyMatch(h -> h instanceof RestUpdateWorkloadGroupAction)); + } + + public void testCreateComponentsInitializesRulePersistenceService() { + Client mockClient = mock(Client.class); + plugin.createComponents( + mockClient, + mock(ClusterService.class), + mock(ThreadPool.class), + mock(ResourceWatcherService.class), + mock(ScriptService.class), + mock(NamedXContentRegistry.class), + mock(Environment.class), + null, + mock(NamedWriteableRegistry.class), + mock(IndexNameExpressionResolver.class), + () -> mock(RepositoriesService.class) + ); + + RulePersistenceService service = plugin.getRulePersistenceServiceSupplier().get(); + assertNotNull(service); + assertTrue(service instanceof IndexStoredRulePersistenceService); + } + + public void testGetSystemIndexDescriptorsReturnsCorrectDescriptor() { + Collection descriptors = plugin.getSystemIndexDescriptors(Settings.EMPTY); + assertEquals(1, descriptors.size()); + SystemIndexDescriptor descriptor = descriptors.iterator().next(); + assertEquals(".wlm_rules", descriptor.getIndexPattern()); + } + + public void testGetFeatureTypeReturnsWorkloadGroupFeatureType() { + FeatureType featureType = plugin.getFeatureType(); + assertEquals("workload_group", featureType.getName()); + } + + public void testGetSettingsIncludesMaxQueryGroupCount() { + List settings = plugin.getSettings(); + assertTrue(settings.contains(WorkloadGroupPersistenceService.MAX_QUERY_GROUP_COUNT)); + } + + public void testCreateGuiceModulesReturnsModule() { + Collection modules = plugin.createGuiceModules(); + assertEquals(1, modules.size()); + assertTrue(modules.iterator().next() instanceof WorkloadManagementPluginModule); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java index b0ac1d78edbac..c2728a36e9196 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java @@ -16,12 +16,7 @@ import java.util.Map; public class WorkloadGroupFeatureTypeTests extends OpenSearchTestCase { - private WorkloadGroupFeatureType featureType; - - public void setUp() throws Exception { - super.setUp(); - featureType = WorkloadGroupFeatureType.INSTANCE; - } + WorkloadGroupFeatureType featureType = WorkloadGroupFeatureType.INSTANCE; public void testGetName_returnsCorrectName() { assertEquals("workload_group", featureType.getName());