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 c86490552f2f2..2eea15f2c697a 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,21 +18,26 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; import org.opensearch.core.action.ActionResponse; -import org.opensearch.plugin.wlm.action.CreateQueryGroupAction; -import org.opensearch.plugin.wlm.action.DeleteQueryGroupAction; -import org.opensearch.plugin.wlm.action.GetQueryGroupAction; -import org.opensearch.plugin.wlm.action.TransportCreateQueryGroupAction; -import org.opensearch.plugin.wlm.action.TransportDeleteQueryGroupAction; -import org.opensearch.plugin.wlm.action.TransportGetQueryGroupAction; -import org.opensearch.plugin.wlm.action.TransportUpdateQueryGroupAction; -import org.opensearch.plugin.wlm.action.UpdateQueryGroupAction; -import org.opensearch.plugin.wlm.rest.RestCreateQueryGroupAction; -import org.opensearch.plugin.wlm.rest.RestDeleteQueryGroupAction; -import org.opensearch.plugin.wlm.rest.RestGetQueryGroupAction; -import org.opensearch.plugin.wlm.rest.RestUpdateQueryGroupAction; -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +import org.opensearch.indices.SystemIndexDescriptor; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.TransportCreateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.TransportDeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.TransportGetQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.TransportUpdateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.rest.RestCreateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.rest.RestDeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.rest.RestGetQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.rest.RestUpdateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +import org.opensearch.plugin.wlm.rule.action.CreateRuleAction; +import org.opensearch.plugin.wlm.rule.action.TransportCreateRuleAction; +import org.opensearch.plugin.wlm.rule.rest.RestCreateRuleAction; 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.RULE_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,17 @@ public WorkloadManagementPlugin() {} new ActionPlugin.ActionHandler<>(CreateQueryGroupAction.INSTANCE, TransportCreateQueryGroupAction.class), new ActionPlugin.ActionHandler<>(GetQueryGroupAction.INSTANCE, TransportGetQueryGroupAction.class), new ActionPlugin.ActionHandler<>(DeleteQueryGroupAction.INSTANCE, TransportDeleteQueryGroupAction.class), - new ActionPlugin.ActionHandler<>(UpdateQueryGroupAction.INSTANCE, TransportUpdateQueryGroupAction.class) + new ActionPlugin.ActionHandler<>(UpdateQueryGroupAction.INSTANCE, TransportUpdateQueryGroupAction.class), + new ActionPlugin.ActionHandler<>(CreateRuleAction.INSTANCE, TransportCreateRuleAction.class) ); } + @Override + public Collection getSystemIndexDescriptors(Settings settings) { + List descriptors = List.of(new SystemIndexDescriptor(RULE_INDEX, "System index used for storing rules")); + return descriptors; + } + @Override public List getRestHandlers( Settings settings, @@ -74,7 +88,8 @@ public List getRestHandlers( new RestCreateQueryGroupAction(), new RestGetQueryGroupAction(), new RestDeleteQueryGroupAction(), - new RestUpdateQueryGroupAction() + new RestUpdateQueryGroupAction(), + new RestCreateRuleAction() ); } 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 b7c7805639eb2..9f1e0d5f5dab0 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,7 @@ import org.opensearch.common.inject.AbstractModule; import org.opensearch.common.inject.Singleton; -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; /** * Guice Module to manage WorkloadManagement related objects diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupAction.java index 14cb8cfcd125a..3ca7ba97366d1 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupAction.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/CreateQueryGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequest.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequest.java index 1ce04faa7ccc1..b122057da9485 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequest.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/CreateQueryGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponse.java index 9a2a8178c0a29..8616208eb2d9c 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponse.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.QueryGroup; import org.opensearch.core.action.ActionResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupAction.java index c78952a2f89ad..a953e9ff848a8 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupAction.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.master.AcknowledgedResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequest.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequest.java index e514943c2c7e9..37acd9a406ed6 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequest.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.master.AcknowledgedRequest; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupAction.java similarity index 93% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupAction.java index 0200185580f7d..e1ce81b3c1ed0 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupAction.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/GetQueryGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequest.java similarity index 96% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequest.java index 0524c615a84e7..2c9ceab5bf1dc 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequest.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/GetQueryGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponse.java index 547c501e6a28e..625cb423cd3f9 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponse.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.QueryGroup; import org.opensearch.core.action.ActionResponse; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java similarity index 95% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java index dff9c429d63b0..e6f3216d1045c 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.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,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.java similarity index 95% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.java index e4d3908d4a208..598cf574e0dcf 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.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; @@ -19,7 +19,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.java similarity index 96% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.java index 51bb21b255511..64f92e2ef1129 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.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,7 @@ import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.rest.RestStatus; -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; 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/TransportUpdateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.java similarity index 95% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.java index 09a0da7086b36..493ed6a56aeb5 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.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,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupAction.java similarity index 94% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupAction.java index ff472f206131c..ffc0c388b98c8 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupAction.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/UpdateQueryGroupRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequest.java similarity index 98% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequest.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequest.java index 18af58289be13..4c773d5ab9dc6 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequest.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequest.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/UpdateQueryGroupResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponse.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponse.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponse.java index 9071f52ecb5a7..694770bd63d12 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponse.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponse.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.QueryGroup; 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/RestCreateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java similarity index 89% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java index b0e0af4f9d17f..08a9c3ca4fcf6 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java @@ -6,15 +6,15 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.client.node.NodeClient; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; -import org.opensearch.plugin.wlm.action.CreateQueryGroupAction; -import org.opensearch.plugin.wlm.action.CreateQueryGroupRequest; -import org.opensearch.plugin.wlm.action.CreateQueryGroupResponse; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; 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/RestDeleteQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupAction.java similarity index 89% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupAction.java index 8ad621cf8a1e4..b6f532f79edba 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupAction.java @@ -6,11 +6,11 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.client.node.NodeClient; -import org.opensearch.plugin.wlm.action.DeleteQueryGroupAction; -import org.opensearch.plugin.wlm.action.DeleteQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.RestRequest; import org.opensearch.rest.action.RestToXContentListener; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java similarity index 88% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java index c87973e113138..b5b4c0e36e56d 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java @@ -6,14 +6,14 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.client.node.NodeClient; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.plugin.wlm.action.GetQueryGroupAction; -import org.opensearch.plugin.wlm.action.GetQueryGroupRequest; -import org.opensearch.plugin.wlm.action.GetQueryGroupResponse; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupResponse; 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/RestUpdateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java similarity index 89% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java index 55b4bc5a295c4..644d905d9cf53 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java @@ -6,15 +6,15 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.client.node.NodeClient; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; -import org.opensearch.plugin.wlm.action.UpdateQueryGroupAction; -import org.opensearch.plugin.wlm.action.UpdateQueryGroupRequest; -import org.opensearch.plugin.wlm.action.UpdateQueryGroupResponse; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; 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/service/QueryGroupPersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.java similarity index 97% rename from plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceService.java rename to plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.java index f9332ff3022dc..e71e10d17633e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.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,10 +27,10 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.action.ActionListener; import org.opensearch.core.rest.RestStatus; -import org.opensearch.plugin.wlm.action.CreateQueryGroupResponse; -import org.opensearch.plugin.wlm.action.DeleteQueryGroupRequest; -import org.opensearch.plugin.wlm.action.UpdateQueryGroupRequest; -import org.opensearch.plugin.wlm.action.UpdateQueryGroupResponse; +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; import org.opensearch.wlm.ResourceType; 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/CreateRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/CreateRuleAction.java new file mode 100644 index 0000000000000..b66d2e0c670ee --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/CreateRuleAction.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 create Rule + * @opensearch.experimental + */ +public class CreateRuleAction extends ActionType { + + /** + * An instance of CreateRuleAction + */ + public static final CreateRuleAction INSTANCE = new CreateRuleAction(); + + /** + * Name for CreateRuleAction + */ + public static final String NAME = "cluster:admin/opensearch/wlm/rule/_create"; + + /** + * Default constructor + */ + private CreateRuleAction() { + super(NAME, CreateRuleResponse::new); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/CreateRuleRequest.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/CreateRuleRequest.java new file mode 100644 index 0000000000000..f2a8ca8ed71b2 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/CreateRuleRequest.java @@ -0,0 +1,72 @@ +/* + * 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.core.xcontent.XContentParser; +import org.opensearch.wlm.Rule; +import org.opensearch.wlm.Rule.Builder; +import org.joda.time.Instant; + +import java.io.IOException; + +/** + * A request for create Rule + * @opensearch.experimental + */ +public class CreateRuleRequest extends ClusterManagerNodeRequest { + private final Rule rule; + + /** + * Constructor for CreateRuleRequest + * @param rule - A {@link Rule} object + */ + CreateRuleRequest(Rule rule) { + this.rule = rule; + } + + /** + * Constructor for CreateRuleRequest + * @param in - A {@link StreamInput} object + */ + CreateRuleRequest(StreamInput in) throws IOException { + super(in); + rule = new Rule(in); + } + + /** + * Generate a CreateRuleRequest from XContent + * @param parser - A {@link XContentParser} object + */ + public static CreateRuleRequest fromXContent(XContentParser parser) throws IOException { + Builder builder = Builder.fromXContent(parser); + return new CreateRuleRequest(builder.updatedAt(Instant.now().toString()).build()); + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + rule.writeTo(out); + } + + /** + * Rule getter + */ + public Rule getRule() { + return rule; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/CreateRuleResponse.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/CreateRuleResponse.java new file mode 100644 index 0000000000000..0405906786503 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/CreateRuleResponse.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.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 create API for Rule + * @opensearch.experimental + */ +public class CreateRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { + private final String _id; + private final Rule rule; + private final RestStatus restStatus; + + /** + * Constructor for CreateRuleResponse + * @param rule - The Rule to be included in the response + * @param restStatus - The restStatus for the response + */ + public CreateRuleResponse(String id, final Rule rule, RestStatus restStatus) { + this._id = id; + this.rule = rule; + this.restStatus = restStatus; + } + + /** + * Constructor for CreateRuleResponse + * @param in - A {@link StreamInput} object + */ + public CreateRuleResponse(StreamInput in) throws IOException { + _id = in.readString(); + rule = new Rule(in); + restStatus = RestStatus.readFrom(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(_id); + rule.writeTo(out); + RestStatus.writeTo(out, restStatus); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return rule.toXContent(builder, new MapParams(Map.of(_ID_STRING, _id))); + } + + /** + * rule getter + */ + public Rule getRule() { + return rule; + } + + /** + * restStatus getter + */ + public RestStatus getRestStatus() { + return restStatus; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportCreateRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportCreateRuleAction.java new file mode 100644 index 0000000000000..399065a1583ef --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportCreateRuleAction.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.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 create Rule + * @opensearch.experimental + */ +public class TransportCreateRuleAction extends HandledTransportAction { + + private final RulePersistenceService rulePersistenceService; + + /** + * Constructor for TransportCreateRuleAction + * + * @param transportService - a {@link TransportService} object + * @param actionFilters - a {@link ActionFilters} object + * @param rulePersistenceService - a {@link RulePersistenceService} object + */ + @Inject + public TransportCreateRuleAction( + TransportService transportService, + ActionFilters actionFilters, + RulePersistenceService rulePersistenceService + ) { + super(CreateRuleAction.NAME, transportService, actionFilters, CreateRuleRequest::new); + this.rulePersistenceService = rulePersistenceService; + } + + @Override + protected void doExecute(Task task, CreateRuleRequest request, ActionListener listener) { + rulePersistenceService.createRule(request.getRule(), 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/RestCreateRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestCreateRuleAction.java new file mode 100644 index 0000000000000..e567fd49429f7 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestCreateRuleAction.java @@ -0,0 +1,71 @@ +/* + * 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.core.xcontent.XContentParser; +import org.opensearch.plugin.wlm.rule.action.CreateRuleAction; +import org.opensearch.plugin.wlm.rule.action.CreateRuleRequest; +import org.opensearch.plugin.wlm.rule.action.CreateRuleResponse; +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 java.io.IOException; +import java.util.List; + +import static org.opensearch.rest.RestRequest.Method.POST; +import static org.opensearch.rest.RestRequest.Method.PUT; + +/** + * Rest action to create a Rule + * @opensearch.experimental + */ +public class RestCreateRuleAction extends BaseRestHandler { + + /** + * Constructor for RestCreateRuleAction + */ + public RestCreateRuleAction() {} + + @Override + public String getName() { + return "create_rule"; + } + + /** + * The list of {@link Route}s that this RestHandler is responsible for handling. + */ + @Override + public List routes() { + return List.of(new Route(POST, "_wlm/rule/"), new Route(PUT, "_wlm/rule/")); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + try (XContentParser parser = request.contentParser()) { + final CreateRuleRequest createRuleRequest = CreateRuleRequest.fromXContent(parser); + return channel -> client.execute(CreateRuleAction.INSTANCE, createRuleRequest, createRuleResponse(channel)); + } + } + + private RestResponseListener createRuleResponse(final RestChannel channel) { + return new RestResponseListener<>(channel) { + @Override + public RestResponse buildResponse(final CreateRuleResponse 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..918672855eaef --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceService.java @@ -0,0 +1,140 @@ +/* + * 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.ResourceAlreadyExistsException; +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.client.Client; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.common.xcontent.XContentFactory; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.plugin.wlm.rule.action.CreateRuleResponse; +import org.opensearch.wlm.Rule; + +import java.io.IOException; +import java.util.Map; + +/** + * 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 final ClusterService clusterService; + private static final Logger logger = LogManager.getLogger(RulePersistenceService.class); + + /** + * 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; + this.client = client; + } + + /** + * This method is the entry point for create rule logic in persistence service. + * @param rule - the rule that we're persisting + * @param listener - ActionListener for CreateRuleResponse + */ + public void createRule(Rule rule, ActionListener listener) { + createRuleIndexIfAbsent(new ActionListener<>() { + @Override + public void onResponse(Boolean indexCreated) { + persistRule(rule, listener); + } + + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + } + }); + } + + /** + * This method handles the core logic to save a rule to the system index. + * @param rule - the rule that we're persisting + * @param listener - ActionListener for CreateRuleResponse + */ + void persistRule(Rule rule, ActionListener listener) { + try (ThreadContext.StoredContext context = client.threadPool().getThreadContext().stashContext()) { + IndexRequest indexRequest = new IndexRequest(RULE_INDEX).source( + rule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) + ); + + client.index(indexRequest, ActionListener.wrap(indexResponse -> { + CreateRuleResponse createRuleResponse = new CreateRuleResponse(indexResponse.getId(), rule, RestStatus.OK); + listener.onResponse(createRuleResponse); + }, e -> { + logger.warn("Failed to save Rule object due to error: {}", e.getMessage()); + listener.onFailure(e); + })); + } catch (IOException e) { + logger.warn("Error saving rule to index: {}", e.getMessage()); + listener.onFailure(new RuntimeException("Failed to save rule to index.")); + } + } + + /** + * This method creates the rule system index if it's absent. + * @param listener - ActionListener for CreateRuleResponse + */ + void createRuleIndexIfAbsent(ActionListener listener) { + if (clusterService.state().metadata().hasIndex(RulePersistenceService.RULE_INDEX)) { + listener.onResponse(true); + return; + } + try (ThreadContext.StoredContext context = client.threadPool().getThreadContext().stashContext()) { + final Map indexSettings = Map.of("index.number_of_shards", 1, "index.auto_expand_replicas", "0-all"); + final CreateIndexRequest createIndexRequest = new CreateIndexRequest(RulePersistenceService.RULE_INDEX).settings(indexSettings); + client.admin().indices().create(createIndexRequest, new ActionListener<>() { + @Override + public void onResponse(CreateIndexResponse response) { + logger.info("Index {} created?: {}", RulePersistenceService.RULE_INDEX, response.isAcknowledged()); + listener.onResponse(response.isAcknowledged()); + } + + @Override + public void onFailure(Exception e) { + if (e instanceof ResourceAlreadyExistsException) { + logger.info("Index {} already exists", RulePersistenceService.RULE_INDEX); + listener.onResponse(true); + } else { + logger.error("Failed to create index {}: {}", RulePersistenceService.RULE_INDEX, e.getMessage()); + listener.onFailure(e); + } + } + }); + } + } + + /** + * client getter + */ + public Client getClient() { + return client; + } + + /** + * clusterService getter + */ + public ClusterService getClusterService() { + return clusterService; + } +} 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/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java index c6eb3140e943d..fcaeec4571d68 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java @@ -19,7 +19,7 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.wlm.MutableQueryGroupFragment; import org.opensearch.wlm.ResourceType; 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..e04f2be3fe24f --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/RuleTestUtils.java @@ -0,0 +1,85 @@ +/* + * 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.cluster.service.ClusterService; +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); + 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(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.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/CreateQueryGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequestTests.java similarity index 96% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequestTests.java index dd9de4bf8fb1a..a20f027f09e15 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequestTests.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.QueryGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponseTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponseTests.java index 3a2ce215d21b5..fb6141fc65082 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponseTests.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.QueryGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequestTests.java similarity index 96% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequestTests.java index bc2e4f0faca4c..c91742cc3609a 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequestTests.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/GetQueryGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequestTests.java similarity index 97% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequestTests.java index 32b5f7ec9e2c3..3a96a58fe88ed 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequestTests.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/GetQueryGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponseTests.java similarity index 99% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponseTests.java index 1a2ac282d86a4..95c4422f92e5f 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponseTests.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.QueryGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/QueryGroupActionTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/QueryGroupActionTestUtils.java similarity index 90% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/QueryGroupActionTestUtils.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/QueryGroupActionTestUtils.java index 08d128ca7ed59..87c768b056e4e 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/QueryGroupActionTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/QueryGroupActionTestUtils.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.wlm.MutableQueryGroupFragment; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.java similarity index 94% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.java index 253d65f8da80f..e40fc9985dbb0 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.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.master.AcknowledgedResponse; @@ -14,7 +14,7 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.action.ActionListener; -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; 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/TransportGetQueryGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupActionTests.java similarity index 97% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupActionTests.java index 755b11a5f4b89..5ddd8ec4e29cc 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupActionTests.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/UpdateQueryGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequestTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequestTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequestTests.java index b99f079e81984..3175c0a812287 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequestTests.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/UpdateQueryGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java similarity index 98% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponseTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java index a7ab4c6a682ef..3f0bde66699b1 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.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.QueryGroup; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java similarity index 94% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupActionTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java index 72191e076bb87..9f97f666a2e4e 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java @@ -6,14 +6,14 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rest; +package org.opensearch.plugin.wlm.querygroup.rest; import org.opensearch.action.support.master.AcknowledgedResponse; import org.opensearch.client.node.NodeClient; import org.opensearch.common.CheckedConsumer; import org.opensearch.common.unit.TimeValue; -import org.opensearch.plugin.wlm.action.DeleteQueryGroupAction; -import org.opensearch.plugin.wlm.action.DeleteQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; 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/QueryGroupPersistenceServiceTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceServiceTests.java similarity index 97% rename from plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceServiceTests.java rename to plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceServiceTests.java index 08b51fd46cfcf..a0b6a0e8a77bc 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceServiceTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceServiceTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.service; +package org.opensearch.plugin.wlm.querygroup.service; import org.opensearch.ResourceNotFoundException; import org.opensearch.action.support.master.AcknowledgedResponse; @@ -22,10 +22,10 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.action.ActionListener; import org.opensearch.plugin.wlm.QueryGroupTestUtils; -import org.opensearch.plugin.wlm.action.CreateQueryGroupResponse; -import org.opensearch.plugin.wlm.action.DeleteQueryGroupRequest; -import org.opensearch.plugin.wlm.action.UpdateQueryGroupRequest; -import org.opensearch.plugin.wlm.action.UpdateQueryGroupResponse; +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.test.OpenSearchTestCase; import org.opensearch.threadpool.ThreadPool; import org.opensearch.wlm.MutableQueryGroupFragment; @@ -58,9 +58,9 @@ import static org.opensearch.plugin.wlm.QueryGroupTestUtils.queryGroupOne; import static org.opensearch.plugin.wlm.QueryGroupTestUtils.queryGroupPersistenceService; import static org.opensearch.plugin.wlm.QueryGroupTestUtils.queryGroupTwo; -import static org.opensearch.plugin.wlm.action.QueryGroupActionTestUtils.updateQueryGroupRequest; -import static org.opensearch.plugin.wlm.service.QueryGroupPersistenceService.QUERY_GROUP_COUNT_SETTING_NAME; -import static org.opensearch.plugin.wlm.service.QueryGroupPersistenceService.SOURCE; +import static org.opensearch.plugin.wlm.querygroup.action.QueryGroupActionTestUtils.updateQueryGroupRequest; +import static org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService.QUERY_GROUP_COUNT_SETTING_NAME; +import static org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService.SOURCE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.anyString; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/CreateRuleRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/CreateRuleRequestTests.java new file mode 100644 index 0000000000000..991eaec158b17 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/CreateRuleRequestTests.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.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 java.io.IOException; + +import static org.opensearch.plugin.wlm.RuleTestUtils.assertEqualRule; +import static org.opensearch.plugin.wlm.RuleTestUtils.ruleOne; + +public class CreateRuleRequestTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of CreateRuleRequest. + */ + public void testSerialization() throws IOException { + CreateRuleRequest request = new CreateRuleRequest(ruleOne); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + CreateRuleRequest otherRequest = new CreateRuleRequest(streamInput); + assertEqualRule(ruleOne, otherRequest.getRule(), false); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/CreateRuleResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/CreateRuleResponseTests.java new file mode 100644 index 0000000000000..d24f3207eda4b --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/action/CreateRuleResponseTests.java @@ -0,0 +1,62 @@ +/* + * 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.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.mockito.Mockito.mock; + +public class CreateRuleResponseTests extends OpenSearchTestCase { + + /** + * Test case to verify serialization and deserialization of CreateRuleResponse + */ + public void testSerialization() throws IOException { + CreateRuleResponse response = new CreateRuleResponse(_ID_ONE, ruleOne, RestStatus.OK); + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + CreateRuleResponse otherResponse = new CreateRuleResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + Rule responseRule = response.getRule(); + Rule otherResponseRule = otherResponse.getRule(); + assertEqualRules(Map.of(_ID_ONE, responseRule), Map.of(_ID_ONE, otherResponseRule), false); + } + + /** + * Test case to validate the toXContent method of CreateRuleResponse + */ + public void testToXContentCreateRule() throws IOException { + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + CreateRuleResponse response = new CreateRuleResponse(_ID_ONE, ruleOne, RestStatus.OK); + String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\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" + + "}"; + assertEquals(expected, actual); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestCreateRuleActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestCreateRuleActionTests.java new file mode 100644 index 0000000000000..dbe7a7ef6661f --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestCreateRuleActionTests.java @@ -0,0 +1,36 @@ +/* + * 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.POST; +import static org.opensearch.rest.RestRequest.Method.PUT; + +public class RestCreateRuleActionTests extends OpenSearchTestCase { + /** + * Test case to validate the construction for RestCreateRuleAction + */ + public void testConstruction() { + RestCreateRuleAction action = new RestCreateRuleAction(); + assertNotNull(action); + assertEquals("create_rule", action.getName()); + List routes = action.routes(); + assertEquals(2, routes.size()); + RestHandler.Route route = routes.get(0); + assertEquals(POST, route.getMethod()); + assertEquals("_wlm/rule/", route.getPath()); + route = routes.get(1); + assertEquals(PUT, route.getMethod()); + assertEquals("_wlm/rule/", 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..1f82a7e963395 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/service/RulePersistenceServiceTests.java @@ -0,0 +1,85 @@ +/* + * 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.action.index.IndexRequest; +import org.opensearch.action.index.IndexResponse; +import org.opensearch.client.Client; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.metadata.Metadata; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.index.shard.ShardId; +import org.opensearch.plugin.wlm.rule.action.CreateRuleResponse; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.wlm.Rule; + +import java.io.IOException; + +import org.mockito.ArgumentCaptor; + +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.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@SuppressWarnings("unchecked") +public class RulePersistenceServiceTests extends OpenSearchTestCase { + + public void testCreateRuleIndexIfAbsent() { + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); + Client client = rulePersistenceService.getClient(); + ClusterService clusterService = rulePersistenceService.getClusterService(); + Metadata metadata = mock(Metadata.class); + ClusterState clusterState = mock(ClusterState.class); + ActionListener listener = mock(ActionListener.class); + + when(clusterService.state()).thenReturn(clusterState); + when(clusterState.metadata()).thenReturn(metadata); + when(metadata.hasIndex(RulePersistenceService.RULE_INDEX)).thenReturn(true); + + rulePersistenceService.createRuleIndexIfAbsent(listener); + verify(listener).onResponse(true); + verify(client, never()).admin(); + } + + /** + * Test case to validate the creation logic of a Rule + */ + public void testPersistRule() throws IOException { + ActionListener listener = mock(ActionListener.class); + RulePersistenceService rulePersistenceService = setUpRulePersistenceService(); + Client client = rulePersistenceService.getClient(); + IndexResponse indexResponse = new IndexResponse(new ShardId(RULE_INDEX, "uuid", 0), "id", 1, 1, 1, true); + doAnswer(invocation -> { + ActionListener actionListener = invocation.getArgument(1); + actionListener.onResponse(indexResponse); + return null; + }).when(client).index(any(IndexRequest.class), any(ActionListener.class)); + + rulePersistenceService.persistRule(ruleOne, listener); + verify(client).index(any(IndexRequest.class), any(ActionListener.class)); + ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(CreateRuleResponse.class); + verify(listener).onResponse(responseCaptor.capture()); + + CreateRuleResponse createRuleResponse = responseCaptor.getValue(); + assertNotNull(createRuleResponse); + Rule rule = createRuleResponse.getRule(); + assertEquals(rule.getFeature(), ruleOne.getFeature()); + assertEquals(rule.getLabel(), ruleOne.getLabel()); + assertEquals(rule.getAttributeMap(), ruleOne.getAttributeMap()); + clearInvocations(client, 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() + ); + } +}