From 4b9002703774ed0522c035737422be2259fa7636 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Wed, 12 Mar 2025 13:52:18 -0700 Subject: [PATCH 01/11] rebase add update rule api logic Signed-off-by: Ruirui Zhang --- .../rule/action/CreateRuleResponse.java | 81 +++ .../rule/action/GetRuleResponse.java | 103 ++++ .../rule/action/UpdateRuleRequest.java | 114 ++++ .../rule/action/UpdateRuleResponse.java | 86 +++ .../opensearch/rule/action/package-info.java | 12 + .../rule/rest/RestUpdateRuleAction.java | 97 ++++ .../opensearch/rule/rest/package-info.java | 12 + .../IndexStoredRulePersistenceService.java | 276 ++++++++++ .../rule/service/RulePersistenceService.java | 26 + .../opensearch/rule/service/package-info.java | 13 + .../rule/utils/IndexStoredRuleParser.java | 51 ++ .../rule/utils/IndexStoredRuleUtils.java | 104 ++++ .../opensearch/rule/utils/package-info.java | 12 + .../rule/action/UpdateRuleRequestTests.java | 60 ++ .../rule/action/UpdateRuleResponseTests.java | 62 +++ ...ndexStoredRulePersistenceServiceTests.java | 69 +++ .../utils/IndexStoredRuleParserTests.java | 52 ++ .../rule/utils/IndexStoredRuleUtilsTests.java | 100 ++++ .../opensearch/rule/utils/RuleTestUtils.java | 157 ++++++ .../org/opensearch/rule/autotagging/Rule.java | 4 + .../rule/autotagging/RuleValidator.java | 18 + .../wlm/WorkloadManagementPluginModule.java | 3 + .../wlm/action/CreateQueryGroupAction.java | 36 ++ .../wlm/action/CreateQueryGroupRequest.java | 82 +++ .../wlm/action/CreateQueryGroupResponse.java | 74 +++ .../wlm/action/DeleteQueryGroupAction.java | 38 ++ .../wlm/action/DeleteQueryGroupRequest.java | 65 +++ .../wlm/action/GetQueryGroupAction.java | 36 ++ .../wlm/action/GetQueryGroupRequest.java | 64 +++ .../wlm/action/GetQueryGroupResponse.java | 82 +++ .../TransportCreateQueryGroupAction.java | 95 ++++ .../TransportCreateWorkloadGroupAction.java | 4 + .../TransportDeleteQueryGroupAction.java | 97 ++++ .../TransportDeleteWorkloadGroupAction.java | 4 + .../action/TransportGetQueryGroupAction.java | 107 ++++ .../TransportGetWorkloadGroupAction.java | 4 + .../TransportUpdateQueryGroupAction.java | 96 ++++ .../TransportUpdateWorkloadGroupAction.java | 4 + .../wlm/action/UpdateQueryGroupAction.java | 36 ++ .../wlm/action/UpdateQueryGroupRequest.java | 83 +++ .../wlm/action/UpdateQueryGroupResponse.java | 74 +++ .../wlm/rest/RestCreateQueryGroupAction.java | 82 +++ .../rest/RestCreateWorkloadGroupAction.java | 5 + .../wlm/rest/RestDeleteQueryGroupAction.java | 66 +++ .../rest/RestDeleteWorkloadGroupAction.java | 5 + .../wlm/rest/RestGetQueryGroupAction.java | 74 +++ .../wlm/rest/RestGetWorkloadGroupAction.java | 6 + .../wlm/rest/RestUpdateQueryGroupAction.java | 81 +++ .../rest/RestUpdateWorkloadGroupAction.java | 6 + .../plugin/wlm/rule/QueryGroupAttribute.java | 61 +++ .../wlm/rule/QueryGroupFeatureType.java | 64 +++ .../action/TransportUpdateWlmRuleAction.java | 58 ++ .../wlm/rule/action/UpdateWlmRuleAction.java | 37 ++ .../plugin/wlm/rule/action/package-info.java | 12 + .../rule/rest/RestUpdateWlmRuleAction.java | 70 +++ .../plugin/wlm/rule/rest/package-info.java | 12 + .../service/QueryGroupPersistenceService.java | 372 +++++++++++++ .../WorkloadGroupPersistenceService.java | 7 + .../plugin/wlm/QueryGroupTestUtils.java | 172 ++++++ .../plugin/wlm/WorkloadGroupTestUtils.java | 6 +- .../action/CreateQueryGroupRequestTests.java | 46 ++ .../action/CreateQueryGroupResponseTests.java | 71 +++ .../CreateWorkloadGroupRequestTests.java | 8 +- .../CreateWorkloadGroupResponseTests.java | 5 + .../action/DeleteQueryGroupRequestTests.java | 47 ++ .../DeleteWorkloadGroupRequestTests.java | 5 + .../wlm/action/GetQueryGroupRequestTests.java | 58 ++ .../action/GetQueryGroupResponseTests.java | 156 ++++++ .../action/GetWorkloadGroupRequestTests.java | 5 + .../action/GetWorkloadGroupResponseTests.java | 5 + .../wlm/action/QueryGroupActionTestUtils.java | 18 + .../TransportDeleteQueryGroupActionTests.java | 69 +++ ...ansportDeleteWorkloadGroupActionTests.java | 6 + .../TransportGetQueryGroupActionTests.java | 59 ++ .../TransportGetWorkloadGroupActionTests.java | 8 + .../action/UpdateQueryGroupRequestTests.java | 105 ++++ .../action/UpdateQueryGroupResponseTests.java | 76 +++ .../UpdateWorkloadGroupRequestTests.java | 7 +- .../UpdateWorkloadGroupResponseTests.java | 9 + .../rest/RestDeleteQueryGroupActionTests.java | 95 ++++ .../RestDeleteWorkloadGroupActionTests.java | 10 + .../rest/RestUpdateWlmRuleActionTests.java | 37 ++ .../QueryGroupPersistenceServiceTests.java | 515 ++++++++++++++++++ 83 files changed, 5206 insertions(+), 3 deletions(-) create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java create mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java create mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequest.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponse.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequest.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequest.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponse.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequest.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponse.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/UpdateWlmRuleAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleAction.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java create mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceService.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequestTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponseTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequestTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequestTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponseTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/QueryGroupActionTestUtils.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupActionTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupActionTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequestTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponseTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupActionTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleActionTests.java create mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceServiceTests.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java new file mode 100644 index 0000000000000..aef3936c554c3 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java @@ -0,0 +1,81 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.autotagging.Rule; +import org.opensearch.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 java.io.IOException; +import java.util.Map; + +import static org.opensearch.autotagging.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; + + /** + * contructor for CreateRuleResponse + * @param id - the id for the rule created + * @param rule - the rule created + * @param restStatus - the status of CreateRuleResponse + */ + public CreateRuleResponse(String id, final Rule rule, RestStatus restStatus) { + this._id = id; + this.rule = rule; + this.restStatus = restStatus; + } + + /** + * Constructs a CreateRuleResponse from a StreamInput for deserialization + * @param in - The {@link StreamInput} instance to read from. + */ + 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/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java new file mode 100644 index 0000000000000..110522ff86af6 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java @@ -0,0 +1,103 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.autotagging.Rule; +import org.opensearch.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 java.io.IOException; +import java.util.Map; + +import static org.opensearch.autotagging.Rule._ID_STRING; + +/** + * Response for the get API for Rule. + * Example response: + * { + * "rules": [ + * { + * "_id": "z1MJApUB0zgMcDmz-UQq", + * "description": "Rule for tagging query_group_id to index123" + * "index_pattern": ["index123"], + * "query_group": "query_group_id", + * "updated_at": "2025-02-14T01:19:22.589Z" + * }, + * ... + * ], + * "search_after": ["z1MJApUB0zgMcDmz-UQq"] + * } + * @opensearch.experimental + */ +public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { + private final Map rules; + private final String searchAfter; + private final RestStatus restStatus; + + /** + * Constructor for GetRuleResponse + * @param rules - Rules get from the request + * @param searchAfter - The sort value used for pagination. + * @param restStatus - Status of the GetRuleResponse + */ + public GetRuleResponse(final Map rules, String searchAfter, RestStatus restStatus) { + this.rules = rules; + this.searchAfter = searchAfter; + this.restStatus = restStatus; + } + + /** + * Constructs a GetRuleResponse from a StreamInput for deserialization + * @param in - The {@link StreamInput} instance to read from. + */ + public GetRuleResponse(StreamInput in) throws IOException { + this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString(), RestStatus.readFrom(in)); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeMap(rules, StreamOutput::writeString, (outStream, rule) -> rule.writeTo(outStream)); + out.writeOptionalString(searchAfter); + RestStatus.writeTo(out, restStatus); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.startArray("rules"); + for (Map.Entry entry : rules.entrySet()) { + entry.getValue().toXContent(builder, new MapParams(Map.of(_ID_STRING, entry.getKey()))); + } + builder.endArray(); + if (searchAfter != null && !searchAfter.isEmpty()) { + builder.field("search_after", new Object[] { searchAfter }); + } + builder.endObject(); + return builder; + } + + /** + * rules getter + */ + public Map getRules() { + return rules; + } + + /** + * restStatus getter + */ + public RestStatus getRestStatus() { + return restStatus; + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java new file mode 100644 index 0000000000000..ffd029f9cd996 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java @@ -0,0 +1,114 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.RuleValidator; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A request for update Rule + * @opensearch.experimental + */ +public class UpdateRuleRequest extends ActionRequest { + private final String _id; + private final String description; + private final Map> attributeMap; + private final String featureValue; + private final FeatureType featureType; + + /** + * constructor for UpdateRuleRequest + * @param _id - the rule id to update + * @param description - the description to update + * @param attributeMap - the attribute values to update + * @param featureValue - the feature value to update + * @param featureType - the feature type for the rule + */ + public UpdateRuleRequest( + String _id, + String description, + Map> attributeMap, + String featureValue, + FeatureType featureType + ) { + this._id = _id; + this.description = description; + this.attributeMap = attributeMap; + this.featureValue = featureValue; + this.featureType = featureType; + } + + /** + * Constructs a UpdateRuleRequest from a StreamInput for deserialization + * @param in - The {@link StreamInput} instance to read from. + */ + public UpdateRuleRequest(StreamInput in) throws IOException { + super(in); + _id = in.readString(); + description = in.readOptionalString(); + featureType = FeatureType.from(in); + attributeMap = in.readMap(i -> Attribute.from(i, featureType), i -> new HashSet<>(i.readStringList())); + featureValue = in.readOptionalString(); + } + + @Override + public ActionRequestValidationException validate() { + RuleValidator validator = new RuleValidator(description, attributeMap, featureValue, null, featureType); + validator.validateUpdatingRuleParams(); + return null; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeString(_id); + out.writeOptionalString(description); + featureType.writeTo(out); + out.writeMap(attributeMap, (o, a) -> a.writeTo(o), StreamOutput::writeStringCollection); + out.writeOptionalString(featureValue); + } + + /** + * id getter + */ + public String get_id() { + return _id; + } + + /** + * description getter + */ + public String getDescription() { + return description; + } + + /** + * attributeMap getter + */ + public Map> getAttributeMap() { + return attributeMap; + } + + /** + * featureValue getter + */ + public String getFeatureValue() { + return featureValue; + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java new file mode 100644 index 0000000000000..005d587b02fb3 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java @@ -0,0 +1,86 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.autotagging.Rule; +import org.opensearch.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 java.io.IOException; +import java.util.Map; + +import static org.opensearch.autotagging.Rule._ID_STRING; + +/** + * Response for the update API for Rule + * @opensearch.experimental + */ +public class UpdateRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { + private final String _id; + private final Rule rule; + private final RestStatus restStatus; + + /** + * constructor for UpdateRuleResponse + * @param _id - rule id updated + * @param rule - the updated rule + * @param restStatus - the status of UpdateRuleResponse + */ + public UpdateRuleResponse(String _id, final Rule rule, RestStatus restStatus) { + this._id = _id; + this.rule = rule; + this.restStatus = restStatus; + } + + /** + * Constructs a UpdateRuleResponse from a StreamInput for deserialization + * @param in - The {@link StreamInput} instance to read from. + */ + public UpdateRuleResponse(StreamInput in) throws IOException { + this(in.readString(), new Rule(in), 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))); + } + + /** + * id getter + */ + public String get_id() { + return _id; + } + + /** + * rule getter + */ + public Rule getRule() { + return rule; + } + + /** + * restStatus getter + */ + public RestStatus getRestStatus() { + return restStatus; + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java new file mode 100644 index 0000000000000..91913aff23eac --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * This package contains abstract action classes for rules + */ +package org.opensearch.rule.action; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java new file mode 100644 index 0000000000000..9f52503884cbc --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java @@ -0,0 +1,97 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.rest; + +import org.opensearch.action.ActionType; +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule.Builder; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestResponse; +import org.opensearch.rest.action.RestResponseListener; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; +import org.opensearch.transport.client.node.NodeClient; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.autotagging.Rule._ID_STRING; + +/** + * Rest action to update a Rule + * @opensearch.experimental + */ +public abstract class RestUpdateRuleAction extends BaseRestHandler { + /** + * constructor for RestUpdateRuleAction + */ + public RestUpdateRuleAction() {} + + @Override + public abstract String getName(); + + @Override + public abstract List routes(); + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + try (XContentParser parser = request.contentParser()) { + Builder builder = Builder.fromXContent(parser, retrieveFeatureTypeInstance()); + UpdateRuleRequest updateRuleRequest = buildUpdateRuleRequest( + request.param(_ID_STRING), + builder.getDescription(), + builder.getAttributeMap(), + builder.getFeatureValue() + ); + return channel -> client.execute(retrieveUpdateRuleActionInstance(), updateRuleRequest, updateRuleResponse(channel)); + } + } + + private RestResponseListener updateRuleResponse(final RestChannel channel) { + return new RestResponseListener<>(channel) { + @Override + public RestResponse buildResponse(final UpdateRuleResponse response) throws Exception { + return new BytesRestResponse(RestStatus.OK, response.toXContent(channel.newBuilder(), ToXContent.EMPTY_PARAMS)); + } + }; + } + + /** + * Abstract method for subclasses to provide specific ActionType Instance + */ + protected abstract > T retrieveUpdateRuleActionInstance(); + + /** + * Abstract method for subclasses to provide specific FeatureType Instance + */ + protected abstract FeatureType retrieveFeatureTypeInstance(); + + /** + * Abstract method for subclasses to provide implementation to updateRuleRequest + * @param id - rule id to update + * @param description - rule description to update + * @param attributeMap - rule attributes to update + * @param featureValue - rule feature value to update + */ + protected abstract UpdateRuleRequest buildUpdateRuleRequest( + String id, + String description, + Map> attributeMap, + String featureValue + ); +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java new file mode 100644 index 0000000000000..c1000b90b1856 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * This package contains abstract rest classes for rules + */ +package org.opensearch.rule.rest; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java new file mode 100644 index 0000000000000..31722c96c77ed --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -0,0 +1,276 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.service; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.index.IndexRequest; +import org.opensearch.action.search.SearchRequestBuilder; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.action.update.UpdateRequest; +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.cluster.service.ClusterService; +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.index.query.BoolQueryBuilder; +import org.opensearch.rule.action.CreateRuleResponse; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; +import org.opensearch.rule.utils.IndexStoredRuleParser; +import org.opensearch.rule.utils.IndexStoredRuleUtils; +import org.opensearch.search.SearchHit; +import org.opensearch.search.sort.SortOrder; +import org.opensearch.transport.client.Client; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.opensearch.autotagging.Rule._ID_STRING; + +/** + * This class encapsulates the logic to manage the lifecycle of rules at index level + * @opensearch.experimental + */ +public class IndexStoredRulePersistenceService implements RulePersistenceService { + /** + * The system index name used for storing rules + */ + private final String indexName; + private final ClusterService clusterService; + private final Client client; + private final FeatureType featureType; + private final int maxRulesPerPage; + private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); + + /** + * Constructs an instance of {@link IndexStoredRulePersistenceService} with the specified parameters. + * This service handles persistence and retrieval of stored rules within an OpenSearch index. + * @param indexName - The name of the OpenSearch index where the rules are stored. + * @param clusterService - The clusterService used in IndexStoredRulePersistenceService. + * @param client - The OpenSearch client used to interact with the OpenSearch cluster. + * @param featureType - The feature type associated with the stored rules. + * @param maxRulesPerPage - The maximum number of rules that can be returned in a single get request. + */ + public IndexStoredRulePersistenceService( + String indexName, + ClusterService clusterService, + Client client, + FeatureType featureType, + int maxRulesPerPage + ) { + this.indexName = indexName; + this.clusterService = clusterService; + this.client = client; + this.featureType = featureType; + this.maxRulesPerPage = maxRulesPerPage; + } + + /** + * Entry point for the update rule api logic in persistence service. + * @param request - The UpdateRuleRequest + * @param listener - ActionListener for UpdateRuleResponse + */ + public void updateRule(UpdateRuleRequest request, ActionListener listener) { + String ruleId = request.get_id(); + try (ThreadContext.StoredContext context = getContext()) { + getRuleFromIndex(ruleId, new HashMap<>(), null, new ActionListener<>() { + @Override + public void onResponse(GetRuleResponse getRuleResponse) { + if (getRuleResponse == null || getRuleResponse.getRules().isEmpty()) { + listener.onFailure(new ResourceNotFoundException("Rule with ID " + ruleId + " not found.")); + return; + } + Rule updatedRule = IndexStoredRuleUtils.composeUpdatedRule( + getRuleResponse.getRules().get(ruleId), + request, + featureType + ); + checkDuplicateRule(updatedRule, new ActionListener<>() { + @Override + public void onResponse(CreateRuleResponse createRuleResponse) { + persistUpdatedRule(ruleId, updatedRule, listener); + } + + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + } + }); + } + + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + } + }); + } + } + + /** + * Check if there's an existing Rule with the same attributes. + * For example, if there's an existing Rule with the attribute index_pattern: ["a", "b", "c"], + * then we cannot create another Rule with only one attribute index_pattern: ["b"], because the value "b" + * already exists under another Rule. Note that the conflict exists only when we have the exact same attribute + * names in the two rules (That is, a Rule with attribute "index_pattern" won't create a conflict with another + * Rule that has "index_pattern" and some other attributes). + * @param rule - The rule to update. + * @param listener - ActionListener for CreateRuleResponse + */ + public void checkDuplicateRule(Rule rule, ActionListener listener) { + try (ThreadContext.StoredContext ctx = getContext()) { + getRuleFromIndex(null, rule.getAttributeMap(), null, new ActionListener<>() { + @Override + public void onResponse(GetRuleResponse getRuleResponse) { + Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId( + rule.getAttributeMap(), + getRuleResponse.getRules() + ); + duplicateRuleId.map(id -> { + listener.onFailure( + new IllegalArgumentException("A rule that has the same attribute values already exists under rule id " + id) + ); + return null; + }).orElseGet(() -> { + persistRule(rule, listener); + return null; + }); + } + + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + } + }); + } + } + + /** + * Persist the updated rule in index + * @param ruleId - the rule id to update + * @param updatedRule - the rule we update to + * @param listener - ActionListener for UpdateRuleResponse + */ + public void persistUpdatedRule(String ruleId, Rule updatedRule, ActionListener listener) { + try (ThreadContext.StoredContext context = getContext()) { + UpdateRequest updateRequest = new UpdateRequest(indexName, ruleId).doc( + updatedRule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) + ); + client.update(updateRequest, ActionListener.wrap(updateResponse -> { + listener.onResponse(new UpdateRuleResponse(ruleId, updatedRule, RestStatus.OK)); + }, e -> { + logger.warn("Failed to update Rule object due to error: {}", e.getMessage()); + listener.onFailure(e); + })); + } catch (IOException e) { + logger.error("Error updating rule in index: {}", indexName); + listener.onFailure(new RuntimeException("Failed to update rule to index.")); + } + } + + /** + * Persist the rule in the index + * @param rule - The rule to update. + * @param listener - ActionListener for CreateRuleResponse + */ + public void persistRule(Rule rule, ActionListener listener) { + try (ThreadContext.StoredContext ctx = getContext()) { + IndexRequest indexRequest = new IndexRequest(indexName).source( + rule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) + ); + client.index(indexRequest, ActionListener.wrap(indexResponse -> { + listener.onResponse(new CreateRuleResponse(indexResponse.getId(), rule, RestStatus.OK)); + }, e -> { + logger.warn("Failed to save Rule object due to error: {}", e.getMessage()); + listener.onFailure(e); + })); + } catch (IOException e) { + logger.error("Error saving rule to index: {}", indexName); + listener.onFailure(new RuntimeException("Failed to save rule to index.")); + } + } + + /** + * Entry point for the get rule api logic in persistence service. If id is provided, we only get a single rule. + * Otherwise, we get all rules that satisfy the attributeFilters. + * @param id - The id of the rule to get. + * @param attributeFilters - A map containing the attributes that user want to filter on + * @param searchAfter - The sort values from the last document of the previous page, used for pagination + * @param listener - ActionListener for GetRuleResponse + */ + public void getRuleFromIndex( + String id, + Map> attributeFilters, + String searchAfter, + ActionListener listener + ) { + // Stash the current thread context when interacting with system index to perform + // operations as the system itself, bypassing authorization checks. This ensures that + // actions within this block are trusted and executed with system-level privileges. + try (ThreadContext.StoredContext context = getContext()) { + BoolQueryBuilder boolQuery = IndexStoredRuleUtils.buildGetRuleQuery(id, attributeFilters, featureType); + SearchRequestBuilder searchRequest = client.prepareSearch(indexName).setQuery(boolQuery).setSize(maxRulesPerPage); + if (searchAfter != null) { + searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); + } + searchRequest.execute(ActionListener.wrap(searchResponse -> handleGetRuleResponse(id, searchResponse, listener), e -> { + logger.error("Failed to fetch all rules: {}", e.getMessage()); + listener.onFailure(e); + })); + } + } + + /** + * Process searchResponse from index and send a GetRuleResponse + * @param searchResponse - Response received from index + * @param listener - ActionListener for GetRuleResponse + */ + void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { + List hits = Arrays.asList(searchResponse.getHits().getHits()); + if (id != null && hits.isEmpty()) { + logger.error("Rule with ID " + id + " not found."); + listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " doesn't exist in the .rules index.")); + return; + } + Map ruleMap = hits.stream() + .collect(Collectors.toMap(SearchHit::getId, hit -> IndexStoredRuleParser.parseRule(hit.getSourceAsString(), featureType))); + String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); + listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); + } + + private ThreadContext.StoredContext getContext() { + return client.threadPool().getThreadContext().stashContext(); + } + + /** + * client getter + */ + public Client getClient() { + return client; + } + + /** + * clusterService getter + */ + public ClusterService getClusterService() { + return clusterService; + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java new file mode 100644 index 0000000000000..f0264e8829536 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.service; + +import org.opensearch.core.action.ActionListener; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; + +/** + * Interface for a service that handles rule persistence CRUD operations. + * @opensearch.experimental + */ +public interface RulePersistenceService { + /** + * Update rule based on the provided request. + * @param request The request containing the details for updating the rule. + * @param listener The listener that will handle the response or failure. + */ + void updateRule(UpdateRuleRequest request, ActionListener listener); +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java new file mode 100644 index 0000000000000..a1ec9ea7c8521 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java @@ -0,0 +1,13 @@ + +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * This package contains abstract service classes for rules + */ +package org.opensearch.rule.service; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java new file mode 100644 index 0000000000000..4d2e808a22c2d --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.utils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.core.xcontent.DeprecationHandler; +import org.opensearch.core.xcontent.MediaTypeRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.core.xcontent.XContentParser; + +import java.io.IOException; + +/** + * Utility class for parsing index stored rules into Rule objects. + * @opensearch.experimental + */ +public class IndexStoredRuleParser { + + /** + * constructor for IndexStoredRuleParser + */ + public IndexStoredRuleParser() {} + + private static final Logger logger = LogManager.getLogger(IndexStoredRuleParser.class); + + /** + * Parses a source string into a Rule object + * @param source - The raw source string representing the rule to be parsed + * @param featureType - The feature type to associate with the parsed rule + */ + public static Rule parseRule(String source, FeatureType featureType) { + try ( + XContentParser parser = MediaTypeRegistry.JSON.xContent() + .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source) + ) { + return Rule.Builder.fromXContent(parser, featureType).build(); + } catch (IOException e) { + logger.info("Issue met when parsing rule {}: {}", source, e.getMessage()); + throw new RuntimeException("Cannot parse rule from index: " + source); + } + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java new file mode 100644 index 0000000000000..f27969e259128 --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java @@ -0,0 +1,104 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.utils; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.rule.action.UpdateRuleRequest; + +import java.time.Instant; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static org.opensearch.autotagging.Rule._ID_STRING; + +/** + * Utility class that provides methods for the lifecycle of rules. + * @opensearch.experimental + */ +public class IndexStoredRuleUtils { + + /** + * constructor for IndexStoredRuleUtils + */ + public IndexStoredRuleUtils() {} + + /** + * Builds a Boolean query to retrieve a rule by its ID or attribute filters. + * @param id The ID of the rule to search for. If null, no ID-based filtering is applied. + * @param attributeFilters A map of attributes and their corresponding filter values. This allows filtering by specific attribute values. + * @param featureType The feature type that is required in the query. + */ + public static BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters, FeatureType featureType) { + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + if (id != null) { + return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); + } + for (Map.Entry> entry : attributeFilters.entrySet()) { + Attribute attribute = entry.getKey(); + Set values = entry.getValue(); + if (values != null && !values.isEmpty()) { + BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); + for (String value : values) { + attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); + } + boolQuery.must(attributeQuery); + } + } + boolQuery.filter(QueryBuilders.existsQuery(featureType.getName())); + return boolQuery; + } + + /** + * Checks if a duplicate rule exists based on the attribute map. + * A rule is considered a duplicate when the attribute value already exists in the index, and the number of + * attributes in the new rule is equal to the number of attributes in an existing rule. + * + * For example, if an existing rule has: + * attribute1 = ['a'] and attribute2 = ['c'] + * And we are creating a new rule with: + * attribute1 = ['a'] + * @param attributeMapToValidate The attribute map to be validated against existing rules. + * @param ruleMap A map of existing rules where the key is the rule ID and the value is the Rule object. + */ + public static Optional getDuplicateRuleId(Map> attributeMapToValidate, Map ruleMap) { + for (Map.Entry entry : ruleMap.entrySet()) { + String ruleId = entry.getKey(); + Rule currRule = entry.getValue(); + // Compare the size of the attribute maps to ensure we only check for duplicates with the same number of attributes. + if (attributeMapToValidate.size() == currRule.getAttributeMap().size()) { + return Optional.of(ruleId); + } + } + return Optional.empty(); + } + + /** + * Compose the updated rule from the original rule and the UpdateRuleRequest + * @param originalRule - the existing rule + * @param request - the UpdateRuleRequest + * @param featureType - the featureType for the rule + */ + public static Rule composeUpdatedRule(Rule originalRule, UpdateRuleRequest request, FeatureType featureType) { + String requestDescription = request.getDescription(); + Map> requestMap = request.getAttributeMap(); + String requestLabel = request.getFeatureValue(); + return new Rule( + requestDescription == null ? originalRule.getDescription() : requestDescription, + requestMap == null || requestMap.isEmpty() ? originalRule.getAttributeMap() : requestMap, + featureType, + requestLabel == null ? originalRule.getFeatureValue() : requestLabel, + Instant.now().toString() + ); + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java new file mode 100644 index 0000000000000..c3437a5f6a77a --- /dev/null +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * This package contains utility classes for rules + */ +package org.opensearch.rule.utils; diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java new file mode 100644 index 0000000000000..34d5c06aaa131 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.rule.utils.RuleTestUtils; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; + +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.FEATURE_VALUE_ONE; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; + +public class UpdateRuleRequestTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of UpdateRuleRequest. + */ + public void testSerialization() throws IOException { + UpdateRuleRequest request = new UpdateRuleRequest( + _ID_ONE, + DESCRIPTION_ONE, + ATTRIBUTE_MAP, + FEATURE_VALUE_ONE, + RuleTestUtils.MockRuleFeatureType.INSTANCE + ); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateRuleRequest otherRequest = new UpdateRuleRequest(streamInput); + assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getFeatureValue(), otherRequest.getFeatureValue()); + assertEquals(request.getAttributeMap(), otherRequest.getAttributeMap()); + assertEquals(request.getDescription(), otherRequest.getDescription()); + } + + /** + * Test case to verify the serialization and deserialization of UpdateRuleRequest when there's null values. + */ + public void testSerializationWithNull() throws IOException { + UpdateRuleRequest request = new UpdateRuleRequest(_ID_ONE, null, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateRuleRequest otherRequest = new UpdateRuleRequest(streamInput); + assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getFeatureValue(), otherRequest.getFeatureValue()); + assertEquals(request.getAttributeMap(), otherRequest.getAttributeMap()); + assertEquals(request.getDescription(), otherRequest.getDescription()); + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java new file mode 100644 index 0000000000000..e5aa382a3f20b --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.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.rule.action; + +import org.opensearch.autotagging.Rule; +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.common.xcontent.json.JsonXContent; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; + +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRule; +import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; +import static org.mockito.Mockito.mock; + +public class UpdateRuleResponseTests extends OpenSearchTestCase { + + /** + * Test case to verify serialization and deserialization of UpdateRuleResponse + */ + public void testSerialization() throws IOException { + UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne, RestStatus.OK); + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateRuleResponse otherResponse = new UpdateRuleResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + Rule responseRule = response.getRule(); + Rule otherResponseRule = otherResponse.getRule(); + assertEqualRule(responseRule, otherResponseRule, true); + } + + /** + * Test case to validate the toXContent method of UpdateRuleResponse + */ + public void testToXContentUpdateRule() throws IOException { + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne, RestStatus.OK); + String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + + " \"description\" : \"description_1\",\n" + + " \"mock_attribute_one\" : [\n" + + " \"mock_attribute_one\"\n" + + " ],\n" + + " \"mock_feature_type\" : \"feature_value_one\",\n" + + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + + "}"; + assertEquals(expected, actual); + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java new file mode 100644 index 0000000000000..4eb64c8cf9e66 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -0,0 +1,69 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.service; + +import org.opensearch.action.update.UpdateRequest; +import org.opensearch.action.update.UpdateResponse; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.rule.action.UpdateRuleResponse; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.client.Client; + +import java.io.IOException; +import java.util.HashMap; + +import org.mockito.ArgumentCaptor; + +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.ruleTwo; +import static org.opensearch.rule.utils.RuleTestUtils.setUpIndexStoredRulePersistenceService; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@SuppressWarnings("unchecked") +public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { + public void testPersistUpdatedRule_Success() throws IOException { + IndexStoredRulePersistenceService indexStoredRulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + Client client = indexStoredRulePersistenceService.getClient(); + UpdateResponse updateResponse = mock(UpdateResponse.class); + when(updateResponse.status()).thenReturn(RestStatus.OK); + ActionListener listener = mock(ActionListener.class); + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(UpdateRequest.class); + doAnswer(invocation -> { + ActionListener callback = invocation.getArgument(1); + callback.onResponse(updateResponse); + return null; + }).when(client).update(requestCaptor.capture(), any()); + indexStoredRulePersistenceService.persistUpdatedRule(_ID_ONE, ruleTwo, listener); + verify(listener, times(1)).onResponse(any(UpdateRuleResponse.class)); + verify(listener, never()).onFailure(any()); + assertEquals(_ID_ONE, requestCaptor.getValue().id()); + } + + public void testPersistUpdatedRule_UpdateFailure() { + IndexStoredRulePersistenceService indexStoredRulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + Client client = indexStoredRulePersistenceService.getClient(); + ActionListener listener = mock(ActionListener.class); + doAnswer(invocation -> { + ActionListener callback = invocation.getArgument(1); + callback.onFailure(new Exception("Update failure")); + return null; + }).when(client).update(any(UpdateRequest.class), any()); + indexStoredRulePersistenceService.persistUpdatedRule(_ID_ONE, ruleTwo, listener); + + verify(listener, times(1)).onFailure(any(Exception.class)); + verify(listener, never()).onResponse(any()); + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java new file mode 100644 index 0000000000000..18e1bb99926b7 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.utils; + +import org.opensearch.autotagging.Rule; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.time.Instant; +import java.util.Locale; + +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; + +public class IndexStoredRuleParserTests extends OpenSearchTestCase { + public static final String VALID_JSON = String.format(Locale.ROOT, """ + { + "description": "%s", + "mock_feature_type": "feature value", + "mock_attribute_one": ["attribute_value_one", "attribute_value_two"], + "updated_at": "%s" + } + """, DESCRIPTION_ONE, Instant.now().toString()); + + private static final String INVALID_JSON = """ + { + "name": "TestRule", + "description": "A test rule for unit testing", + "mock_attribute_three": ["attribute_value_one", "attribute_value_two"] + } + """; + + public void testParseRule_Success() throws IOException { + Rule parsedRule = IndexStoredRuleParser.parseRule(VALID_JSON, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertNotNull(parsedRule); + assertEquals(DESCRIPTION_ONE, parsedRule.getDescription()); + assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, parsedRule.getFeatureType()); + } + + public void testParseRule_InvalidJson() { + Exception exception = assertThrows( + RuntimeException.class, + () -> IndexStoredRuleParser.parseRule(INVALID_JSON, RuleTestUtils.MockRuleFeatureType.INSTANCE) + ); + assertTrue(exception.getMessage().contains("mock_attribute_three is not a valid attribute within the mock_feature_type feature.")); + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java new file mode 100644 index 0000000000000..70474ed3e98b7 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java @@ -0,0 +1,100 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.utils; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.Rule; +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.test.OpenSearchTestCase; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_TWO; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_TWO; +import static org.opensearch.rule.utils.RuleTestUtils.FEATURE_VALUE_TWO; +import static org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class IndexStoredRuleUtilsTests extends OpenSearchTestCase { + public void testBuildGetRuleQuery_WithId() { + BoolQueryBuilder query = IndexStoredRuleUtils.buildGetRuleQuery( + _ID_ONE, + new HashMap<>(), + RuleTestUtils.MockRuleFeatureType.INSTANCE + ); + assertNotNull(query); + assertEquals(1, query.must().size()); + QueryBuilder idQuery = query.must().get(0); + assertTrue(idQuery.toString().contains(_ID_ONE)); + } + + public void testBuildGetRuleQuery_WithAttributes() { + BoolQueryBuilder query = IndexStoredRuleUtils.buildGetRuleQuery(null, ATTRIBUTE_MAP, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertNotNull(query); + assertTrue(query.must().size() == 1); + assertTrue(query.toString().contains(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE.getName())); + assertTrue(query.toString().contains(ATTRIBUTE_VALUE_ONE)); + } + + public void testGetDuplicateRuleId_Found() { + Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(ATTRIBUTE_MAP, Map.of(_ID_ONE, ruleOne)); + assertFalse(duplicateRuleId.isEmpty()); + assertEquals(_ID_ONE, duplicateRuleId.get()); + } + + public void testGetDuplicateRuleId_NotFound() { + Map> map = Map.of( + RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, + Set.of(ATTRIBUTE_VALUE_ONE), + RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, + Set.of(ATTRIBUTE_VALUE_TWO) + ); + Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(map, Map.of(_ID_ONE, ruleOne)); + assertTrue(duplicateRuleId.isEmpty()); + } + + public void testComposeUpdatedRule() { + UpdateRuleRequest request = mock(UpdateRuleRequest.class); + Map> attributeMap = new HashMap<>(); + attributeMap.put(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_TWO)); + when(request.getDescription()).thenReturn(DESCRIPTION_TWO); + when(request.getAttributeMap()).thenReturn(attributeMap); + when(request.getFeatureValue()).thenReturn(FEATURE_VALUE_TWO); + Rule updatedRule = IndexStoredRuleUtils.composeUpdatedRule(ruleOne, request, MockRuleFeatureType.INSTANCE); + assertEquals(DESCRIPTION_TWO, updatedRule.getDescription()); + assertEquals(attributeMap, updatedRule.getAttributeMap()); + assertEquals(FEATURE_VALUE_TWO, updatedRule.getFeatureValue()); + assertEquals(MockRuleFeatureType.INSTANCE, updatedRule.getFeatureType()); + } + + public void testComposeUpdatedRule_WithNull() { + UpdateRuleRequest request = mock(UpdateRuleRequest.class); + Map> attributeMap = new HashMap<>(); + attributeMap.put(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_TWO)); + when(request.getDescription()).thenReturn(null); + when(request.getAttributeMap()).thenReturn(attributeMap); + when(request.getFeatureValue()).thenReturn(FEATURE_VALUE_TWO); + Rule updatedRule = IndexStoredRuleUtils.composeUpdatedRule(ruleOne, request, MockRuleFeatureType.INSTANCE); + assertEquals(DESCRIPTION_ONE, updatedRule.getDescription()); + assertEquals(attributeMap, updatedRule.getAttributeMap()); + assertEquals(FEATURE_VALUE_TWO, updatedRule.getFeatureValue()); + assertEquals(MockRuleFeatureType.INSTANCE, updatedRule.getFeatureType()); + } +} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java new file mode 100644 index 0000000000000..fd9a228370af4 --- /dev/null +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -0,0 +1,157 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.utils; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.AutoTaggingRegistry; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.autotagging.Rule; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.metadata.Metadata; +import org.opensearch.cluster.metadata.QueryGroup; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.client.Client; + +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class RuleTestUtils { + public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; + public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; + public static final String FEATURE_VALUE_ONE = "feature_value_one"; + public static final String FEATURE_VALUE_TWO = "feature_value_two"; + public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; + public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two"; + public static final String DESCRIPTION_ONE = "description_1"; + public static final String DESCRIPTION_TWO = "description_2"; + public static final String SEARCH_AFTER = "search_after_id"; + public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; + public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; + public static final String FEATURE_TYPE_NAME = "mock_feature_type"; + public static final String TEST_INDEX_NAME = ".test_index_for_rule"; + public static final Map> ATTRIBUTE_MAP = Map.of( + MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, + Set.of(ATTRIBUTE_VALUE_ONE) + ); + public static final Rule ruleOne = Rule.builder() + .description(DESCRIPTION_ONE) + .featureType(MockRuleFeatureType.INSTANCE) + .featureValue(FEATURE_VALUE_ONE) + .attributeMap(ATTRIBUTE_MAP) + .updatedAt(TIMESTAMP_ONE) + .build(); + + public static final Rule ruleTwo = Rule.builder() + .description(DESCRIPTION_TWO) + .featureType(MockRuleFeatureType.INSTANCE) + .featureValue(FEATURE_VALUE_TWO) + .attributeMap(Map.of(MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, Set.of(ATTRIBUTE_VALUE_TWO))) + .updatedAt(TIMESTAMP_TWO) + .build(); + + public static Map ruleMap() { + return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); + } + + public static IndexStoredRulePersistenceService setUpIndexStoredRulePersistenceService(Map queryGroupMap) { + Client client = mock(Client.class); + ClusterService clusterService = mock(ClusterService.class); + ClusterState clusterState = mock(ClusterState.class); + Metadata metadata = mock(Metadata.class); + ThreadPool threadPool = mock(ThreadPool.class); + + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + when(client.threadPool()).thenReturn(threadPool); + when(threadPool.getThreadContext()).thenReturn(threadContext); + when(clusterService.state()).thenReturn(clusterState); + when(clusterState.metadata()).thenReturn(metadata); + when(metadata.queryGroups()).thenReturn(queryGroupMap); + return new IndexStoredRulePersistenceService(TEST_INDEX_NAME, clusterService, client, MockRuleFeatureType.INSTANCE, 50); + } + + public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { + assertEquals(mapOne.size(), mapTwo.size()); + for (Map.Entry entry : mapOne.entrySet()) { + String id = entry.getKey(); + assertTrue(mapTwo.containsKey(id)); + Rule one = mapOne.get(id); + Rule two = mapTwo.get(id); + assertEqualRule(one, two, ruleUpdated); + } + } + + public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { + if (ruleUpdated) { + assertEquals(one.getDescription(), two.getDescription()); + assertEquals(one.getFeatureType(), two.getFeatureType()); + assertEquals(one.getFeatureValue(), two.getFeatureValue()); + assertEquals(one.getAttributeMap(), two.getAttributeMap()); + assertEquals(one.getAttributeMap(), two.getAttributeMap()); + } else { + assertEquals(one, two); + } + } + + public static class MockRuleFeatureType implements FeatureType { + + public static final MockRuleFeatureType INSTANCE = new MockRuleFeatureType(); + + private MockRuleFeatureType() {} + + static { + INSTANCE.registerFeatureType(); + } + + @Override + public String getName() { + return FEATURE_TYPE_NAME; + } + + @Override + public Map getAllowedAttributesRegistry() { + return Map.of( + ATTRIBUTE_VALUE_ONE, + MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, + ATTRIBUTE_VALUE_TWO, + MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO + ); + } + + @Override + public void registerFeatureType() { + AutoTaggingRegistry.registerFeatureType(INSTANCE); + } + } + + public enum MockRuleAttributes implements Attribute { + MOCK_RULE_ATTRIBUTE_ONE(ATTRIBUTE_VALUE_ONE), + MOCK_RULE_ATTRIBUTE_TWO(ATTRIBUTE_VALUE_TWO); + ; + + private final String name; + + MockRuleAttributes(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + } +} diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java index 8a1905fcff23a..17e789c58a7f7 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java @@ -368,5 +368,9 @@ public String getFeatureValue() { public Map> getAttributeMap() { return attributeMap; } + + public String getDescription() { + return description; + } } } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java index 3314598e8211a..33ea53419b3d9 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java @@ -67,6 +67,24 @@ public void validate() { errorMessages.addAll(validateFeatureType()); errorMessages.addAll(validateUpdatedAtEpoch()); errorMessages.addAll(validateAttributeMap()); + handleErrorMessages(errorMessages); + } + + public void validateUpdatingRuleParams() { + List errorMessages = new ArrayList<>(); + if (isEmpty(description)) { + errorMessages.add("Rule description can't be empty"); + } + if (isEmpty(featureValue)) { + errorMessages.add("Rule featureValue can't be empty"); + } + if (attributeMap != null && !attributeMap.isEmpty()) { + validateAttributeMap(); + } + handleErrorMessages(errorMessages); + } + + private void handleErrorMessages(List errorMessages) { if (!errorMessages.isEmpty()) { ValidationException validationException = new ValidationException(); validationException.addValidationErrors(errorMessages); diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java index bb0f4c7e90122..2008c3217a85d 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 @@ -11,6 +11,8 @@ import org.opensearch.common.inject.AbstractModule; import org.opensearch.common.inject.Singleton; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.rule.service.RulePersistenceService; /** * Guice Module to manage WorkloadManagement related objects @@ -27,5 +29,6 @@ protected void configure() { // Bind WorkloadGroupPersistenceService as a singleton to ensure a single instance is used, // preventing multiple throttling key registrations in the constructor. bind(WorkloadGroupPersistenceService.class).in(Singleton.class); + bind(RulePersistenceService.class).to(IndexStoredRulePersistenceService.class); } } 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/action/CreateQueryGroupAction.java new file mode 100644 index 0000000000000..ee1b40a2f9bbc --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupAction.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.action; + +import org.opensearch.action.ActionType; + +/** + * Transport action to get WorkloadGroup + * + * @opensearch.experimental + */ +public class GetWorkloadGroupAction extends ActionType { + + /** + * An instance of GetWorkloadGroupAction + */ + public static final GetWorkloadGroupAction INSTANCE = new GetWorkloadGroupAction(); + + /** + * Name for GetWorkloadGroupAction + */ + public static final String NAME = "cluster:admin/opensearch/wlm/workload_group/_get"; + + /** + * Default constructor + */ + private GetWorkloadGroupAction() { + super(NAME, GetWorkloadGroupResponse::new); + } +} 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/action/CreateQueryGroupRequest.java new file mode 100644 index 0000000000000..ad932667b25e8 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequest.java @@ -0,0 +1,82 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.action; + +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; +import org.opensearch.cluster.metadata.WorkloadGroup; +import org.opensearch.common.UUIDs; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.core.xcontent.XContentParser; +import org.joda.time.Instant; + +import java.io.IOException; + +/** + * A request for create WorkloadGroup + * User input schema: + * { + * "name": "analytics", + * "resiliency_mode": "enforced", + * "resource_limits": { + * "cpu" : 0.4, + * "memory" : 0.2 + * } + * } + * + * @opensearch.experimental + */ +public class CreateWorkloadGroupRequest extends ClusterManagerNodeRequest { + private final WorkloadGroup workloadGroup; + + /** + * Constructor for CreateWorkloadGroupRequest + * @param workloadGroup - A {@link WorkloadGroup} object + */ + CreateWorkloadGroupRequest(WorkloadGroup workloadGroup) { + this.workloadGroup = workloadGroup; + } + + /** + * Constructor for CreateWorkloadGroupRequest + * @param in - A {@link StreamInput} object + */ + CreateWorkloadGroupRequest(StreamInput in) throws IOException { + super(in); + workloadGroup = new WorkloadGroup(in); + } + + /** + * Generate a CreateWorkloadGroupRequest from XContent + * @param parser - A {@link XContentParser} object + */ + public static CreateWorkloadGroupRequest fromXContent(XContentParser parser) throws IOException { + WorkloadGroup.Builder builder = WorkloadGroup.Builder.fromXContent(parser); + return new CreateWorkloadGroupRequest(builder._id(UUIDs.randomBase64UUID()).updatedAt(Instant.now().getMillis()).build()); + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + workloadGroup.writeTo(out); + } + + /** + * WorkloadGroup getter + */ + public WorkloadGroup getWorkloadGroup() { + return workloadGroup; + } +} 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/action/CreateQueryGroupResponse.java new file mode 100644 index 0000000000000..b33214e042398 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponse.java @@ -0,0 +1,74 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.action; + +import org.opensearch.cluster.metadata.WorkloadGroup; +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 java.io.IOException; + +/** + * Response for the create API for WorkloadGroup + * + * @opensearch.experimental + */ +public class CreateWorkloadGroupResponse extends ActionResponse implements ToXContent, ToXContentObject { + private final WorkloadGroup workloadGroup; + private final RestStatus restStatus; + + /** + * Constructor for CreateWorkloadGroupResponse + * @param workloadGroup - The WorkloadGroup to be included in the response + * @param restStatus - The restStatus for the response + */ + public CreateWorkloadGroupResponse(final WorkloadGroup workloadGroup, RestStatus restStatus) { + this.workloadGroup = workloadGroup; + this.restStatus = restStatus; + } + + /** + * Constructor for CreateWorkloadGroupResponse + * @param in - A {@link StreamInput} object + */ + public CreateWorkloadGroupResponse(StreamInput in) throws IOException { + workloadGroup = new WorkloadGroup(in); + restStatus = RestStatus.readFrom(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + workloadGroup.writeTo(out); + RestStatus.writeTo(out, restStatus); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return workloadGroup.toXContent(builder, params); + } + + /** + * workloadGroup getter + */ + public WorkloadGroup getWorkloadGroup() { + return workloadGroup; + } + + /** + * restStatus getter + */ + public RestStatus getRestStatus() { + return restStatus; + } +} 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/action/DeleteQueryGroupAction.java new file mode 100644 index 0000000000000..39b47d69776f4 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupAction.java @@ -0,0 +1,38 @@ +/* + * 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.action; + +import org.opensearch.action.ActionType; +import org.opensearch.action.support.clustermanager.AcknowledgedResponse; + +/** + * Transport action for delete WorkloadGroup + * + * @opensearch.experimental + */ +public class DeleteWorkloadGroupAction extends ActionType { + + /** + /** + * An instance of DeleteWorkloadGroupAction + */ + public static final DeleteWorkloadGroupAction INSTANCE = new DeleteWorkloadGroupAction(); + + /** + * Name for DeleteWorkloadGroupAction + */ + public static final String NAME = "cluster:admin/opensearch/wlm/workload_group/_delete"; + + /** + * Default constructor + */ + private DeleteWorkloadGroupAction() { + super(NAME, AcknowledgedResponse::new); + } +} 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/action/DeleteQueryGroupRequest.java new file mode 100644 index 0000000000000..940a3815b1662 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequest.java @@ -0,0 +1,65 @@ +/* + * 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.action; + +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.action.support.clustermanager.AcknowledgedRequest; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; + +import java.io.IOException; + +/** + * Request for delete WorkloadGroup + * + * @opensearch.experimental + */ +public class DeleteWorkloadGroupRequest extends AcknowledgedRequest { + private final String name; + + /** + * Default constructor for DeleteWorkloadGroupRequest + * @param name - name for the WorkloadGroup to get + */ + public DeleteWorkloadGroupRequest(String name) { + this.name = name; + } + + /** + * Constructor for DeleteWorkloadGroupRequest + * @param in - A {@link StreamInput} object + */ + public DeleteWorkloadGroupRequest(StreamInput in) throws IOException { + super(in); + name = in.readOptionalString(); + } + + @Override + public ActionRequestValidationException validate() { + if (name == null) { + ActionRequestValidationException actionRequestValidationException = new ActionRequestValidationException(); + actionRequestValidationException.addValidationError("WorkloadGroup name is missing"); + return actionRequestValidationException; + } + return null; + } + + /** + * Name getter + */ + public String getName() { + return name; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeOptionalString(name); + } +} 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/action/GetQueryGroupAction.java new file mode 100644 index 0000000000000..b4f8e1ce90126 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupAction.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.action; + +import org.opensearch.action.ActionType; + +/** + * Transport action to update WorkloadGroup + * + * @opensearch.experimental + */ +public class UpdateWorkloadGroupAction extends ActionType { + + /** + * An instance of UpdateWorkloadGroupAction + */ + public static final UpdateWorkloadGroupAction INSTANCE = new UpdateWorkloadGroupAction(); + + /** + * Name for UpdateWorkloadGroupAction + */ + public static final String NAME = "cluster:admin/opensearch/wlm/workload_group/_update"; + + /** + * Default constructor + */ + private UpdateWorkloadGroupAction() { + super(NAME, UpdateWorkloadGroupResponse::new); + } +} 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/action/GetQueryGroupRequest.java new file mode 100644 index 0000000000000..4b8a5f85fd236 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequest.java @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.action; + +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.action.support.clustermanager.ClusterManagerNodeReadRequest; +import org.opensearch.cluster.metadata.WorkloadGroup; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; + +import java.io.IOException; + +/** + * Request for get WorkloadGroup + * + * @opensearch.experimental + */ +public class GetWorkloadGroupRequest extends ClusterManagerNodeReadRequest { + final String name; + + /** + * Default constructor for GetWorkloadGroupRequest + * @param name - name for the WorkloadGroup to get + */ + public GetWorkloadGroupRequest(String name) { + this.name = name; + } + + /** + * Constructor for GetWorkloadGroupRequest + * @param in - A {@link StreamInput} object + */ + public GetWorkloadGroupRequest(StreamInput in) throws IOException { + super(in); + name = in.readOptionalString(); + } + + @Override + public ActionRequestValidationException validate() { + if (name != null) { + WorkloadGroup.validateName(name); + } + return null; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeOptionalString(name); + } + + /** + * Name getter + */ + public String getName() { + return name; + } +} 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/action/GetQueryGroupResponse.java new file mode 100644 index 0000000000000..ab8f773088a37 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponse.java @@ -0,0 +1,82 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.action; + +import org.opensearch.cluster.metadata.WorkloadGroup; +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 java.io.IOException; +import java.util.Collection; + +/** + * Response for the get API for WorkloadGroup + * + * @opensearch.experimental + */ +public class GetWorkloadGroupResponse extends ActionResponse implements ToXContent, ToXContentObject { + private final Collection workloadGroups; + private final RestStatus restStatus; + + /** + * Constructor for GetWorkloadGroupResponse + * @param workloadGroups - The WorkloadGroup list to be fetched + * @param restStatus - The rest status of the request + */ + public GetWorkloadGroupResponse(final Collection workloadGroups, RestStatus restStatus) { + this.workloadGroups = workloadGroups; + this.restStatus = restStatus; + } + + /** + * Constructor for GetWorkloadGroupResponse + * @param in - A {@link StreamInput} object + */ + public GetWorkloadGroupResponse(StreamInput in) throws IOException { + this.workloadGroups = in.readList(WorkloadGroup::new); + restStatus = RestStatus.readFrom(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeCollection(workloadGroups); + RestStatus.writeTo(out, restStatus); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.startArray("workload_groups"); + for (WorkloadGroup group : workloadGroups) { + group.toXContent(builder, params); + } + builder.endArray(); + builder.endObject(); + return builder; + } + + /** + * workloadGroups getter + */ + public Collection getWorkloadGroups() { + return workloadGroups; + } + + /** + * restStatus getter + */ + public RestStatus getRestStatus() { + return restStatus; + } +} 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/action/TransportCreateQueryGroupAction.java new file mode 100644 index 0000000000000..03dd2ac1f9952 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateQueryGroupAction.java @@ -0,0 +1,95 @@ +/* + * 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.action; + +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.block.ClusterBlockException; +import org.opensearch.cluster.block.ClusterBlockLevel; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.common.inject.Inject; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java +import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportService; + +import java.io.IOException; + +import static org.opensearch.threadpool.ThreadPool.Names.SAME; + +/** + * Transport action to update WorkloadGroup + * + * @opensearch.experimental + */ +public class TransportUpdateWorkloadGroupAction extends TransportClusterManagerNodeAction< + UpdateWorkloadGroupRequest, + UpdateWorkloadGroupResponse> { + + private final WorkloadGroupPersistenceService workloadGroupPersistenceService; + + /** + * Constructor for TransportUpdateWorkloadGroupAction + * + * @param threadPool - {@link ThreadPool} object + * @param transportService - a {@link TransportService} object + * @param actionFilters - a {@link ActionFilters} object + * @param indexNameExpressionResolver - {@link IndexNameExpressionResolver} object + * @param workloadGroupPersistenceService - a {@link WorkloadGroupPersistenceService} object + */ + @Inject + public TransportUpdateWorkloadGroupAction( + ThreadPool threadPool, + TransportService transportService, + ActionFilters actionFilters, + IndexNameExpressionResolver indexNameExpressionResolver, + WorkloadGroupPersistenceService workloadGroupPersistenceService + ) { + super( + UpdateWorkloadGroupAction.NAME, + transportService, + workloadGroupPersistenceService.getClusterService(), + threadPool, + actionFilters, + UpdateWorkloadGroupRequest::new, + indexNameExpressionResolver + ); + this.workloadGroupPersistenceService = workloadGroupPersistenceService; + } + + @Override + protected void clusterManagerOperation( + UpdateWorkloadGroupRequest request, + ClusterState clusterState, + ActionListener listener + ) { + workloadGroupPersistenceService.updateInClusterStateMetadata(request, listener); + } + + @Override + protected String executor() { + return SAME; + } + + @Override + protected UpdateWorkloadGroupResponse read(StreamInput in) throws IOException { + return new UpdateWorkloadGroupResponse(in); + } + + @Override + protected ClusterBlockException checkBlock(UpdateWorkloadGroupRequest request, ClusterState state) { + return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java index 2039f1cb590ff..e13b682914dd3 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java @@ -17,7 +17,11 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java new file mode 100644 index 0000000000000..5fc8b30bf419c --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java @@ -0,0 +1,97 @@ +/* + * 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.action; + +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.clustermanager.AcknowledgedResponse; +import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.block.ClusterBlockException; +import org.opensearch.cluster.block.ClusterBlockLevel; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.inject.Inject; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java +import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.java +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportService; + +import java.io.IOException; + +/** + * Transport action for delete WorkloadGroup + * + * @opensearch.experimental + */ +public class TransportDeleteWorkloadGroupAction extends TransportClusterManagerNodeAction< + DeleteWorkloadGroupRequest, + AcknowledgedResponse> { + + private final WorkloadGroupPersistenceService workloadGroupPersistenceService; + + /** + * Constructor for TransportDeleteWorkloadGroupAction + * + * @param clusterService - a {@link ClusterService} object + * @param transportService - a {@link TransportService} object + * @param actionFilters - a {@link ActionFilters} object + * @param threadPool - a {@link ThreadPool} object + * @param indexNameExpressionResolver - a {@link IndexNameExpressionResolver} object + * @param workloadGroupPersistenceService - a {@link WorkloadGroupPersistenceService} object + */ + @Inject + public TransportDeleteWorkloadGroupAction( + ClusterService clusterService, + TransportService transportService, + ActionFilters actionFilters, + ThreadPool threadPool, + IndexNameExpressionResolver indexNameExpressionResolver, + WorkloadGroupPersistenceService workloadGroupPersistenceService + ) { + super( + DeleteWorkloadGroupAction.NAME, + transportService, + clusterService, + threadPool, + actionFilters, + DeleteWorkloadGroupRequest::new, + indexNameExpressionResolver + ); + this.workloadGroupPersistenceService = workloadGroupPersistenceService; + } + + @Override + protected void clusterManagerOperation( + DeleteWorkloadGroupRequest request, + ClusterState state, + ActionListener listener + ) throws Exception { + workloadGroupPersistenceService.deleteInClusterStateMetadata(request, listener); + } + + @Override + protected String executor() { + return ThreadPool.Names.SAME; + } + + @Override + protected AcknowledgedResponse read(StreamInput in) throws IOException { + return new AcknowledgedResponse(in); + } + + @Override + protected ClusterBlockException checkBlock(DeleteWorkloadGroupRequest request, ClusterState state) { + return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java index 2bfbadba4d51d..5fc8b30bf419c 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java @@ -19,7 +19,11 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java new file mode 100644 index 0000000000000..ab1ff9f247c56 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java @@ -0,0 +1,107 @@ +/* + * 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.action; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeReadAction; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.block.ClusterBlockException; +import org.opensearch.cluster.block.ClusterBlockLevel; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.metadata.WorkloadGroup; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.inject.Inject; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.rest.RestStatus; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java +import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.java +import org.opensearch.search.pipeline.SearchPipelineService; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportService; + +import java.io.IOException; +import java.util.Collection; + +/** + * Transport action to get WorkloadGroup + * + * @opensearch.experimental + */ +public class TransportGetWorkloadGroupAction extends TransportClusterManagerNodeReadAction< + GetWorkloadGroupRequest, + GetWorkloadGroupResponse> { + private static final Logger logger = LogManager.getLogger(SearchPipelineService.class); + + /** + * Constructor for TransportGetWorkloadGroupAction + * + * @param clusterService - a {@link ClusterService} object + * @param transportService - a {@link TransportService} object + * @param actionFilters - a {@link ActionFilters} object + * @param threadPool - a {@link ThreadPool} object + * @param indexNameExpressionResolver - a {@link IndexNameExpressionResolver} object + */ + @Inject + public TransportGetWorkloadGroupAction( + ClusterService clusterService, + TransportService transportService, + ActionFilters actionFilters, + ThreadPool threadPool, + IndexNameExpressionResolver indexNameExpressionResolver + ) { + super( + GetWorkloadGroupAction.NAME, + transportService, + clusterService, + threadPool, + actionFilters, + GetWorkloadGroupRequest::new, + indexNameExpressionResolver, + true + ); + } + + @Override + protected String executor() { + return ThreadPool.Names.SAME; + } + + @Override + protected GetWorkloadGroupResponse read(StreamInput in) throws IOException { + return new GetWorkloadGroupResponse(in); + } + + @Override + protected ClusterBlockException checkBlock(GetWorkloadGroupRequest request, ClusterState state) { + return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ); + } + + @Override + protected void clusterManagerOperation( + GetWorkloadGroupRequest request, + ClusterState state, + ActionListener listener + ) throws Exception { + final String name = request.getName(); + final Collection resultGroups = WorkloadGroupPersistenceService.getFromClusterStateMetadata(name, state); + + if (resultGroups.isEmpty() && name != null && !name.isEmpty()) { + logger.warn("No WorkloadGroup exists with the provided name: {}", name); + throw new ResourceNotFoundException("No WorkloadGroup exists with the provided name: " + name); + } + listener.onResponse(new GetWorkloadGroupResponse(resultGroups, RestStatus.OK)); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java index bb2fbab047343..ab1ff9f247c56 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java @@ -23,7 +23,11 @@ import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.rest.RestStatus; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.java import org.opensearch.search.pipeline.SearchPipelineService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java new file mode 100644 index 0000000000000..e13b682914dd3 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java @@ -0,0 +1,96 @@ +/* + * 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.action; + +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.block.ClusterBlockException; +import org.opensearch.cluster.block.ClusterBlockLevel; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.common.inject.Inject; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java +import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.java +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportService; + +import java.io.IOException; + +import static org.opensearch.threadpool.ThreadPool.Names.SAME; + +/** + * Transport action to create WorkloadGroup + * + * @opensearch.experimental + */ +public class TransportCreateWorkloadGroupAction extends TransportClusterManagerNodeAction< + CreateWorkloadGroupRequest, + CreateWorkloadGroupResponse> { + + private final WorkloadGroupPersistenceService workloadGroupPersistenceService; + + /** + * Constructor for TransportCreateWorkloadGroupAction + * + * @param threadPool - {@link ThreadPool} object + * @param transportService - a {@link TransportService} object + * @param actionFilters - a {@link ActionFilters} object + * @param indexNameExpressionResolver - {@link IndexNameExpressionResolver} object + * @param workloadGroupPersistenceService - a {@link WorkloadGroupPersistenceService} object + */ + @Inject + public TransportCreateWorkloadGroupAction( + ThreadPool threadPool, + TransportService transportService, + ActionFilters actionFilters, + IndexNameExpressionResolver indexNameExpressionResolver, + WorkloadGroupPersistenceService workloadGroupPersistenceService + ) { + super( + CreateWorkloadGroupAction.NAME, + transportService, + workloadGroupPersistenceService.getClusterService(), + threadPool, + actionFilters, + CreateWorkloadGroupRequest::new, + indexNameExpressionResolver + ); + this.workloadGroupPersistenceService = workloadGroupPersistenceService; + } + + @Override + protected void clusterManagerOperation( + CreateWorkloadGroupRequest request, + ClusterState clusterState, + ActionListener listener + ) { + workloadGroupPersistenceService.persistInClusterStateMetadata(request.getWorkloadGroup(), listener); + } + + @Override + protected String executor() { + return SAME; + } + + @Override + protected CreateWorkloadGroupResponse read(StreamInput in) throws IOException { + return new CreateWorkloadGroupResponse(in); + } + + @Override + protected ClusterBlockException checkBlock(CreateWorkloadGroupRequest request, ClusterState state) { + return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); + } + +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java index ef639d44b4155..03dd2ac1f9952 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java @@ -17,7 +17,11 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java new file mode 100644 index 0000000000000..ca9784ebc7e4b --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.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.action; + +import org.opensearch.action.ActionType; + +/** + * Transport action to create WorkloadGroup + * + * @opensearch.experimental + */ +public class CreateWorkloadGroupAction extends ActionType { + + /** + * An instance of CreateWorkloadGroupAction + */ + public static final CreateWorkloadGroupAction INSTANCE = new CreateWorkloadGroupAction(); + + /** + * Name for CreateWorkloadGroupAction + */ + public static final String NAME = "cluster:admin/opensearch/wlm/workload_group/_create"; + + /** + * Default constructor + */ + private CreateWorkloadGroupAction() { + super(NAME, CreateWorkloadGroupResponse::new); + } +} 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/action/UpdateQueryGroupRequest.java new file mode 100644 index 0000000000000..18af58289be13 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequest.java @@ -0,0 +1,83 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.action; + +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; +import org.opensearch.cluster.metadata.QueryGroup; +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.MutableQueryGroupFragment; + +import java.io.IOException; + +/** + * A request for update QueryGroup + * + * @opensearch.experimental + */ +public class UpdateQueryGroupRequest extends ClusterManagerNodeRequest { + private final String name; + private final MutableQueryGroupFragment mutableQueryGroupFragment; + + /** + * Constructor for UpdateQueryGroupRequest + * @param name - QueryGroup name for UpdateQueryGroupRequest + * @param mutableQueryGroupFragment - MutableQueryGroupFragment for UpdateQueryGroupRequest + */ + UpdateQueryGroupRequest(String name, MutableQueryGroupFragment mutableQueryGroupFragment) { + this.name = name; + this.mutableQueryGroupFragment = mutableQueryGroupFragment; + } + + /** + * Constructor for UpdateQueryGroupRequest + * @param in - A {@link StreamInput} object + */ + UpdateQueryGroupRequest(StreamInput in) throws IOException { + this(in.readString(), new MutableQueryGroupFragment(in)); + } + + /** + * Generate a UpdateQueryGroupRequest from XContent + * @param parser - A {@link XContentParser} object + * @param name - name of the QueryGroup to be updated + */ + public static UpdateQueryGroupRequest fromXContent(XContentParser parser, String name) throws IOException { + QueryGroup.Builder builder = QueryGroup.Builder.fromXContent(parser); + return new UpdateQueryGroupRequest(name, builder.getMutableQueryGroupFragment()); + } + + @Override + public ActionRequestValidationException validate() { + QueryGroup.validateName(name); + return null; + } + + /** + * name getter + */ + public String getName() { + return name; + } + + /** + * mutableQueryGroupFragment getter + */ + public MutableQueryGroupFragment getmMutableQueryGroupFragment() { + return mutableQueryGroupFragment; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(name); + mutableQueryGroupFragment.writeTo(out); + } +} 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/action/UpdateQueryGroupResponse.java new file mode 100644 index 0000000000000..9b8fccbdb5346 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponse.java @@ -0,0 +1,74 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.action; + +import org.opensearch.cluster.metadata.WorkloadGroup; +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 java.io.IOException; + +/** + * Response for the update API for WorkloadGroup + * + * @opensearch.experimental + */ +public class UpdateWorkloadGroupResponse extends ActionResponse implements ToXContent, ToXContentObject { + private final WorkloadGroup workloadGroup; + private final RestStatus restStatus; + + /** + * Constructor for UpdateWorkloadGroupResponse + * @param workloadGroup - the WorkloadGroup to be updated + * @param restStatus - the rest status for the response + */ + public UpdateWorkloadGroupResponse(final WorkloadGroup workloadGroup, RestStatus restStatus) { + this.workloadGroup = workloadGroup; + this.restStatus = restStatus; + } + + /** + * Constructor for UpdateWorkloadGroupResponse + * @param in - a {@link StreamInput} object + */ + public UpdateWorkloadGroupResponse(StreamInput in) throws IOException { + workloadGroup = new WorkloadGroup(in); + restStatus = RestStatus.readFrom(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + workloadGroup.writeTo(out); + RestStatus.writeTo(out, restStatus); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return workloadGroup.toXContent(builder, params); + } + + /** + * workloadGroup getter + */ + public WorkloadGroup getWorkloadGroup() { + return workloadGroup; + } + + /** + * restStatus getter + */ + public RestStatus getRestStatus() { + return restStatus; + } +} 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/rest/RestCreateQueryGroupAction.java new file mode 100644 index 0000000000000..ee3564dc5c7f6 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateQueryGroupAction.java @@ -0,0 +1,82 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rest; + +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentParser; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java +import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupAction; +import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestResponse; +import org.opensearch.rest.action.RestResponseListener; +import org.opensearch.transport.client.node.NodeClient; + +import java.io.IOException; +import java.util.List; + +import static org.opensearch.rest.RestRequest.Method.POST; +import static org.opensearch.rest.RestRequest.Method.PUT; + +/** + * Rest action to update a WorkloadGroup + * + * @opensearch.experimental + */ +public class RestUpdateWorkloadGroupAction extends BaseRestHandler { + + /** + * Constructor for RestUpdateWorkloadGroupAction + */ + public RestUpdateWorkloadGroupAction() {} + + @Override + public String getName() { + return "update_workload_group"; + } + + /** + * The list of {@link Route}s that this RestHandler is responsible for handling. + */ + @Override + public List routes() { + return List.of(new Route(POST, "_wlm/workload_group/{name}"), new Route(PUT, "_wlm/workload_group/{name}")); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + try (XContentParser parser = request.contentParser()) { + UpdateWorkloadGroupRequest updateWorkloadGroupRequest = UpdateWorkloadGroupRequest.fromXContent(parser, request.param("name")); + return channel -> client.execute( + UpdateWorkloadGroupAction.INSTANCE, + updateWorkloadGroupRequest, + updateWorkloadGroupResponse(channel) + ); + } + } + + private RestResponseListener updateWorkloadGroupResponse(final RestChannel channel) { + return new RestResponseListener<>(channel) { + @Override + public RestResponse buildResponse(final UpdateWorkloadGroupResponse 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/rest/RestCreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java index 5ef59602f7893..06624664d46eb 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java @@ -11,9 +11,14 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java new file mode 100644 index 0000000000000..8a1591b015372 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java @@ -0,0 +1,66 @@ +/* + * 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.rest; + +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +======== +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupAction.java +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.action.RestToXContentListener; +import org.opensearch.transport.client.node.NodeClient; + +import java.io.IOException; +import java.util.List; + +import static org.opensearch.rest.RestRequest.Method.DELETE; + +/** + * Rest action to delete a WorkloadGroup + * + * @opensearch.experimental + */ +public class RestDeleteWorkloadGroupAction extends BaseRestHandler { + + /** + * Constructor for RestDeleteWorkloadGroupAction + */ + public RestDeleteWorkloadGroupAction() {} + + @Override + public String getName() { + return "delete_workload_group"; + } + + /** + * The list of {@link Route}s that this RestHandler is responsible for handling. + */ + @Override + public List routes() { + return List.of(new Route(DELETE, "_wlm/workload_group/{name}")); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + DeleteWorkloadGroupRequest deleteWorkloadGroupRequest = new DeleteWorkloadGroupRequest(request.param("name")); + deleteWorkloadGroupRequest.clusterManagerNodeTimeout( + request.paramAsTime("cluster_manager_timeout", deleteWorkloadGroupRequest.clusterManagerNodeTimeout()) + ); + deleteWorkloadGroupRequest.timeout(request.paramAsTime("timeout", deleteWorkloadGroupRequest.timeout())); + return channel -> client.execute( + DeleteWorkloadGroupAction.INSTANCE, + deleteWorkloadGroupRequest, + new RestToXContentListener<>(channel) + ); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java index d0d82f43679fa..8a1591b015372 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java @@ -8,8 +8,13 @@ package org.opensearch.plugin.wlm.rest; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +======== +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupAction.java 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/rest/RestGetQueryGroupAction.java new file mode 100644 index 0000000000000..4879adc6898c2 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetQueryGroupAction.java @@ -0,0 +1,74 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rest; + +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java +import org.opensearch.plugin.wlm.action.GetWorkloadGroupAction; +import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupResponse; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestResponse; +import org.opensearch.rest.action.RestResponseListener; +import org.opensearch.transport.client.node.NodeClient; + +import java.io.IOException; +import java.util.List; + +import static org.opensearch.rest.RestRequest.Method.GET; + +/** + * Rest action to get a WorkloadGroup + * + * @opensearch.experimental + */ +public class RestGetWorkloadGroupAction extends BaseRestHandler { + + /** + * Constructor for RestGetWorkloadGroupAction + */ + public RestGetWorkloadGroupAction() {} + + @Override + public String getName() { + return "get_workload_group"; + } + + /** + * The list of {@link Route}s that this RestHandler is responsible for handling. + */ + @Override + public List routes() { + return List.of(new Route(GET, "_wlm/workload_group/{name}"), new Route(GET, "_wlm/workload_group/")); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + final GetWorkloadGroupRequest getWorkloadGroupRequest = new GetWorkloadGroupRequest(request.param("name")); + return channel -> client.execute(GetWorkloadGroupAction.INSTANCE, getWorkloadGroupRequest, getWorkloadGroupResponse(channel)); + } + + private RestResponseListener getWorkloadGroupResponse(final RestChannel channel) { + return new RestResponseListener<>(channel) { + @Override + public RestResponse buildResponse(final GetWorkloadGroupResponse 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/rest/RestGetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java index 818531352f4d3..4879adc6898c2 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java @@ -10,9 +10,15 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.GetWorkloadGroupAction; import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupResponse; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java new file mode 100644 index 0000000000000..06624664d46eb --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java @@ -0,0 +1,81 @@ +/* + * 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.rest; + +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentParser; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestResponse; +import org.opensearch.rest.action.RestResponseListener; +import org.opensearch.transport.client.node.NodeClient; + +import java.io.IOException; +import java.util.List; + +import static org.opensearch.rest.RestRequest.Method.POST; +import static org.opensearch.rest.RestRequest.Method.PUT; + +/** + * Rest action to create a WorkloadGroup + * + * @opensearch.experimental + */ +public class RestCreateWorkloadGroupAction extends BaseRestHandler { + + /** + * Constructor for RestCreateWorkloadGroupAction + */ + public RestCreateWorkloadGroupAction() {} + + @Override + public String getName() { + return "create_workload_group"; + } + + /** + * The list of {@link Route}s that this RestHandler is responsible for handling. + */ + @Override + public List routes() { + return List.of(new Route(POST, "_wlm/workload_group/"), new Route(PUT, "_wlm/workload_group/")); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + try (XContentParser parser = request.contentParser()) { + CreateWorkloadGroupRequest createWorkloadGroupRequest = CreateWorkloadGroupRequest.fromXContent(parser); + return channel -> client.execute( + CreateWorkloadGroupAction.INSTANCE, + createWorkloadGroupRequest, + createWorkloadGroupResponse(channel) + ); + } + } + + private RestResponseListener createWorkloadGroupResponse(final RestChannel channel) { + return new RestResponseListener<>(channel) { + @Override + public RestResponse buildResponse(final CreateWorkloadGroupResponse 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/rest/RestUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java index db77dc5963037..ee3564dc5c7f6 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java @@ -11,9 +11,15 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; +======== +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java new file mode 100644 index 0000000000000..5357a344da407 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule; + +import org.opensearch.autotagging.Attribute; + +import java.util.HashMap; +import java.util.Map; + +/** + * Attributes specific to the query group feature. + * @opensearch.experimental + */ +public enum QueryGroupAttribute implements Attribute { + /** + * Represents the index_pattern attribute in QueryGroupAttribute + */ + INDEX_PATTERN("index_pattern"); + + private final String name; + + QueryGroupAttribute(String name) { + this.name = name; + validateAttribute(); + } + + @Override + public String getName() { + return name; + } + + /** + * Retrieves the QueryGroupAttribute from a name string + * @param name - attribute name + */ + public static QueryGroupAttribute fromName(String name) { + for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { + if (attr.getName().equals(name)) { + return attr; + } + } + throw new IllegalArgumentException("Unknown QueryGroupAttribute: " + name); + } + + /** + * Converts the QueryGroupAttribute values into a map with attribute names as keys. + */ + public static Map toMap() { + Map map = new HashMap<>(); + for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { + map.put(attr.getName(), attr); + } + return map; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java new file mode 100644 index 0000000000000..42f45d3d7c5d6 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule; + +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.AutoTaggingRegistry; +import org.opensearch.autotagging.FeatureType; + +import java.util.Map; + +/** + * Represents a feature type specific to the query group feature + * @opensearch.experimental + */ +public class QueryGroupFeatureType implements FeatureType { + /** + * The instance for QueryGroupFeatureType + */ + public static final QueryGroupFeatureType INSTANCE = new QueryGroupFeatureType(); + /** + * Name for QueryGroupFeatureType + */ + public static final String NAME = "query_group"; + private static final int MAX_ATTRIBUTE_VALUES = 10; + private static final int MAX_ATTRIBUTE_VALUE_LENGTH = 100; + private static final Map ALLOWED_ATTRIBUTES = QueryGroupAttribute.toMap(); + + private QueryGroupFeatureType() {} + + static { + INSTANCE.registerFeatureType(); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public int getMaxNumberOfValuesPerAttribute() { + return MAX_ATTRIBUTE_VALUES; + } + + @Override + public int getMaxCharLengthPerAttributeValue() { + return MAX_ATTRIBUTE_VALUE_LENGTH; + } + + @Override + public Map getAllowedAttributesRegistry() { + return ALLOWED_ATTRIBUTES; + } + + @Override + public void registerFeatureType() { + AutoTaggingRegistry.registerFeatureType(INSTANCE); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java new file mode 100644 index 0000000000000..84e068900568e --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.action; + +import org.opensearch.ResourceNotFoundException; +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.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.rule.service.RulePersistenceService; +import org.opensearch.tasks.Task; +import org.opensearch.transport.TransportService; + +/** + * Transport action to update Rule in workload management + * @opensearch.experimental + */ +public class TransportUpdateWlmRuleAction extends HandledTransportAction { + + private final IndexStoredRulePersistenceService rulePersistenceService; + + /** + * Constructor for TransportUpdateWlmRuleAction + * + * @param transportService - a {@link TransportService} object + * @param actionFilters - a {@link ActionFilters} object + * @param rulePersistenceService - a {@link RulePersistenceService} object + */ + @Inject + public TransportUpdateWlmRuleAction( + TransportService transportService, + ActionFilters actionFilters, + IndexStoredRulePersistenceService rulePersistenceService + ) { + super(UpdateWlmRuleAction.NAME, transportService, actionFilters, UpdateRuleRequest::new); + this.rulePersistenceService = rulePersistenceService; + } + + @Override + protected void doExecute(Task task, UpdateRuleRequest request, ActionListener listener) { + String queryGroupId = request.getFeatureValue(); + if (queryGroupId != null + && !rulePersistenceService.getClusterService().state().metadata().queryGroups().containsKey(queryGroupId)) { + listener.onFailure(new ResourceNotFoundException("Couldn't find an existing query group with id: " + queryGroupId)); + return; + } + rulePersistenceService.updateRule(request, listener); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/UpdateWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/UpdateWlmRuleAction.java new file mode 100644 index 0000000000000..a7182f20f9fb5 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/UpdateWlmRuleAction.java @@ -0,0 +1,37 @@ +/* + * 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; +import org.opensearch.rule.action.UpdateRuleResponse; + +/** + * Action type for updating a Rule in workload management + * + * @opensearch.experimental + */ +public class UpdateWlmRuleAction extends ActionType { + + /** + * An instance of UpdateWlmRuleAction + */ + public static final UpdateWlmRuleAction INSTANCE = new UpdateWlmRuleAction(); + + /** + * Name for UpdateWlmRuleAction + */ + public static final String NAME = "cluster:admin/opensearch/wlm/rule/_update"; + + /** + * Default constructor + */ + private UpdateWlmRuleAction() { + super(NAME, UpdateRuleResponse::new); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java new file mode 100644 index 0000000000000..b9fb278dae5b0 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * Package for the action classes related to rules in WorkloadManagementPlugin + */ +package org.opensearch.plugin.wlm.rule.action; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleAction.java new file mode 100644 index 0000000000000..88b1b1a9a3813 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleAction.java @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.rule.rest; + +import org.opensearch.action.ActionType; +import org.opensearch.autotagging.Attribute; +import org.opensearch.autotagging.FeatureType; +import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; +import org.opensearch.plugin.wlm.rule.action.UpdateWlmRuleAction; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; +import org.opensearch.rule.rest.RestUpdateRuleAction; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.rest.RestRequest.Method.POST; +import static org.opensearch.rest.RestRequest.Method.PUT; + +/** + * Rest action to update a workload management Rule + * @opensearch.experimental + */ +public class RestUpdateWlmRuleAction extends RestUpdateRuleAction { + + /** + * Constructor for RestUpdateWlmRuleAction + */ + public RestUpdateWlmRuleAction() { + super(); + } + + @Override + public String getName() { + return "update_rule"; + } + + @Override + public List routes() { + return List.of(new Route(POST, "_wlm/rule/{_id}"), new Route(PUT, "_wlm/rule/{_id}")); + } + + @Override + @SuppressWarnings("unchecked") + protected > T retrieveUpdateRuleActionInstance() { + return (T) UpdateWlmRuleAction.INSTANCE; + } + + @Override + protected FeatureType retrieveFeatureTypeInstance() { + return QueryGroupFeatureType.INSTANCE; + } + + @Override + protected UpdateRuleRequest buildUpdateRuleRequest( + String id, + String description, + Map> attributeMap, + String featureValue + ) { + return new UpdateRuleRequest(id, description, attributeMap, featureValue, QueryGroupFeatureType.INSTANCE); + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java new file mode 100644 index 0000000000000..1d82e4fea71e5 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * Package for the rest classes related to rules in WorkloadManagementPlugin + */ +package org.opensearch.plugin.wlm.rule.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/service/QueryGroupPersistenceService.java new file mode 100644 index 0000000000000..39b259410dfd5 --- /dev/null +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceService.java @@ -0,0 +1,372 @@ +/* + * 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.service; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.support.clustermanager.AcknowledgedResponse; +import org.opensearch.cluster.AckedClusterStateUpdateTask; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.ClusterStateUpdateTask; +import org.opensearch.cluster.metadata.Metadata; +import org.opensearch.cluster.metadata.WorkloadGroup; +import org.opensearch.cluster.service.ClusterManagerTaskThrottler; +import org.opensearch.cluster.service.ClusterManagerTaskThrottler.ThrottlingKey; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.Priority; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.ClusterSettings; +import org.opensearch.common.settings.Setting; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.rest.RestStatus; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/WorkloadGroupPersistenceService.java +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; +import org.opensearch.wlm.MutableWorkloadGroupFragment; +======== +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; +import org.opensearch.wlm.MutableQueryGroupFragment; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.java +import org.opensearch.wlm.ResourceType; + +import java.util.Collection; +import java.util.EnumMap; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.opensearch.cluster.metadata.WorkloadGroup.updateExistingWorkloadGroup; + +/** + * This class defines the functions for WorkloadGroup persistence + */ +public class WorkloadGroupPersistenceService { + static final String SOURCE = "query-group-persistence-service"; + private static final String CREATE_QUERY_GROUP_THROTTLING_KEY = "create-query-group"; + private static final String DELETE_QUERY_GROUP_THROTTLING_KEY = "delete-query-group"; + private static final String UPDATE_QUERY_GROUP_THROTTLING_KEY = "update-query-group"; + private static final Logger logger = LogManager.getLogger(WorkloadGroupPersistenceService.class); + /** + * max WorkloadGroup count setting name + */ + public static final String QUERY_GROUP_COUNT_SETTING_NAME = "node.workload_group.max_count"; + /** + * default max workloadGroup count on any node at any given point in time + */ + private static final int DEFAULT_MAX_QUERY_GROUP_COUNT_VALUE = 100; + /** + * min workloadGroup count on any node at any given point in time + */ + private static final int MIN_QUERY_GROUP_COUNT_VALUE = 1; + /** + * max WorkloadGroup count setting + */ + public static final Setting MAX_QUERY_GROUP_COUNT = Setting.intSetting( + QUERY_GROUP_COUNT_SETTING_NAME, + DEFAULT_MAX_QUERY_GROUP_COUNT_VALUE, + 0, + WorkloadGroupPersistenceService::validateMaxWorkloadGroupCount, + Setting.Property.Dynamic, + Setting.Property.NodeScope + ); + private final ClusterService clusterService; + private volatile int maxWorkloadGroupCount; + final ThrottlingKey createWorkloadGroupThrottlingKey; + final ThrottlingKey deleteWorkloadGroupThrottlingKey; + final ThrottlingKey updateWorkloadGroupThrottlingKey; + + /** + * Constructor for WorkloadGroupPersistenceService + * + * @param clusterService {@link ClusterService} - The cluster service to be used by WorkloadGroupPersistenceService + * @param settings {@link Settings} - The settings to be used by WorkloadGroupPersistenceService + * @param clusterSettings {@link ClusterSettings} - The cluster settings to be used by WorkloadGroupPersistenceService + */ + @Inject + public WorkloadGroupPersistenceService( + final ClusterService clusterService, + final Settings settings, + final ClusterSettings clusterSettings + ) { + this.clusterService = clusterService; + this.createWorkloadGroupThrottlingKey = clusterService.registerClusterManagerTask(CREATE_QUERY_GROUP_THROTTLING_KEY, true); + this.deleteWorkloadGroupThrottlingKey = clusterService.registerClusterManagerTask(DELETE_QUERY_GROUP_THROTTLING_KEY, true); + this.updateWorkloadGroupThrottlingKey = clusterService.registerClusterManagerTask(UPDATE_QUERY_GROUP_THROTTLING_KEY, true); + setMaxWorkloadGroupCount(MAX_QUERY_GROUP_COUNT.get(settings)); + clusterSettings.addSettingsUpdateConsumer(MAX_QUERY_GROUP_COUNT, this::setMaxWorkloadGroupCount); + } + + /** + * Set maxWorkloadGroupCount to be newMaxWorkloadGroupCount + * @param newMaxWorkloadGroupCount - the max number of WorkloadGroup allowed + */ + public void setMaxWorkloadGroupCount(int newMaxWorkloadGroupCount) { + validateMaxWorkloadGroupCount(newMaxWorkloadGroupCount); + this.maxWorkloadGroupCount = newMaxWorkloadGroupCount; + } + + /** + * Validator for maxWorkloadGroupCount + * @param maxWorkloadGroupCount - the maxWorkloadGroupCount number to be verified + */ + private static void validateMaxWorkloadGroupCount(int maxWorkloadGroupCount) { + if (maxWorkloadGroupCount > DEFAULT_MAX_QUERY_GROUP_COUNT_VALUE || maxWorkloadGroupCount < MIN_QUERY_GROUP_COUNT_VALUE) { + throw new IllegalArgumentException(QUERY_GROUP_COUNT_SETTING_NAME + " should be in range [1-100]."); + } + } + + /** + * Update cluster state to include the new WorkloadGroup + * @param workloadGroup {@link WorkloadGroup} - the WorkloadGroup we're currently creating + * @param listener - ActionListener for CreateWorkloadGroupResponse + */ + public void persistInClusterStateMetadata(WorkloadGroup workloadGroup, ActionListener listener) { + clusterService.submitStateUpdateTask(SOURCE, new ClusterStateUpdateTask(Priority.NORMAL) { + @Override + public ClusterState execute(ClusterState currentState) throws Exception { + return saveWorkloadGroupInClusterState(workloadGroup, currentState); + } + + @Override + public ThrottlingKey getClusterManagerThrottlingKey() { + return createWorkloadGroupThrottlingKey; + } + + @Override + public void onFailure(String source, Exception e) { + logger.warn("failed to save WorkloadGroup object due to error: {}, for source: {}.", e.getMessage(), source); + listener.onFailure(e); + } + + @Override + public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) { + CreateWorkloadGroupResponse response = new CreateWorkloadGroupResponse(workloadGroup, RestStatus.OK); + listener.onResponse(response); + } + }); + } + + /** + * This method will be executed before we submit the new cluster state + * @param workloadGroup - the WorkloadGroup we're currently creating + * @param currentClusterState - the cluster state before the update + */ + ClusterState saveWorkloadGroupInClusterState(final WorkloadGroup workloadGroup, final ClusterState currentClusterState) { + final Map existingWorkloadGroups = currentClusterState.metadata().workloadGroups(); + String groupName = workloadGroup.getName(); + + // check if maxWorkloadGroupCount will breach + if (existingWorkloadGroups.size() == maxWorkloadGroupCount) { + logger.warn("{} value exceeded its assigned limit of {}.", QUERY_GROUP_COUNT_SETTING_NAME, maxWorkloadGroupCount); + throw new IllegalStateException("Can't create more than " + maxWorkloadGroupCount + " WorkloadGroups in the system."); + } + + // check for duplicate name + Optional findExistingGroup = existingWorkloadGroups.values() + .stream() + .filter(group -> group.getName().equals(groupName)) + .findFirst(); + if (findExistingGroup.isPresent()) { + logger.warn("WorkloadGroup with name {} already exists. Not creating a new one.", groupName); + throw new IllegalArgumentException("WorkloadGroup with name " + groupName + " already exists. Not creating a new one."); + } + + // check if there's any resource allocation that exceed limit of 1.0 + validateTotalUsage(existingWorkloadGroups, groupName, workloadGroup.getResourceLimits()); + + return ClusterState.builder(currentClusterState) + .metadata(Metadata.builder(currentClusterState.metadata()).put(workloadGroup).build()) + .build(); + } + + /** + * Get the WorkloadGroups with the specified name from cluster state + * @param name - the WorkloadGroup name we are getting + * @param currentState - current cluster state + */ + public static Collection getFromClusterStateMetadata(String name, ClusterState currentState) { + final Map currentGroups = currentState.getMetadata().workloadGroups(); + if (name == null || name.isEmpty()) { + return currentGroups.values(); + } + return currentGroups.values() + .stream() + .filter(group -> group.getName().equals(name)) + .findAny() + .stream() + .collect(Collectors.toList()); + } + + /** + * Modify cluster state to delete the WorkloadGroup + * @param deleteWorkloadGroupRequest - request to delete a WorkloadGroup + * @param listener - ActionListener for AcknowledgedResponse + */ + public void deleteInClusterStateMetadata( + DeleteWorkloadGroupRequest deleteWorkloadGroupRequest, + ActionListener listener + ) { + clusterService.submitStateUpdateTask(SOURCE, new AckedClusterStateUpdateTask<>(deleteWorkloadGroupRequest, listener) { + @Override + public ClusterState execute(ClusterState currentState) { + return deleteWorkloadGroupInClusterState(deleteWorkloadGroupRequest.getName(), currentState); + } + + @Override + public ClusterManagerTaskThrottler.ThrottlingKey getClusterManagerThrottlingKey() { + return deleteWorkloadGroupThrottlingKey; + } + + @Override + protected AcknowledgedResponse newResponse(boolean acknowledged) { + return new AcknowledgedResponse(acknowledged); + } + }); + } + + /** + * Modify cluster state to delete the WorkloadGroup, and return the new cluster state + * @param name - the name for WorkloadGroup to be deleted + * @param currentClusterState - current cluster state + */ + ClusterState deleteWorkloadGroupInClusterState(final String name, final ClusterState currentClusterState) { + final Metadata metadata = currentClusterState.metadata(); + final WorkloadGroup workloadGroupToRemove = metadata.workloadGroups() + .values() + .stream() + .filter(workloadGroup -> workloadGroup.getName().equals(name)) + .findAny() + .orElseThrow(() -> new ResourceNotFoundException("No WorkloadGroup exists with the provided name: " + name)); + + return ClusterState.builder(currentClusterState).metadata(Metadata.builder(metadata).remove(workloadGroupToRemove).build()).build(); + } + + /** + * Modify cluster state to update the WorkloadGroup + * @param toUpdateGroup {@link WorkloadGroup} - the WorkloadGroup that we want to update + * @param listener - ActionListener for UpdateWorkloadGroupResponse + */ + public void updateInClusterStateMetadata( + UpdateWorkloadGroupRequest toUpdateGroup, + ActionListener listener + ) { + clusterService.submitStateUpdateTask(SOURCE, new ClusterStateUpdateTask(Priority.NORMAL) { + @Override + public ClusterState execute(ClusterState currentState) { + return updateWorkloadGroupInClusterState(toUpdateGroup, currentState); + } + + @Override + public ThrottlingKey getClusterManagerThrottlingKey() { + return updateWorkloadGroupThrottlingKey; + } + + @Override + public void onFailure(String source, Exception e) { + logger.warn("Failed to update WorkloadGroup due to error: {}, for source: {}", e.getMessage(), source); + listener.onFailure(e); + } + + @Override + public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) { + String name = toUpdateGroup.getName(); + Optional findUpdatedGroup = newState.metadata() + .workloadGroups() + .values() + .stream() + .filter(group -> group.getName().equals(name)) + .findFirst(); + assert findUpdatedGroup.isPresent(); + WorkloadGroup updatedGroup = findUpdatedGroup.get(); + UpdateWorkloadGroupResponse response = new UpdateWorkloadGroupResponse(updatedGroup, RestStatus.OK); + listener.onResponse(response); + } + }); + } + + /** + * Modify cluster state to update the existing WorkloadGroup + * @param updateWorkloadGroupRequest {@link WorkloadGroup} - the WorkloadGroup that we want to update + * @param currentState - current cluster state + */ + ClusterState updateWorkloadGroupInClusterState(UpdateWorkloadGroupRequest updateWorkloadGroupRequest, ClusterState currentState) { + final Metadata metadata = currentState.metadata(); + final Map existingGroups = currentState.metadata().workloadGroups(); + String name = updateWorkloadGroupRequest.getName(); + MutableWorkloadGroupFragment mutableWorkloadGroupFragment = updateWorkloadGroupRequest.getmMutableWorkloadGroupFragment(); + + final WorkloadGroup existingGroup = existingGroups.values() + .stream() + .filter(group -> group.getName().equals(name)) + .findFirst() + .orElseThrow(() -> new ResourceNotFoundException("No WorkloadGroup exists with the provided name: " + name)); + + validateTotalUsage(existingGroups, name, mutableWorkloadGroupFragment.getResourceLimits()); + return ClusterState.builder(currentState) + .metadata( + Metadata.builder(metadata) + .remove(existingGroup) + .put(updateExistingWorkloadGroup(existingGroup, mutableWorkloadGroupFragment)) + .build() + ) + .build(); + } + + /** + * This method checks if there's any resource allocation that exceed limit of 1.0 + * @param existingWorkloadGroups - existing WorkloadGroups in the system + * @param resourceLimits - the WorkloadGroup we're creating or updating + */ + private void validateTotalUsage( + Map existingWorkloadGroups, + String name, + Map resourceLimits + ) { + if (resourceLimits == null || resourceLimits.isEmpty()) { + return; + } + final Map totalUsage = new EnumMap<>(ResourceType.class); + totalUsage.putAll(resourceLimits); + for (WorkloadGroup currGroup : existingWorkloadGroups.values()) { + if (!currGroup.getName().equals(name)) { + for (ResourceType resourceType : resourceLimits.keySet()) { + totalUsage.compute(resourceType, (k, v) -> v + currGroup.getResourceLimits().getOrDefault(resourceType, 0.0)); + } + } + } + totalUsage.forEach((resourceType, total) -> { + if (total > 1.0) { + logger.warn("Total resource allocation for {} will go above the max limit of 1.0.", resourceType.getName()); + throw new IllegalArgumentException( + "Total resource allocation for " + resourceType.getName() + " will go above the max limit of 1.0." + ); + } + }); + } + + /** + * maxWorkloadGroupCount getter + */ + public int getMaxWorkloadGroupCount() { + return maxWorkloadGroupCount; + } + + /** + * clusterService getter + */ + public ClusterService getClusterService() { + return clusterService; + } +} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java index 8fd5fe5dfcfed..4d7f7d9aabc4d 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java @@ -27,11 +27,18 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.action.ActionListener; import org.opensearch.core.rest.RestStatus; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/WorkloadGroupPersistenceService.java import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; import org.opensearch.wlm.MutableWorkloadGroupFragment; +======== +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; +import org.opensearch.wlm.MutableQueryGroupFragment; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.java import org.opensearch.wlm.ResourceType; import java.util.Collection; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java new file mode 100644 index 0000000000000..d206238118734 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java @@ -0,0 +1,172 @@ +/* + * 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.cluster.ClusterName; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.metadata.Metadata; +import org.opensearch.cluster.metadata.WorkloadGroup; +import org.opensearch.cluster.service.ClusterApplierService; +import org.opensearch.cluster.service.ClusterManagerService; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.collect.Tuple; +import org.opensearch.common.settings.ClusterSettings; +import org.opensearch.common.settings.Setting; +import org.opensearch.common.settings.Settings; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java +import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/QueryGroupTestUtils.java +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.wlm.MutableWorkloadGroupFragment; +import org.opensearch.wlm.ResourceType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.cluster.metadata.WorkloadGroup.builder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +public class WorkloadGroupTestUtils { + public static final String NAME_ONE = "workload_group_one"; + public static final String NAME_TWO = "workload_group_two"; + public static final String _ID_ONE = "AgfUO5Ja9yfsYlONlYi3TQ=="; + public static final String _ID_TWO = "G5iIqHy4g7eK1qIAAAAIH53=1"; + public static final String NAME_NONE_EXISTED = "workload_group_none_existed"; + public static final long TIMESTAMP_ONE = 4513232413L; + public static final long TIMESTAMP_TWO = 4513232415L; + public static final WorkloadGroup workloadGroupOne = builder().name(NAME_ONE) + ._id(_ID_ONE) + .mutableWorkloadGroupFragment( + new MutableWorkloadGroupFragment(MutableWorkloadGroupFragment.ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.3)) + ) + .updatedAt(TIMESTAMP_ONE) + .build(); + + public static final WorkloadGroup workloadGroupTwo = builder().name(NAME_TWO) + ._id(_ID_TWO) + .mutableWorkloadGroupFragment( + new MutableWorkloadGroupFragment(MutableWorkloadGroupFragment.ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.6)) + ) + .updatedAt(TIMESTAMP_TWO) + .build(); + + public static List workloadGroupList() { + List list = new ArrayList<>(); + list.add(workloadGroupOne); + list.add(workloadGroupTwo); + return list; + } + + public static ClusterState clusterState() { + final Metadata metadata = Metadata.builder().workloadGroups(Map.of(_ID_ONE, workloadGroupOne, _ID_TWO, workloadGroupTwo)).build(); + return ClusterState.builder(new ClusterName("_name")).metadata(metadata).build(); + } + + public static Set> clusterSettingsSet() { + Set> set = new HashSet<>(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); + set.add(WorkloadGroupPersistenceService.MAX_QUERY_GROUP_COUNT); + assertFalse(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS.contains(WorkloadGroupPersistenceService.MAX_QUERY_GROUP_COUNT)); + return set; + } + + public static Settings settings() { + return Settings.builder().build(); + } + + public static ClusterSettings clusterSettings() { + return new ClusterSettings(settings(), clusterSettingsSet()); + } + + public static WorkloadGroupPersistenceService workloadGroupPersistenceService() { + ClusterApplierService clusterApplierService = new ClusterApplierService( + "name", + settings(), + clusterSettings(), + mock(ThreadPool.class) + ); + clusterApplierService.setInitialState(clusterState()); + ClusterService clusterService = new ClusterService( + settings(), + clusterSettings(), + mock(ClusterManagerService.class), + clusterApplierService + ); + return new WorkloadGroupPersistenceService(clusterService, settings(), clusterSettings()); + } + + public static Tuple preparePersistenceServiceSetup( + Map workloadGroups + ) { + Metadata metadata = Metadata.builder().workloadGroups(workloadGroups).build(); + Settings settings = Settings.builder().build(); + ClusterState clusterState = ClusterState.builder(new ClusterName("_name")).metadata(metadata).build(); + ClusterSettings clusterSettings = new ClusterSettings(settings, clusterSettingsSet()); + ClusterApplierService clusterApplierService = new ClusterApplierService( + "name", + settings(), + clusterSettings(), + mock(ThreadPool.class) + ); + clusterApplierService.setInitialState(clusterState); + ClusterService clusterService = new ClusterService( + settings(), + clusterSettings(), + mock(ClusterManagerService.class), + clusterApplierService + ); + WorkloadGroupPersistenceService workloadGroupPersistenceService = new WorkloadGroupPersistenceService( + clusterService, + settings, + clusterSettings + ); + return new Tuple(workloadGroupPersistenceService, clusterState); + } + + public static void assertEqualResourceLimits( + Map resourceLimitMapOne, + Map resourceLimitMapTwo + ) { + assertTrue(resourceLimitMapOne.keySet().containsAll(resourceLimitMapTwo.keySet())); + assertTrue(resourceLimitMapOne.values().containsAll(resourceLimitMapTwo.values())); + } + + public static void assertEqualWorkloadGroups( + Collection collectionOne, + Collection collectionTwo, + boolean assertUpdateAt + ) { + assertEquals(collectionOne.size(), collectionTwo.size()); + List listOne = new ArrayList<>(collectionOne); + List listTwo = new ArrayList<>(collectionTwo); + listOne.sort(Comparator.comparing(WorkloadGroup::getName)); + listTwo.sort(Comparator.comparing(WorkloadGroup::getName)); + for (int i = 0; i < listOne.size(); i++) { + if (assertUpdateAt) { + WorkloadGroup one = listOne.get(i); + WorkloadGroup two = listTwo.get(i); + assertEquals(one.getName(), two.getName()); + assertEquals(one.getResourceLimits(), two.getResourceLimits()); + assertEquals(one.getResiliencyMode(), two.getResiliencyMode()); + assertEquals(one.get_id(), two.get_id()); + } else { + assertEquals(listOne.get(i), listTwo.get(i)); + } + } + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java index bac644a172c1e..49e258f05619b 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm; +package org.opensearch.plugin.wlm.querygroup; import org.opensearch.cluster.ClusterName; import org.opensearch.cluster.ClusterState; @@ -19,7 +19,11 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/QueryGroupTestUtils.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.wlm.MutableWorkloadGroupFragment; import org.opensearch.wlm.ResourceType; 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/action/CreateQueryGroupRequestTests.java new file mode 100644 index 0000000000000..a756e2dadb2c6 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequestTests.java @@ -0,0 +1,46 @@ +/* + * 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.querygroup.action; + +import org.opensearch.cluster.metadata.WorkloadGroup; +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.assertEqualWorkloadGroups; +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.assertEqualQueryGroups; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequestTests.java + +public class CreateWorkloadGroupRequestTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of CreateWorkloadGroupRequest. + */ + public void testSerialization() throws IOException { + CreateWorkloadGroupRequest request = new CreateWorkloadGroupRequest(workloadGroupOne); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + CreateWorkloadGroupRequest otherRequest = new CreateWorkloadGroupRequest(streamInput); + List list1 = new ArrayList<>(); + List list2 = new ArrayList<>(); + list1.add(workloadGroupOne); + list2.add(otherRequest.getWorkloadGroup()); + assertEqualWorkloadGroups(list1, list2, false); + } +} 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/action/CreateQueryGroupResponseTests.java new file mode 100644 index 0000000000000..59d2fa5fd97fa --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponseTests.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.action; + +import org.opensearch.cluster.metadata.WorkloadGroup; +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; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java +import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponseTests.java +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.Mockito.mock; + +public class CreateWorkloadGroupResponseTests extends OpenSearchTestCase { + + /** + * Test case to verify serialization and deserialization of CreateWorkloadGroupResponse. + */ + public void testSerialization() throws IOException { + CreateWorkloadGroupResponse response = new CreateWorkloadGroupResponse(WorkloadGroupTestUtils.workloadGroupOne, RestStatus.OK); + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + CreateWorkloadGroupResponse otherResponse = new CreateWorkloadGroupResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + WorkloadGroup responseGroup = response.getWorkloadGroup(); + WorkloadGroup otherResponseGroup = otherResponse.getWorkloadGroup(); + List listOne = new ArrayList<>(); + List listTwo = new ArrayList<>(); + listOne.add(responseGroup); + listTwo.add(otherResponseGroup); + WorkloadGroupTestUtils.assertEqualWorkloadGroups(listOne, listTwo, false); + } + + /** + * Test case to validate the toXContent method of CreateWorkloadGroupResponse. + */ + public void testToXContentCreateWorkloadGroup() throws IOException { + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + CreateWorkloadGroupResponse response = new CreateWorkloadGroupResponse(WorkloadGroupTestUtils.workloadGroupOne, RestStatus.OK); + String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + + " \"_id\" : \"AgfUO5Ja9yfsYlONlYi3TQ==\",\n" + + " \"name\" : \"workload_group_one\",\n" + + " \"resiliency_mode\" : \"monitor\",\n" + + " \"resource_limits\" : {\n" + + " \"memory\" : 0.3\n" + + " },\n" + + " \"updated_at\" : 4513232413\n" + + "}"; + assertEquals(expected, actual); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java index 31d3ea00b7bda..a756e2dadb2c6 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java @@ -6,19 +6,25 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; import java.util.ArrayList; import java.util.List; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.assertEqualWorkloadGroups; import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.assertEqualQueryGroups; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequestTests.java public class CreateWorkloadGroupRequestTests extends OpenSearchTestCase { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java index d25050341f997..59d2fa5fd97fa 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java @@ -15,7 +15,12 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponseTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; 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/action/DeleteQueryGroupRequestTests.java new file mode 100644 index 0000000000000..c7fecfc3095ae --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequestTests.java @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.action; + +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java +import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequestTests.java +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; + +public class DeleteWorkloadGroupRequestTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of DeleteWorkloadGroupRequest. + */ + public void testSerialization() throws IOException { + DeleteWorkloadGroupRequest request = new DeleteWorkloadGroupRequest(WorkloadGroupTestUtils.NAME_ONE); + assertEquals(WorkloadGroupTestUtils.NAME_ONE, request.getName()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + DeleteWorkloadGroupRequest otherRequest = new DeleteWorkloadGroupRequest(streamInput); + assertEquals(request.getName(), otherRequest.getName()); + } + + /** + * Test case to validate a DeleteWorkloadGroupRequest. + */ + public void testSerializationWithNull() throws IOException { + DeleteWorkloadGroupRequest request = new DeleteWorkloadGroupRequest((String) null); + ActionRequestValidationException actionRequestValidationException = request.validate(); + assertFalse(actionRequestValidationException.getMessage().isEmpty()); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java index a7fa0939583c5..c7fecfc3095ae 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java @@ -11,7 +11,12 @@ import org.opensearch.action.ActionRequestValidationException; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequestTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; 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/action/GetQueryGroupRequestTests.java new file mode 100644 index 0000000000000..683e88251b733 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequestTests.java @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugin.wlm.action; + +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java +import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequestTests.java +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; + +public class GetWorkloadGroupRequestTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of GetWorkloadGroupRequest. + */ + public void testSerialization() throws IOException { + GetWorkloadGroupRequest request = new GetWorkloadGroupRequest(WorkloadGroupTestUtils.NAME_ONE); + assertEquals(WorkloadGroupTestUtils.NAME_ONE, request.getName()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + GetWorkloadGroupRequest otherRequest = new GetWorkloadGroupRequest(streamInput); + assertEquals(request.getName(), otherRequest.getName()); + } + + /** + * Test case to verify the serialization and deserialization of GetWorkloadGroupRequest when name is null. + */ + public void testSerializationWithNull() throws IOException { + GetWorkloadGroupRequest request = new GetWorkloadGroupRequest((String) null); + assertNull(request.getName()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + GetWorkloadGroupRequest otherRequest = new GetWorkloadGroupRequest(streamInput); + assertEquals(request.getName(), otherRequest.getName()); + } + + /** + * Test case the validation function of GetWorkloadGroupRequest + */ + public void testValidation() { + GetWorkloadGroupRequest request = new GetWorkloadGroupRequest("a".repeat(51)); + assertThrows(IllegalArgumentException.class, request::validate); + } +} 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/action/GetQueryGroupResponseTests.java new file mode 100644 index 0000000000000..b0ce2da8f07b8 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponseTests.java @@ -0,0 +1,156 @@ +/* + * 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.action; + +import org.opensearch.cluster.metadata.WorkloadGroup; +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; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java +import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponseTests.java +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.Mockito.mock; + +public class GetWorkloadGroupResponseTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of GetWorkloadGroupResponse. + */ + public void testSerializationSingleWorkloadGroup() throws IOException { + List list = new ArrayList<>(); + list.add(WorkloadGroupTestUtils.workloadGroupOne); + GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(list, RestStatus.OK); + assertEquals(response.getWorkloadGroups(), list); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetWorkloadGroupResponse otherResponse = new GetWorkloadGroupResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + WorkloadGroupTestUtils.assertEqualWorkloadGroups(response.getWorkloadGroups(), otherResponse.getWorkloadGroups(), false); + } + + /** + * Test case to verify the serialization and deserialization of GetWorkloadGroupResponse when the result contains multiple WorkloadGroups. + */ + public void testSerializationMultipleWorkloadGroup() throws IOException { + GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(WorkloadGroupTestUtils.workloadGroupList(), RestStatus.OK); + assertEquals(response.getWorkloadGroups(), WorkloadGroupTestUtils.workloadGroupList()); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetWorkloadGroupResponse otherResponse = new GetWorkloadGroupResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + assertEquals(2, otherResponse.getWorkloadGroups().size()); + WorkloadGroupTestUtils.assertEqualWorkloadGroups(response.getWorkloadGroups(), otherResponse.getWorkloadGroups(), false); + } + + /** + * Test case to verify the serialization and deserialization of GetWorkloadGroupResponse when the result is empty. + */ + public void testSerializationNull() throws IOException { + List list = new ArrayList<>(); + GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(list, RestStatus.OK); + assertEquals(response.getWorkloadGroups(), list); + + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + + GetWorkloadGroupResponse otherResponse = new GetWorkloadGroupResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + assertEquals(0, otherResponse.getWorkloadGroups().size()); + } + + /** + * Test case to verify the toXContent of GetWorkloadGroupResponse. + */ + public void testToXContentGetSingleWorkloadGroup() throws IOException { + List workloadGroupList = new ArrayList<>(); + workloadGroupList.add(WorkloadGroupTestUtils.workloadGroupOne); + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(workloadGroupList, RestStatus.OK); + String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + + " \"workload_groups\" : [\n" + + " {\n" + + " \"_id\" : \"AgfUO5Ja9yfsYlONlYi3TQ==\",\n" + + " \"name\" : \"workload_group_one\",\n" + + " \"resiliency_mode\" : \"monitor\",\n" + + " \"resource_limits\" : {\n" + + " \"memory\" : 0.3\n" + + " },\n" + + " \"updated_at\" : 4513232413\n" + + " }\n" + + " ]\n" + + "}"; + assertEquals(expected, actual); + } + + /** + * Test case to verify the toXContent of GetWorkloadGroupResponse when the result contains multiple WorkloadGroups. + */ + public void testToXContentGetMultipleWorkloadGroup() throws IOException { + List workloadGroupList = new ArrayList<>(); + workloadGroupList.add(WorkloadGroupTestUtils.workloadGroupOne); + workloadGroupList.add(WorkloadGroupTestUtils.workloadGroupTwo); + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(workloadGroupList, RestStatus.OK); + String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + + " \"workload_groups\" : [\n" + + " {\n" + + " \"_id\" : \"AgfUO5Ja9yfsYlONlYi3TQ==\",\n" + + " \"name\" : \"workload_group_one\",\n" + + " \"resiliency_mode\" : \"monitor\",\n" + + " \"resource_limits\" : {\n" + + " \"memory\" : 0.3\n" + + " },\n" + + " \"updated_at\" : 4513232413\n" + + " },\n" + + " {\n" + + " \"_id\" : \"G5iIqHy4g7eK1qIAAAAIH53=1\",\n" + + " \"name\" : \"workload_group_two\",\n" + + " \"resiliency_mode\" : \"monitor\",\n" + + " \"resource_limits\" : {\n" + + " \"memory\" : 0.6\n" + + " },\n" + + " \"updated_at\" : 4513232415\n" + + " }\n" + + " ]\n" + + "}"; + assertEquals(expected, actual); + } + + /** + * Test case to verify toXContent of GetWorkloadGroupResponse when the result contains zero WorkloadGroup. + */ + public void testToXContentGetZeroWorkloadGroup() throws IOException { + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + GetWorkloadGroupResponse otherResponse = new GetWorkloadGroupResponse(new ArrayList<>(), RestStatus.OK); + String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + " \"workload_groups\" : [ ]\n" + "}"; + assertEquals(expected, actual); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java index 832761d5084bb..683e88251b733 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java @@ -10,7 +10,12 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequestTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java index dc0aeabc7a033..b0ce2da8f07b8 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java @@ -15,7 +15,12 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponseTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; 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/action/QueryGroupActionTestUtils.java new file mode 100644 index 0000000000000..618db92643a8f --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/QueryGroupActionTestUtils.java @@ -0,0 +1,18 @@ +/* + * 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.action; + +import org.opensearch.plugin.wlm.action.UpdateQueryGroupRequest; +import org.opensearch.wlm.MutableQueryGroupFragment; + +public class QueryGroupActionTestUtils { + public static UpdateQueryGroupRequest updateQueryGroupRequest(String name, MutableQueryGroupFragment mutableQueryGroupFragment) { + return new UpdateQueryGroupRequest(name, 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/action/TransportDeleteQueryGroupActionTests.java new file mode 100644 index 0000000000000..0f891cf46bc4a --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupActionTests.java @@ -0,0 +1,69 @@ +/* + * 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.action; + +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.clustermanager.AcknowledgedResponse; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.core.action.ActionListener; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.TransportDeleteWorkloadGroupAction; +import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.java +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportService; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class TransportDeleteWorkloadGroupActionTests extends OpenSearchTestCase { + + ClusterService clusterService = mock(ClusterService.class); + TransportService transportService = mock(TransportService.class); + ActionFilters actionFilters = mock(ActionFilters.class); + ThreadPool threadPool = mock(ThreadPool.class); + IndexNameExpressionResolver indexNameExpressionResolver = mock(IndexNameExpressionResolver.class); + WorkloadGroupPersistenceService workloadGroupPersistenceService = mock(WorkloadGroupPersistenceService.class); + + TransportDeleteWorkloadGroupAction action = new TransportDeleteWorkloadGroupAction( + clusterService, + transportService, + actionFilters, + threadPool, + indexNameExpressionResolver, + workloadGroupPersistenceService + ); + + /** + * Test case to validate the construction for TransportDeleteWorkloadGroupAction + */ + public void testConstruction() { + assertNotNull(action); + assertEquals(ThreadPool.Names.SAME, action.executor()); + } + + /** + * Test case to validate the clusterManagerOperation function in TransportDeleteWorkloadGroupAction + */ + public void testClusterManagerOperation() throws Exception { + DeleteWorkloadGroupRequest request = new DeleteWorkloadGroupRequest("testGroup"); + @SuppressWarnings("unchecked") + ActionListener listener = mock(ActionListener.class); + ClusterState clusterState = mock(ClusterState.class); + action.clusterManagerOperation(request, clusterState, listener); + verify(workloadGroupPersistenceService).deleteInClusterStateMetadata(eq(request), eq(listener)); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java index 7ffa33aa8a80a..0f891cf46bc4a 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java @@ -14,7 +14,13 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.action.ActionListener; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.TransportDeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; +======== +import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.java import org.opensearch.test.OpenSearchTestCase; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupActionTests.java new file mode 100644 index 0000000000000..c38b53206f63e --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupActionTests.java @@ -0,0 +1,59 @@ +/* + * 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.action; + +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.support.ActionFilters; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.core.action.ActionListener; +import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.TransportGetWorkloadGroupAction; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportService; + +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_NONE_EXISTED; +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.clusterState; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_NONE_EXISTED; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterState; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupActionTests.java +import static org.mockito.Mockito.mock; + +public class TransportGetWorkloadGroupActionTests extends OpenSearchTestCase { + + /** + * Test case for ClusterManagerOperation function + */ + @SuppressWarnings("unchecked") + public void testClusterManagerOperation() throws Exception { + GetWorkloadGroupRequest getWorkloadGroupRequest1 = new GetWorkloadGroupRequest(NAME_NONE_EXISTED); + GetWorkloadGroupRequest getWorkloadGroupRequest2 = new GetWorkloadGroupRequest(NAME_ONE); + TransportGetWorkloadGroupAction transportGetWorkloadGroupAction = new TransportGetWorkloadGroupAction( + mock(ClusterService.class), + mock(TransportService.class), + mock(ActionFilters.class), + mock(ThreadPool.class), + mock(IndexNameExpressionResolver.class) + ); + assertThrows( + ResourceNotFoundException.class, + () -> transportGetWorkloadGroupAction.clusterManagerOperation( + getWorkloadGroupRequest1, + clusterState(), + mock(ActionListener.class) + ) + ); + transportGetWorkloadGroupAction.clusterManagerOperation(getWorkloadGroupRequest2, clusterState(), mock(ActionListener.class)); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java index cf12d9f6408cf..c38b53206f63e 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java @@ -13,13 +13,21 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.action.ActionListener; +import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; +import org.opensearch.plugin.wlm.action.TransportGetWorkloadGroupAction; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_NONE_EXISTED; import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.clusterState; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_NONE_EXISTED; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterState; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupActionTests.java import static org.mockito.Mockito.mock; public class TransportGetWorkloadGroupActionTests extends OpenSearchTestCase { 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/action/UpdateQueryGroupRequestTests.java new file mode 100644 index 0000000000000..db7c3a1540bf8 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequestTests.java @@ -0,0 +1,105 @@ +/* + * 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.querygroup.action; + +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.wlm.MutableWorkloadGroupFragment; +import org.opensearch.wlm.MutableWorkloadGroupFragment.ResiliencyMode; +import org.opensearch.wlm.ResourceType; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequestTests.java + +public class UpdateWorkloadGroupRequestTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of UpdateWorkloadGroupRequest. + */ + public void testSerialization() throws IOException { + UpdateWorkloadGroupRequest request = new UpdateWorkloadGroupRequest(NAME_ONE, workloadGroupOne.getMutableWorkloadGroupFragment()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateWorkloadGroupRequest otherRequest = new UpdateWorkloadGroupRequest(streamInput); + assertEquals(request.getName(), otherRequest.getName()); + assertEquals(request.getmMutableWorkloadGroupFragment(), otherRequest.getmMutableWorkloadGroupFragment()); + } + + /** + * Test case to verify the serialization and deserialization of UpdateWorkloadGroupRequest with only name field. + */ + public void testSerializationOnlyName() throws IOException { + UpdateWorkloadGroupRequest request = new UpdateWorkloadGroupRequest( + NAME_ONE, + new MutableWorkloadGroupFragment(null, new HashMap<>()) + ); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateWorkloadGroupRequest otherRequest = new UpdateWorkloadGroupRequest(streamInput); + assertEquals(request.getName(), otherRequest.getName()); + assertEquals(request.getmMutableWorkloadGroupFragment(), otherRequest.getmMutableWorkloadGroupFragment()); + } + + /** + * Test case to verify the serialization and deserialization of UpdateWorkloadGroupRequest with only resourceLimits field. + */ + public void testSerializationOnlyResourceLimit() throws IOException { + UpdateWorkloadGroupRequest request = new UpdateWorkloadGroupRequest( + NAME_ONE, + new MutableWorkloadGroupFragment(null, Map.of(ResourceType.MEMORY, 0.4)) + ); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateWorkloadGroupRequest otherRequest = new UpdateWorkloadGroupRequest(streamInput); + assertEquals(request.getName(), otherRequest.getName()); + assertEquals(request.getmMutableWorkloadGroupFragment(), otherRequest.getmMutableWorkloadGroupFragment()); + } + + /** + * Tests invalid ResourceType. + */ + public void testInvalidResourceLimitList() { + assertThrows( + IllegalArgumentException.class, + () -> new UpdateWorkloadGroupRequest( + NAME_ONE, + new MutableWorkloadGroupFragment( + ResiliencyMode.MONITOR, + Map.of(ResourceType.MEMORY, 0.3, ResourceType.fromName("random"), 0.4) + ) + ) + ); + } + + /** + * Tests invalid resiliencyMode. + */ + public void testInvalidEnforcement() { + assertThrows( + IllegalArgumentException.class, + () -> new UpdateWorkloadGroupRequest( + NAME_ONE, + new MutableWorkloadGroupFragment(ResiliencyMode.fromName("random"), Map.of(ResourceType.fromName("memory"), 0.3)) + ) + ); + } +} 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/action/UpdateQueryGroupResponseTests.java new file mode 100644 index 0000000000000..8923d069c396a --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponseTests.java @@ -0,0 +1,76 @@ +/* + * 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.action; + +import org.opensearch.cluster.metadata.WorkloadGroup; +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; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java +import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java +import static org.mockito.Mockito.mock; + +public class UpdateWorkloadGroupResponseTests extends OpenSearchTestCase { + + /** + * Test case to verify the serialization and deserialization of UpdateWorkloadGroupResponse. + */ + public void testSerialization() throws IOException { + UpdateWorkloadGroupResponse response = new UpdateWorkloadGroupResponse(workloadGroupOne, RestStatus.OK); + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateWorkloadGroupResponse otherResponse = new UpdateWorkloadGroupResponse(streamInput); + assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); + WorkloadGroup responseGroup = response.getWorkloadGroup(); + WorkloadGroup otherResponseGroup = otherResponse.getWorkloadGroup(); + List list1 = new ArrayList<>(); + List list2 = new ArrayList<>(); + list1.add(responseGroup); + list2.add(otherResponseGroup); + WorkloadGroupTestUtils.assertEqualWorkloadGroups(list1, list2, false); + } + + /** + * Test case to verify the toXContent method of UpdateWorkloadGroupResponse. + */ + public void testToXContentUpdateSingleWorkloadGroup() throws IOException { + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + UpdateWorkloadGroupResponse otherResponse = new UpdateWorkloadGroupResponse(workloadGroupOne, RestStatus.OK); + String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + + " \"_id\" : \"AgfUO5Ja9yfsYlONlYi3TQ==\",\n" + + " \"name\" : \"workload_group_one\",\n" + + " \"resiliency_mode\" : \"monitor\",\n" + + " \"resource_limits\" : {\n" + + " \"memory\" : 0.3\n" + + " },\n" + + " \"updated_at\" : 4513232413\n" + + "}"; + assertEquals(expected, actual); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java index e8d883da5c6eb..db7c3a1540bf8 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.action; +package org.opensearch.plugin.wlm.querygroup.action; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; @@ -19,8 +19,13 @@ import java.util.HashMap; import java.util.Map; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequestTests.java public class UpdateWorkloadGroupRequestTests extends OpenSearchTestCase { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java index 97b9b9029373f..8923d069c396a 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java @@ -15,14 +15,23 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; +======== +import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; import java.util.ArrayList; import java.util.List; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java import static org.mockito.Mockito.mock; public class UpdateWorkloadGroupResponseTests extends OpenSearchTestCase { 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/rest/RestDeleteQueryGroupActionTests.java new file mode 100644 index 0000000000000..1fb83e02ad12d --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupActionTests.java @@ -0,0 +1,95 @@ +/* + * 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.rest; + +import org.opensearch.action.support.clustermanager.AcknowledgedResponse; +import org.opensearch.common.CheckedConsumer; +import org.opensearch.common.unit.TimeValue; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; +import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +======== +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java +import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestHandler; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.action.RestToXContentListener; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.test.rest.FakeRestRequest; +import org.opensearch.transport.client.node.NodeClient; + +import java.util.List; + +import org.mockito.ArgumentCaptor; + +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java +import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java +import static org.opensearch.rest.RestRequest.Method.DELETE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +public class RestDeleteWorkloadGroupActionTests extends OpenSearchTestCase { + /** + * Test case to validate the construction for RestDeleteWorkloadGroupAction + */ + public void testConstruction() { + RestDeleteWorkloadGroupAction action = new RestDeleteWorkloadGroupAction(); + assertNotNull(action); + assertEquals("delete_workload_group", action.getName()); + List routes = action.routes(); + assertEquals(1, routes.size()); + RestHandler.Route route = routes.get(0); + assertEquals(DELETE, route.getMethod()); + assertEquals("_wlm/workload_group/{name}", route.getPath()); + } + + /** + * Test case to validate the prepareRequest logic for RestDeleteWorkloadGroupAction + */ + @SuppressWarnings("unchecked") + public void testPrepareRequest() throws Exception { + RestDeleteWorkloadGroupAction restDeleteWorkloadGroupAction = new RestDeleteWorkloadGroupAction(); + NodeClient nodeClient = mock(NodeClient.class); + RestRequest realRequest = new FakeRestRequest(); + realRequest.params().put("name", NAME_ONE); + ; + RestRequest spyRequest = spy(realRequest); + + doReturn(TimeValue.timeValueSeconds(30)).when(spyRequest).paramAsTime(eq("cluster_manager_timeout"), any(TimeValue.class)); + doReturn(TimeValue.timeValueSeconds(60)).when(spyRequest).paramAsTime(eq("timeout"), any(TimeValue.class)); + + CheckedConsumer consumer = restDeleteWorkloadGroupAction.prepareRequest(spyRequest, nodeClient); + assertNotNull(consumer); + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(DeleteWorkloadGroupRequest.class); + ArgumentCaptor> listenerCaptor = ArgumentCaptor.forClass(RestToXContentListener.class); + doNothing().when(nodeClient).execute(eq(DeleteWorkloadGroupAction.INSTANCE), requestCaptor.capture(), listenerCaptor.capture()); + + consumer.accept(mock(RestChannel.class)); + DeleteWorkloadGroupRequest capturedRequest = requestCaptor.getValue(); + assertEquals(NAME_ONE, capturedRequest.getName()); + assertEquals(TimeValue.timeValueSeconds(30), capturedRequest.clusterManagerNodeTimeout()); + assertEquals(TimeValue.timeValueSeconds(60), capturedRequest.timeout()); + verify(nodeClient).execute( + eq(DeleteWorkloadGroupAction.INSTANCE), + any(DeleteWorkloadGroupRequest.class), + any(RestToXContentListener.class) + ); + } +} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java index 8ce5c869f4481..1fb83e02ad12d 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java @@ -11,8 +11,14 @@ import org.opensearch.action.support.clustermanager.AcknowledgedResponse; import org.opensearch.common.CheckedConsumer; import org.opensearch.common.unit.TimeValue; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; +======== +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java +import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestHandler; import org.opensearch.rest.RestRequest; @@ -25,7 +31,11 @@ import org.mockito.ArgumentCaptor; +<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; +======== +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; +>>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java import static org.opensearch.rest.RestRequest.Method.DELETE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleActionTests.java new file mode 100644 index 0000000000000..b14ebc47c5a0a --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleActionTests.java @@ -0,0 +1,37 @@ + +/* + * 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 RestUpdateWlmRuleActionTests extends OpenSearchTestCase { + /** + * Test case to validate the construction for RestGetRuleAction + */ + public void testConstruction() { + RestUpdateWlmRuleAction action = new RestUpdateWlmRuleAction(); + assertNotNull(action); + assertEquals("update_rule", action.getName()); + List routes = action.routes(); + assertEquals(2, routes.size()); + RestHandler.Route route = routes.get(0); + assertEquals(POST, route.getMethod()); + assertEquals("_wlm/rule/{_id}", route.getPath()); + route = routes.get(1); + assertEquals(PUT, route.getMethod()); + assertEquals("_wlm/rule/{_id}", route.getPath()); + } +} 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/service/QueryGroupPersistenceServiceTests.java new file mode 100644 index 0000000000000..4b95a63394118 --- /dev/null +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceServiceTests.java @@ -0,0 +1,515 @@ +/* + * 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.service; + +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.support.clustermanager.AcknowledgedResponse; +import org.opensearch.cluster.AckedClusterStateUpdateTask; +import org.opensearch.cluster.ClusterName; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.ClusterStateUpdateTask; +import org.opensearch.cluster.metadata.Metadata; +import org.opensearch.cluster.metadata.QueryGroup; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.collect.Tuple; +import org.opensearch.common.settings.ClusterSettings; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.action.ActionListener; +import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; +import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; +import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; +import org.opensearch.plugin.wlm.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; +import org.opensearch.wlm.MutableQueryGroupFragment.ResiliencyMode; +import org.opensearch.wlm.ResourceType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.mockito.ArgumentCaptor; + +import static org.opensearch.cluster.metadata.QueryGroup.builder; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_NONE_EXISTED; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_TWO; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils._ID_ONE; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils._ID_TWO; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.assertEqualQueryGroups; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterSettings; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterSettingsSet; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterState; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.preparePersistenceServiceSetup; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupList; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupPersistenceService; +import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupTwo; +import static org.opensearch.plugin.wlm.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; +import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class QueryGroupPersistenceServiceTests extends OpenSearchTestCase { + + /** + * Test case to validate the creation logic of a QueryGroup + */ + public void testCreateQueryGroup() { + Tuple setup = preparePersistenceServiceSetup(new HashMap<>()); + QueryGroupPersistenceService queryGroupPersistenceService1 = setup.v1(); + ClusterState clusterState = setup.v2(); + ClusterState newClusterState = queryGroupPersistenceService1.saveQueryGroupInClusterState(queryGroupOne, clusterState); + Map updatedGroupsMap = newClusterState.getMetadata().queryGroups(); + assertEquals(1, updatedGroupsMap.size()); + assertTrue(updatedGroupsMap.containsKey(_ID_ONE)); + List listOne = new ArrayList<>(); + List listTwo = new ArrayList<>(); + listOne.add(queryGroupOne); + listTwo.add(updatedGroupsMap.get(_ID_ONE)); + assertEqualQueryGroups(listOne, listTwo, false); + } + + /** + * Test case to validate the logic for adding a new QueryGroup to a cluster state that already contains + * an existing QueryGroup + */ + public void testCreateAnotherQueryGroup() { + Tuple setup = preparePersistenceServiceSetup(Map.of(_ID_ONE, queryGroupOne)); + QueryGroupPersistenceService queryGroupPersistenceService1 = setup.v1(); + ClusterState clusterState = setup.v2(); + ClusterState newClusterState = queryGroupPersistenceService1.saveQueryGroupInClusterState(queryGroupTwo, clusterState); + Map updatedGroups = newClusterState.getMetadata().queryGroups(); + assertEquals(2, updatedGroups.size()); + assertTrue(updatedGroups.containsKey(_ID_TWO)); + Collection values = updatedGroups.values(); + assertEqualQueryGroups(queryGroupList(), new ArrayList<>(values), false); + } + + /** + * Test case to ensure the error is thrown when we try to create another QueryGroup with duplicate name + */ + public void testCreateQueryGroupDuplicateName() { + Tuple setup = preparePersistenceServiceSetup(Map.of(_ID_ONE, queryGroupOne)); + QueryGroupPersistenceService queryGroupPersistenceService1 = setup.v1(); + ClusterState clusterState = setup.v2(); + QueryGroup toCreate = builder().name(NAME_ONE) + ._id("W5iIqHyhgi4K1qIAAAAIHw==") + .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.3))) + .updatedAt(1690934400000L) + .build(); + assertThrows(RuntimeException.class, () -> queryGroupPersistenceService1.saveQueryGroupInClusterState(toCreate, clusterState)); + } + + /** + * Test case to ensure the error is thrown when we try to create another QueryGroup that will make + * the total resource limits go above 1 + */ + public void testCreateQueryGroupOverflowAllocation() { + Tuple setup = preparePersistenceServiceSetup(Map.of(_ID_TWO, queryGroupTwo)); + QueryGroup toCreate = builder().name(NAME_ONE) + ._id("W5iIqHyhgi4K1qIAAAAIHw==") + .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.41))) + .updatedAt(1690934400000L) + .build(); + + QueryGroupPersistenceService queryGroupPersistenceService1 = setup.v1(); + ClusterState clusterState = setup.v2(); + assertThrows(RuntimeException.class, () -> queryGroupPersistenceService1.saveQueryGroupInClusterState(toCreate, clusterState)); + } + + /** + * Test case to ensure the error is thrown when we already have the max allowed number of QueryGroups, but + * we want to create another one + */ + public void testCreateQueryGroupOverflowCount() { + QueryGroup toCreate = builder().name(NAME_NONE_EXISTED) + ._id("W5iIqHyhgi4K1qIAAAAIHw==") + .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.5))) + .updatedAt(1690934400000L) + .build(); + Metadata metadata = Metadata.builder().queryGroups(Map.of(_ID_ONE, queryGroupOne, _ID_TWO, queryGroupTwo)).build(); + Settings settings = Settings.builder().put(QUERY_GROUP_COUNT_SETTING_NAME, 2).build(); + ClusterSettings clusterSettings = new ClusterSettings(settings, clusterSettingsSet()); + ClusterService clusterService = new ClusterService(settings, clusterSettings, mock(ThreadPool.class)); + ClusterState clusterState = ClusterState.builder(new ClusterName("_name")).metadata(metadata).build(); + QueryGroupPersistenceService queryGroupPersistenceService1 = new QueryGroupPersistenceService( + clusterService, + settings, + clusterSettings + ); + assertThrows(RuntimeException.class, () -> queryGroupPersistenceService1.saveQueryGroupInClusterState(toCreate, clusterState)); + } + + /** + * Tests the invalid value of {@code node.query_group.max_count} + */ + public void testInvalidMaxQueryGroupCount() { + Settings settings = Settings.builder().put(QUERY_GROUP_COUNT_SETTING_NAME, 2).build(); + ClusterSettings clusterSettings = new ClusterSettings(settings, clusterSettingsSet()); + ClusterService clusterService = new ClusterService(settings, clusterSettings, mock(ThreadPool.class)); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + settings, + clusterSettings + ); + assertThrows(IllegalArgumentException.class, () -> queryGroupPersistenceService.setMaxQueryGroupCount(-1)); + } + + /** + * Tests the valid value of {@code node.query_group.max_count} + */ + public void testValidMaxSandboxCountSetting() { + Settings settings = Settings.builder().put(QUERY_GROUP_COUNT_SETTING_NAME, 100).build(); + ClusterService clusterService = new ClusterService(settings, clusterSettings(), mock(ThreadPool.class)); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + settings, + clusterSettings() + ); + queryGroupPersistenceService.setMaxQueryGroupCount(50); + assertEquals(50, queryGroupPersistenceService.getMaxQueryGroupCount()); + } + + /** + * Tests PersistInClusterStateMetadata function + */ + public void testPersistInClusterStateMetadata() { + ClusterService clusterService = mock(ClusterService.class); + @SuppressWarnings("unchecked") + ActionListener listener = mock(ActionListener.class); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + QueryGroupTestUtils.settings(), + clusterSettings() + ); + queryGroupPersistenceService.persistInClusterStateMetadata(queryGroupOne, listener); + verify(clusterService).submitStateUpdateTask(eq(SOURCE), any()); + } + + /** + * Tests PersistInClusterStateMetadata function with inner functions + */ + public void testPersistInClusterStateMetadataInner() { + ClusterService clusterService = mock(ClusterService.class); + @SuppressWarnings("unchecked") + ActionListener listener = mock(ActionListener.class); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + QueryGroupTestUtils.settings(), + clusterSettings() + ); + ArgumentCaptor captor = ArgumentCaptor.forClass(ClusterStateUpdateTask.class); + queryGroupPersistenceService.persistInClusterStateMetadata(queryGroupOne, listener); + verify(clusterService, times(1)).submitStateUpdateTask(eq(SOURCE), captor.capture()); + ClusterStateUpdateTask capturedTask = captor.getValue(); + assertEquals(queryGroupPersistenceService.createQueryGroupThrottlingKey, capturedTask.getClusterManagerThrottlingKey()); + + doAnswer(invocation -> { + ClusterStateUpdateTask task = invocation.getArgument(1); + task.clusterStateProcessed(SOURCE, mock(ClusterState.class), mock(ClusterState.class)); + return null; + }).when(clusterService).submitStateUpdateTask(anyString(), any()); + queryGroupPersistenceService.persistInClusterStateMetadata(queryGroupOne, listener); + verify(listener).onResponse(any(CreateQueryGroupResponse.class)); + } + + /** + * Tests PersistInClusterStateMetadata function with failure + */ + public void testPersistInClusterStateMetadataFailure() { + ClusterService clusterService = mock(ClusterService.class); + @SuppressWarnings("unchecked") + ActionListener listener = mock(ActionListener.class); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + QueryGroupTestUtils.settings(), + clusterSettings() + ); + doAnswer(invocation -> { + ClusterStateUpdateTask task = invocation.getArgument(1); + Exception exception = new RuntimeException("Test Exception"); + task.onFailure(SOURCE, exception); + return null; + }).when(clusterService).submitStateUpdateTask(anyString(), any()); + queryGroupPersistenceService.persistInClusterStateMetadata(queryGroupOne, listener); + verify(listener).onFailure(any(RuntimeException.class)); + } + + /** + * Tests getting a single QueryGroup + */ + public void testGetSingleQueryGroup() { + Collection groupsCollections = QueryGroupPersistenceService.getFromClusterStateMetadata(NAME_ONE, clusterState()); + List groups = new ArrayList<>(groupsCollections); + assertEquals(1, groups.size()); + QueryGroup queryGroup = groups.get(0); + List listOne = new ArrayList<>(); + List listTwo = new ArrayList<>(); + listOne.add(QueryGroupTestUtils.queryGroupOne); + listTwo.add(queryGroup); + QueryGroupTestUtils.assertEqualQueryGroups(listOne, listTwo, false); + } + + /** + * Tests getting all QueryGroups + */ + public void testGetAllQueryGroups() { + assertEquals(2, QueryGroupTestUtils.clusterState().metadata().queryGroups().size()); + Collection groupsCollections = QueryGroupPersistenceService.getFromClusterStateMetadata(null, clusterState()); + List res = new ArrayList<>(groupsCollections); + assertEquals(2, res.size()); + Set currentNAME = res.stream().map(QueryGroup::getName).collect(Collectors.toSet()); + assertTrue(currentNAME.contains(QueryGroupTestUtils.NAME_ONE)); + assertTrue(currentNAME.contains(QueryGroupTestUtils.NAME_TWO)); + QueryGroupTestUtils.assertEqualQueryGroups(QueryGroupTestUtils.queryGroupList(), res, false); + } + + /** + * Tests getting a QueryGroup with invalid name + */ + public void testGetNonExistedQueryGroups() { + Collection groupsCollections = QueryGroupPersistenceService.getFromClusterStateMetadata( + NAME_NONE_EXISTED, + clusterState() + ); + List groups = new ArrayList<>(groupsCollections); + assertEquals(0, groups.size()); + } + + /** + * Tests setting maxQueryGroupCount + */ + public void testMaxQueryGroupCount() { + assertThrows(IllegalArgumentException.class, () -> QueryGroupTestUtils.queryGroupPersistenceService().setMaxQueryGroupCount(-1)); + QueryGroupPersistenceService queryGroupPersistenceService = QueryGroupTestUtils.queryGroupPersistenceService(); + queryGroupPersistenceService.setMaxQueryGroupCount(50); + assertEquals(50, queryGroupPersistenceService.getMaxQueryGroupCount()); + } + + /** + * Tests delete a single QueryGroup + */ + public void testDeleteSingleQueryGroup() { + ClusterState newClusterState = queryGroupPersistenceService().deleteQueryGroupInClusterState(NAME_TWO, clusterState()); + Map afterDeletionGroups = newClusterState.getMetadata().queryGroups(); + assertFalse(afterDeletionGroups.containsKey(_ID_TWO)); + assertEquals(1, afterDeletionGroups.size()); + List oldQueryGroups = new ArrayList<>(); + oldQueryGroups.add(queryGroupOne); + assertEqualQueryGroups(new ArrayList<>(afterDeletionGroups.values()), oldQueryGroups, false); + } + + /** + * Tests delete a QueryGroup with invalid name + */ + public void testDeleteNonExistedQueryGroup() { + assertThrows( + ResourceNotFoundException.class, + () -> queryGroupPersistenceService().deleteQueryGroupInClusterState(NAME_NONE_EXISTED, clusterState()) + ); + } + + /** + * Tests DeleteInClusterStateMetadata function + */ + @SuppressWarnings("unchecked") + public void testDeleteInClusterStateMetadata() throws Exception { + DeleteQueryGroupRequest request = new DeleteQueryGroupRequest(NAME_ONE); + ClusterService clusterService = mock(ClusterService.class); + + ActionListener listener = mock(ActionListener.class); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + QueryGroupTestUtils.settings(), + clusterSettings() + ); + doAnswer(invocation -> { + AckedClusterStateUpdateTask task = invocation.getArgument(1); + ClusterState initialState = clusterState(); + ClusterState newState = task.execute(initialState); + assertNotNull(newState); + assertEquals(queryGroupPersistenceService.deleteQueryGroupThrottlingKey, task.getClusterManagerThrottlingKey()); + task.onAllNodesAcked(null); + verify(listener).onResponse(argThat(response -> response.isAcknowledged())); + return null; + }).when(clusterService).submitStateUpdateTask(anyString(), any()); + queryGroupPersistenceService.deleteInClusterStateMetadata(request, listener); + verify(clusterService).submitStateUpdateTask(eq(SOURCE), any(AckedClusterStateUpdateTask.class)); + } + + /** + * Tests updating a QueryGroup with all fields + */ + public void testUpdateQueryGroupAllFields() { + QueryGroup updated = builder().name(NAME_ONE) + ._id(_ID_ONE) + .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.ENFORCED, Map.of(ResourceType.MEMORY, 0.15))) + .updatedAt(1690934400000L) + .build(); + UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest(NAME_ONE, updated.getMutableQueryGroupFragment()); + ClusterState newClusterState = queryGroupPersistenceService().updateQueryGroupInClusterState( + updateQueryGroupRequest, + clusterState() + ); + List updatedQueryGroups = new ArrayList<>(newClusterState.getMetadata().queryGroups().values()); + assertEquals(2, updatedQueryGroups.size()); + List expectedList = new ArrayList<>(); + expectedList.add(queryGroupTwo); + expectedList.add(updated); + assertEqualQueryGroups(expectedList, updatedQueryGroups, true); + } + + /** + * Tests updating a QueryGroup with only updated resourceLimits + */ + public void testUpdateQueryGroupResourceLimitsOnly() { + QueryGroup updated = builder().name(NAME_ONE) + ._id(_ID_ONE) + .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.15))) + .updatedAt(1690934400000L) + .build(); + UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest(NAME_ONE, updated.getMutableQueryGroupFragment()); + ClusterState newClusterState = queryGroupPersistenceService().updateQueryGroupInClusterState( + updateQueryGroupRequest, + clusterState() + ); + List updatedQueryGroups = new ArrayList<>(newClusterState.getMetadata().queryGroups().values()); + assertEquals(2, updatedQueryGroups.size()); + Optional findUpdatedGroupOne = newClusterState.metadata() + .queryGroups() + .values() + .stream() + .filter(group -> group.getName().equals(NAME_ONE)) + .findFirst(); + Optional findUpdatedGroupTwo = newClusterState.metadata() + .queryGroups() + .values() + .stream() + .filter(group -> group.getName().equals(NAME_TWO)) + .findFirst(); + assertTrue(findUpdatedGroupOne.isPresent()); + assertTrue(findUpdatedGroupTwo.isPresent()); + List list1 = new ArrayList<>(); + list1.add(updated); + List list2 = new ArrayList<>(); + list2.add(findUpdatedGroupOne.get()); + assertEqualQueryGroups(list1, list2, true); + } + + /** + * Tests updating a QueryGroup with invalid name + */ + public void testUpdateQueryGroupNonExistedName() { + QueryGroupPersistenceService queryGroupPersistenceService = queryGroupPersistenceService(); + UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest( + NAME_NONE_EXISTED, + new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.15)) + ); + assertThrows( + RuntimeException.class, + () -> queryGroupPersistenceService.updateQueryGroupInClusterState(updateQueryGroupRequest, clusterState()) + ); + List updatedQueryGroups = new ArrayList<>( + queryGroupPersistenceService.getClusterService().state().metadata().queryGroups().values() + ); + assertEquals(2, updatedQueryGroups.size()); + List expectedList = new ArrayList<>(); + expectedList.add(queryGroupTwo); + expectedList.add(queryGroupOne); + assertEqualQueryGroups(expectedList, updatedQueryGroups, true); + } + + /** + * Tests UpdateInClusterStateMetadata function + */ + public void testUpdateInClusterStateMetadata() { + ClusterService clusterService = mock(ClusterService.class); + @SuppressWarnings("unchecked") + ActionListener listener = mock(ActionListener.class); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + QueryGroupTestUtils.settings(), + clusterSettings() + ); + queryGroupPersistenceService.updateInClusterStateMetadata(null, listener); + verify(clusterService).submitStateUpdateTask(eq(SOURCE), any()); + } + + /** + * Tests UpdateInClusterStateMetadata function with inner functions + */ + public void testUpdateInClusterStateMetadataInner() { + ClusterService clusterService = mock(ClusterService.class); + @SuppressWarnings("unchecked") + ActionListener listener = mock(ActionListener.class); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + QueryGroupTestUtils.settings(), + clusterSettings() + ); + UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest( + NAME_TWO, + new MutableQueryGroupFragment(ResiliencyMode.SOFT, new HashMap<>()) + ); + ArgumentCaptor captor = ArgumentCaptor.forClass(ClusterStateUpdateTask.class); + queryGroupPersistenceService.updateInClusterStateMetadata(updateQueryGroupRequest, listener); + verify(clusterService, times(1)).submitStateUpdateTask(eq(SOURCE), captor.capture()); + ClusterStateUpdateTask capturedTask = captor.getValue(); + assertEquals(queryGroupPersistenceService.updateQueryGroupThrottlingKey, capturedTask.getClusterManagerThrottlingKey()); + + doAnswer(invocation -> { + ClusterStateUpdateTask task = invocation.getArgument(1); + task.clusterStateProcessed(SOURCE, clusterState(), clusterState()); + return null; + }).when(clusterService).submitStateUpdateTask(anyString(), any()); + queryGroupPersistenceService.updateInClusterStateMetadata(updateQueryGroupRequest, listener); + verify(listener).onResponse(any(UpdateQueryGroupResponse.class)); + } + + /** + * Tests UpdateInClusterStateMetadata function with failure + */ + public void testUpdateInClusterStateMetadataFailure() { + ClusterService clusterService = mock(ClusterService.class); + @SuppressWarnings("unchecked") + ActionListener listener = mock(ActionListener.class); + QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( + clusterService, + QueryGroupTestUtils.settings(), + clusterSettings() + ); + UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest( + NAME_TWO, + new MutableQueryGroupFragment(ResiliencyMode.SOFT, new HashMap<>()) + ); + doAnswer(invocation -> { + ClusterStateUpdateTask task = invocation.getArgument(1); + Exception exception = new RuntimeException("Test Exception"); + task.onFailure(SOURCE, exception); + return null; + }).when(clusterService).submitStateUpdateTask(anyString(), any()); + queryGroupPersistenceService.updateInClusterStateMetadata(updateQueryGroupRequest, listener); + verify(listener).onFailure(any(RuntimeException.class)); + } +} From 0c5b312819c9b8ba7c5aaeace81e0cc50cabb460 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Sun, 6 Apr 2025 00:08:55 -0700 Subject: [PATCH 02/11] modify based on comments Signed-off-by: Ruirui Zhang --- .../rule/action/CreateRuleResponse.java | 81 ----------------- .../rule/action/GetRuleResponse.java | 2 + .../rule/action/UpdateRuleRequest.java | 18 +++- .../rule/action/UpdateRuleResponse.java | 26 +++--- .../rule/rest/RestUpdateRuleAction.java | 64 +++++++------- .../IndexStoredRulePersistenceService.java | 77 +++++------------ .../rule/utils/IndexStoredRuleParser.java | 2 +- .../rule/utils/IndexStoredRuleUtils.java | 12 ++- .../rule/action/UpdateRuleResponseTests.java | 6 +- ...ndexStoredRulePersistenceServiceTests.java | 86 +++++++------------ .../rule/utils/IndexStoredRuleUtilsTests.java | 6 +- .../rule/autotagging/RuleValidator.java | 29 +++---- .../action/TransportUpdateWlmRuleAction.java | 13 +-- .../rule/rest/RestUpdateWlmRuleAction.java | 70 --------------- .../plugin/wlm/rule/rest/package-info.java | 12 --- .../rest/RestUpdateWlmRuleActionTests.java | 37 -------- 16 files changed, 146 insertions(+), 395 deletions(-) delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleActionTests.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java deleted file mode 100644 index aef3936c554c3..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.action; - -import org.opensearch.autotagging.Rule; -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 java.io.IOException; -import java.util.Map; - -import static org.opensearch.autotagging.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; - - /** - * contructor for CreateRuleResponse - * @param id - the id for the rule created - * @param rule - the rule created - * @param restStatus - the status of CreateRuleResponse - */ - public CreateRuleResponse(String id, final Rule rule, RestStatus restStatus) { - this._id = id; - this.rule = rule; - this.restStatus = restStatus; - } - - /** - * Constructs a CreateRuleResponse from a StreamInput for deserialization - * @param in - The {@link StreamInput} instance to read from. - */ - 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/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java index 110522ff86af6..5ddb9eb712e7d 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java @@ -9,6 +9,7 @@ package org.opensearch.rule.action; import org.opensearch.autotagging.Rule; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; @@ -40,6 +41,7 @@ * } * @opensearch.experimental */ +@ExperimentalApi public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { private final Map rules; private final String searchAfter; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java index ffd029f9cd996..36db5213dfec0 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java @@ -13,18 +13,29 @@ import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.FeatureType; import org.opensearch.autotagging.RuleValidator; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; import java.io.IOException; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; /** * A request for update Rule + * Example request: + * Note that the endpoint "localhost:9200/_wlm/rule" serves only as an example endpoint here + * curl -XPUT "localhost:9200/_wlm/rule/{rule_id}" -H 'Content-Type: application/json' -d ' + * { + * "description": "description", + * "index_pattern": ["log*", "event*"], + * "query_group": "dev_query_group_id_2" + * }' * @opensearch.experimental */ +@ExperimentalApi public class UpdateRuleRequest extends ActionRequest { private final String _id; private final String description; @@ -70,7 +81,12 @@ public UpdateRuleRequest(StreamInput in) throws IOException { @Override public ActionRequestValidationException validate() { RuleValidator validator = new RuleValidator(description, attributeMap, featureValue, null, featureType); - validator.validateUpdatingRuleParams(); + List errors = validator.validateUpdatingRuleParams(); + if (!errors.isEmpty()) { + ActionRequestValidationException validationException = new ActionRequestValidationException(); + validationException.addValidationErrors(errors); + return validationException; + } return null; } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java index 005d587b02fb3..163618b36d014 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java @@ -9,10 +9,10 @@ package org.opensearch.rule.action; import org.opensearch.autotagging.Rule; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; @@ -24,23 +24,29 @@ /** * Response for the update API for Rule + * Example response: + * { + * _id": "z1MJApUB0zgMcDmz-UQq", + * "description": "Rule for tagging query_group_id to index123" + * "index_pattern": ["index123"], + * "query_group": "query_group_id", + * "updated_at": "2025-02-14T01:19:22.589Z" + * } * @opensearch.experimental */ +@ExperimentalApi public class UpdateRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { private final String _id; private final Rule rule; - private final RestStatus restStatus; /** * constructor for UpdateRuleResponse * @param _id - rule id updated * @param rule - the updated rule - * @param restStatus - the status of UpdateRuleResponse */ - public UpdateRuleResponse(String _id, final Rule rule, RestStatus restStatus) { + public UpdateRuleResponse(String _id, final Rule rule) { this._id = _id; this.rule = rule; - this.restStatus = restStatus; } /** @@ -48,14 +54,13 @@ public UpdateRuleResponse(String _id, final Rule rule, RestStatus restStatus) { * @param in - The {@link StreamInput} instance to read from. */ public UpdateRuleResponse(StreamInput in) throws IOException { - this(in.readString(), new Rule(in), RestStatus.readFrom(in)); + this(in.readString(), new Rule(in)); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeString(_id); rule.writeTo(out); - RestStatus.writeTo(out, restStatus); } @Override @@ -76,11 +81,4 @@ public String get_id() { public Rule getRule() { return rule; } - - /** - * restStatus getter - */ - public RestStatus getRestStatus() { - return restStatus; - } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java index 9f52503884cbc..c68dd43105409 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java @@ -9,9 +9,9 @@ package org.opensearch.rule.rest; import org.opensearch.action.ActionType; -import org.opensearch.autotagging.Attribute; import org.opensearch.autotagging.FeatureType; import org.opensearch.autotagging.Rule.Builder; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; @@ -27,8 +27,6 @@ import java.io.IOException; import java.util.List; -import java.util.Map; -import java.util.Set; import static org.opensearch.autotagging.Rule._ID_STRING; @@ -36,29 +34,49 @@ * Rest action to update a Rule * @opensearch.experimental */ -public abstract class RestUpdateRuleAction extends BaseRestHandler { +@ExperimentalApi +public class RestUpdateRuleAction extends BaseRestHandler { + private final String name; + private final List routes; + private final FeatureType featureType; + private final ActionType updateRuleAction; + /** * constructor for RestUpdateRuleAction + * @param name - RestUpdateRuleAction name + * @param routes the list of REST routes this action handles + * @param featureType the feature type associated with the rule + * @param updateRuleAction the action to execute for updating a rule */ - public RestUpdateRuleAction() {} + public RestUpdateRuleAction(String name, List routes, FeatureType featureType, ActionType updateRuleAction) { + this.name = name; + this.routes = routes; + this.featureType = featureType; + this.updateRuleAction = updateRuleAction; + } @Override - public abstract String getName(); + public String getName() { + return name; + } @Override - public abstract List routes(); + public List routes() { + return routes; + } @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { try (XContentParser parser = request.contentParser()) { - Builder builder = Builder.fromXContent(parser, retrieveFeatureTypeInstance()); - UpdateRuleRequest updateRuleRequest = buildUpdateRuleRequest( + Builder builder = Builder.fromXContent(parser, featureType); + UpdateRuleRequest updateRuleRequest = new UpdateRuleRequest( request.param(_ID_STRING), builder.getDescription(), builder.getAttributeMap(), - builder.getFeatureValue() + builder.getFeatureValue(), + featureType ); - return channel -> client.execute(retrieveUpdateRuleActionInstance(), updateRuleRequest, updateRuleResponse(channel)); + return channel -> client.execute(updateRuleAction, updateRuleRequest, updateRuleResponse(channel)); } } @@ -70,28 +88,4 @@ public RestResponse buildResponse(final UpdateRuleResponse response) throws Exce } }; } - - /** - * Abstract method for subclasses to provide specific ActionType Instance - */ - protected abstract > T retrieveUpdateRuleActionInstance(); - - /** - * Abstract method for subclasses to provide specific FeatureType Instance - */ - protected abstract FeatureType retrieveFeatureTypeInstance(); - - /** - * Abstract method for subclasses to provide implementation to updateRuleRequest - * @param id - rule id to update - * @param description - rule description to update - * @param attributeMap - rule attributes to update - * @param featureValue - rule feature value to update - */ - protected abstract UpdateRuleRequest buildUpdateRuleRequest( - String id, - String description, - Map> attributeMap, - String featureValue - ); } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index 31722c96c77ed..993de0e6a6b7e 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -11,7 +11,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.index.IndexRequest; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; import org.opensearch.action.update.UpdateRequest; @@ -25,7 +24,6 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.rule.action.CreateRuleResponse; import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.rule.action.UpdateRuleRequest; import org.opensearch.rule.action.UpdateRuleResponse; @@ -104,9 +102,9 @@ public void onResponse(GetRuleResponse getRuleResponse) { request, featureType ); - checkDuplicateRule(updatedRule, new ActionListener<>() { + validateNoDuplicateRule(updatedRule, new ActionListener<>() { @Override - public void onResponse(CreateRuleResponse createRuleResponse) { + public void onResponse(Void unused) { persistUpdatedRule(ruleId, updatedRule, listener); } @@ -126,33 +124,21 @@ public void onFailure(Exception e) { } /** - * Check if there's an existing Rule with the same attributes. - * For example, if there's an existing Rule with the attribute index_pattern: ["a", "b", "c"], - * then we cannot create another Rule with only one attribute index_pattern: ["b"], because the value "b" - * already exists under another Rule. Note that the conflict exists only when we have the exact same attribute - * names in the two rules (That is, a Rule with attribute "index_pattern" won't create a conflict with another - * Rule that has "index_pattern" and some other attributes). - * @param rule - The rule to update. - * @param listener - ActionListener for CreateRuleResponse + * Validates that no duplicate rule exists with the same attribute map. + * If a conflict is found, fails the listener + * @param rule - the rule we check duplicate against + * @param listener - listener for validateNoDuplicateRule response */ - public void checkDuplicateRule(Rule rule, ActionListener listener) { + private void validateNoDuplicateRule(Rule rule, ActionListener listener) { try (ThreadContext.StoredContext ctx = getContext()) { getRuleFromIndex(null, rule.getAttributeMap(), null, new ActionListener<>() { @Override public void onResponse(GetRuleResponse getRuleResponse) { - Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId( - rule.getAttributeMap(), - getRuleResponse.getRules() + Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(rule, getRuleResponse.getRules()); + duplicateRuleId.ifPresentOrElse( + id -> listener.onFailure(new IllegalArgumentException("Rule already exists under rule id " + id)), + () -> listener.onResponse(null) ); - duplicateRuleId.map(id -> { - listener.onFailure( - new IllegalArgumentException("A rule that has the same attribute values already exists under rule id " + id) - ); - return null; - }).orElseGet(() -> { - persistRule(rule, listener); - return null; - }); } @Override @@ -169,45 +155,24 @@ public void onFailure(Exception e) { * @param updatedRule - the rule we update to * @param listener - ActionListener for UpdateRuleResponse */ - public void persistUpdatedRule(String ruleId, Rule updatedRule, ActionListener listener) { + private void persistUpdatedRule(String ruleId, Rule updatedRule, ActionListener listener) { try (ThreadContext.StoredContext context = getContext()) { UpdateRequest updateRequest = new UpdateRequest(indexName, ruleId).doc( updatedRule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) ); - client.update(updateRequest, ActionListener.wrap(updateResponse -> { - listener.onResponse(new UpdateRuleResponse(ruleId, updatedRule, RestStatus.OK)); - }, e -> { - logger.warn("Failed to update Rule object due to error: {}", e.getMessage()); - listener.onFailure(e); - })); + client.update( + updateRequest, + ActionListener.wrap(updateResponse -> { listener.onResponse(new UpdateRuleResponse(ruleId, updatedRule)); }, e -> { + logger.error("Failed to update Rule object due to error: {}", e.getMessage()); + listener.onFailure(e); + }) + ); } catch (IOException e) { logger.error("Error updating rule in index: {}", indexName); listener.onFailure(new RuntimeException("Failed to update rule to index.")); } } - /** - * Persist the rule in the index - * @param rule - The rule to update. - * @param listener - ActionListener for CreateRuleResponse - */ - public void persistRule(Rule rule, ActionListener listener) { - try (ThreadContext.StoredContext ctx = getContext()) { - IndexRequest indexRequest = new IndexRequest(indexName).source( - rule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) - ); - client.index(indexRequest, ActionListener.wrap(indexResponse -> { - listener.onResponse(new CreateRuleResponse(indexResponse.getId(), rule, RestStatus.OK)); - }, e -> { - logger.warn("Failed to save Rule object due to error: {}", e.getMessage()); - listener.onFailure(e); - })); - } catch (IOException e) { - logger.error("Error saving rule to index: {}", indexName); - listener.onFailure(new RuntimeException("Failed to save rule to index.")); - } - } - /** * Entry point for the get rule api logic in persistence service. If id is provided, we only get a single rule. * Otherwise, we get all rules that satisfy the attributeFilters. @@ -216,7 +181,7 @@ public void persistRule(Rule rule, ActionListener listener) * @param searchAfter - The sort values from the last document of the previous page, used for pagination * @param listener - ActionListener for GetRuleResponse */ - public void getRuleFromIndex( + private void getRuleFromIndex( String id, Map> attributeFilters, String searchAfter, @@ -243,7 +208,7 @@ public void getRuleFromIndex( * @param searchResponse - Response received from index * @param listener - ActionListener for GetRuleResponse */ - void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { + private void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { List hits = Arrays.asList(searchResponse.getHits().getHits()); if (id != null && hits.isEmpty()) { logger.error("Rule with ID " + id + " not found."); diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java index 4d2e808a22c2d..ccf48cceb645a 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java @@ -28,7 +28,7 @@ public class IndexStoredRuleParser { /** * constructor for IndexStoredRuleParser */ - public IndexStoredRuleParser() {} + private IndexStoredRuleParser() {} private static final Logger logger = LogManager.getLogger(IndexStoredRuleParser.class); diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java index f27969e259128..072c682f3d3d8 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java +++ b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java @@ -31,7 +31,7 @@ public class IndexStoredRuleUtils { /** * constructor for IndexStoredRuleUtils */ - public IndexStoredRuleUtils() {} + private IndexStoredRuleUtils() {} /** * Builds a Boolean query to retrieve a rule by its ID or attribute filters. @@ -68,10 +68,14 @@ public static BoolQueryBuilder buildGetRuleQuery(String id, Map getDuplicateRuleId(Map> attributeMapToValidate, Map ruleMap) { + public static Optional getDuplicateRuleId(Rule rule, Map ruleMap) { + Map> attributeMapToValidate = rule.getAttributeMap(); for (Map.Entry entry : ruleMap.entrySet()) { String ruleId = entry.getKey(); Rule currRule = entry.getValue(); diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java index e5aa382a3f20b..fac087603125c 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java @@ -12,7 +12,6 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.common.xcontent.json.JsonXContent; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.test.OpenSearchTestCase; @@ -30,12 +29,11 @@ public class UpdateRuleResponseTests extends OpenSearchTestCase { * Test case to verify serialization and deserialization of UpdateRuleResponse */ public void testSerialization() throws IOException { - UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne, RestStatus.OK); + UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); UpdateRuleResponse otherResponse = new UpdateRuleResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); Rule responseRule = response.getRule(); Rule otherResponseRule = otherResponse.getRule(); assertEqualRule(responseRule, otherResponseRule, true); @@ -46,7 +44,7 @@ public void testSerialization() throws IOException { */ public void testToXContentUpdateRule() throws IOException { XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne, RestStatus.OK); + UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index 4eb64c8cf9e66..47c0382368083 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -8,62 +8,40 @@ package org.opensearch.rule.service; -import org.opensearch.action.update.UpdateRequest; -import org.opensearch.action.update.UpdateResponse; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.rule.action.UpdateRuleResponse; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.client.Client; - -import java.io.IOException; -import java.util.HashMap; - -import org.mockito.ArgumentCaptor; - -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.ruleTwo; -import static org.opensearch.rule.utils.RuleTestUtils.setUpIndexStoredRulePersistenceService; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { - public void testPersistUpdatedRule_Success() throws IOException { - IndexStoredRulePersistenceService indexStoredRulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - Client client = indexStoredRulePersistenceService.getClient(); - UpdateResponse updateResponse = mock(UpdateResponse.class); - when(updateResponse.status()).thenReturn(RestStatus.OK); - ActionListener listener = mock(ActionListener.class); - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(UpdateRequest.class); - doAnswer(invocation -> { - ActionListener callback = invocation.getArgument(1); - callback.onResponse(updateResponse); - return null; - }).when(client).update(requestCaptor.capture(), any()); - indexStoredRulePersistenceService.persistUpdatedRule(_ID_ONE, ruleTwo, listener); - verify(listener, times(1)).onResponse(any(UpdateRuleResponse.class)); - verify(listener, never()).onFailure(any()); - assertEquals(_ID_ONE, requestCaptor.getValue().id()); - } - - public void testPersistUpdatedRule_UpdateFailure() { - IndexStoredRulePersistenceService indexStoredRulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - Client client = indexStoredRulePersistenceService.getClient(); - ActionListener listener = mock(ActionListener.class); - doAnswer(invocation -> { - ActionListener callback = invocation.getArgument(1); - callback.onFailure(new Exception("Update failure")); - return null; - }).when(client).update(any(UpdateRequest.class), any()); - indexStoredRulePersistenceService.persistUpdatedRule(_ID_ONE, ruleTwo, listener); - - verify(listener, times(1)).onFailure(any(Exception.class)); - verify(listener, never()).onResponse(any()); - } + // public void testPersistUpdatedRule_Success() throws IOException { + // IndexStoredRulePersistenceService indexStoredRulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + // Client client = indexStoredRulePersistenceService.getClient(); + // UpdateResponse updateResponse = mock(UpdateResponse.class); + // when(updateResponse.status()).thenReturn(RestStatus.OK); + // ActionListener listener = mock(ActionListener.class); + // ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(UpdateRequest.class); + // doAnswer(invocation -> { + // ActionListener callback = invocation.getArgument(1); + // callback.onResponse(updateResponse); + // return null; + // }).when(client).update(requestCaptor.capture(), any()); + // indexStoredRulePersistenceService.persistUpdatedRule(_ID_ONE, ruleTwo, listener); + // verify(listener, times(1)).onResponse(any(UpdateRuleResponse.class)); + // verify(listener, never()).onFailure(any()); + // assertEquals(_ID_ONE, requestCaptor.getValue().id()); + // } + // + // public void testPersistUpdatedRule_UpdateFailure() { + // IndexStoredRulePersistenceService indexStoredRulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); + // Client client = indexStoredRulePersistenceService.getClient(); + // ActionListener listener = mock(ActionListener.class); + // doAnswer(invocation -> { + // ActionListener callback = invocation.getArgument(1); + // callback.onFailure(new Exception("Update failure")); + // return null; + // }).when(client).update(any(UpdateRequest.class), any()); + // indexStoredRulePersistenceService.persistUpdatedRule(_ID_ONE, ruleTwo, listener); + // + // verify(listener, times(1)).onFailure(any(Exception.class)); + // verify(listener, never()).onResponse(any()); + // } } diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java index 70474ed3e98b7..2009ef8f5ee1c 100644 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java +++ b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java @@ -54,19 +54,21 @@ public void testBuildGetRuleQuery_WithAttributes() { } public void testGetDuplicateRuleId_Found() { - Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(ATTRIBUTE_MAP, Map.of(_ID_ONE, ruleOne)); + Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(ruleOne, Map.of(_ID_ONE, ruleOne)); assertFalse(duplicateRuleId.isEmpty()); assertEquals(_ID_ONE, duplicateRuleId.get()); } public void testGetDuplicateRuleId_NotFound() { + Rule rule = mock(Rule.class); Map> map = Map.of( RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_ONE), RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, Set.of(ATTRIBUTE_VALUE_TWO) ); - Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(map, Map.of(_ID_ONE, ruleOne)); + when(rule.getAttributeMap()).thenReturn(map); + Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(rule, Map.of(_ID_ONE, ruleOne)); assertTrue(duplicateRuleId.isEmpty()); } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java index 33ea53419b3d9..f1472b78441cc 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java @@ -67,29 +67,25 @@ public void validate() { errorMessages.addAll(validateFeatureType()); errorMessages.addAll(validateUpdatedAtEpoch()); errorMessages.addAll(validateAttributeMap()); - handleErrorMessages(errorMessages); + if (!errorMessages.isEmpty()) { + ValidationException validationException = new ValidationException(); + validationException.addValidationErrors(errorMessages); + throw new IllegalArgumentException(validationException); + } } - public void validateUpdatingRuleParams() { + public List validateUpdatingRuleParams() { List errorMessages = new ArrayList<>(); - if (isEmpty(description)) { + if (isInvalidUpdatedValue(description)) { errorMessages.add("Rule description can't be empty"); } - if (isEmpty(featureValue)) { + if (isInvalidUpdatedValue(featureValue)) { errorMessages.add("Rule featureValue can't be empty"); } if (attributeMap != null && !attributeMap.isEmpty()) { validateAttributeMap(); } - handleErrorMessages(errorMessages); - } - - private void handleErrorMessages(List errorMessages) { - if (!errorMessages.isEmpty()) { - ValidationException validationException = new ValidationException(); - validationException.addValidationErrors(errorMessages); - throw new IllegalArgumentException(validationException); - } + return errorMessages; } private List validateStringFields() { @@ -112,12 +108,7 @@ private boolean isNullOrEmpty(String str) { return str == null || str.isEmpty(); } - /** - * Utility method which checks the empty string in context of Rule - * @param str - * @return - */ - public static boolean isEmpty(String str) { + private boolean isInvalidUpdatedValue(String str) { return str != null && str.isEmpty(); } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java index 84e068900568e..10df593f7bb81 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java @@ -11,11 +11,11 @@ import org.opensearch.ResourceNotFoundException; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.HandledTransportAction; +import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.rule.action.UpdateRuleRequest; import org.opensearch.rule.action.UpdateRuleResponse; -import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.rule.service.RulePersistenceService; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; @@ -26,30 +26,33 @@ */ public class TransportUpdateWlmRuleAction extends HandledTransportAction { - private final IndexStoredRulePersistenceService rulePersistenceService; + private final ClusterService clusterService; + private final RulePersistenceService rulePersistenceService; /** * Constructor for TransportUpdateWlmRuleAction * * @param transportService - a {@link TransportService} object * @param actionFilters - a {@link ActionFilters} object + * @param clusterService - a {@link ClusterService} object} * @param rulePersistenceService - a {@link RulePersistenceService} object */ @Inject public TransportUpdateWlmRuleAction( TransportService transportService, ActionFilters actionFilters, - IndexStoredRulePersistenceService rulePersistenceService + ClusterService clusterService, + RulePersistenceService rulePersistenceService ) { super(UpdateWlmRuleAction.NAME, transportService, actionFilters, UpdateRuleRequest::new); + this.clusterService = clusterService; this.rulePersistenceService = rulePersistenceService; } @Override protected void doExecute(Task task, UpdateRuleRequest request, ActionListener listener) { String queryGroupId = request.getFeatureValue(); - if (queryGroupId != null - && !rulePersistenceService.getClusterService().state().metadata().queryGroups().containsKey(queryGroupId)) { + if (queryGroupId != null && !clusterService.state().metadata().queryGroups().containsKey(queryGroupId)) { listener.onFailure(new ResourceNotFoundException("Couldn't find an existing query group with id: " + queryGroupId)); return; } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleAction.java deleted file mode 100644 index 88b1b1a9a3813..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleAction.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.rest; - -import org.opensearch.action.ActionType; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.plugin.wlm.rule.QueryGroupFeatureType; -import org.opensearch.plugin.wlm.rule.action.UpdateWlmRuleAction; -import org.opensearch.rule.action.UpdateRuleRequest; -import org.opensearch.rule.action.UpdateRuleResponse; -import org.opensearch.rule.rest.RestUpdateRuleAction; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.opensearch.rest.RestRequest.Method.POST; -import static org.opensearch.rest.RestRequest.Method.PUT; - -/** - * Rest action to update a workload management Rule - * @opensearch.experimental - */ -public class RestUpdateWlmRuleAction extends RestUpdateRuleAction { - - /** - * Constructor for RestUpdateWlmRuleAction - */ - public RestUpdateWlmRuleAction() { - super(); - } - - @Override - public String getName() { - return "update_rule"; - } - - @Override - public List routes() { - return List.of(new Route(POST, "_wlm/rule/{_id}"), new Route(PUT, "_wlm/rule/{_id}")); - } - - @Override - @SuppressWarnings("unchecked") - protected > T retrieveUpdateRuleActionInstance() { - return (T) UpdateWlmRuleAction.INSTANCE; - } - - @Override - protected FeatureType retrieveFeatureTypeInstance() { - return QueryGroupFeatureType.INSTANCE; - } - - @Override - protected UpdateRuleRequest buildUpdateRuleRequest( - String id, - String description, - Map> attributeMap, - String featureValue - ) { - return new UpdateRuleRequest(id, description, attributeMap, featureValue, QueryGroupFeatureType.INSTANCE); - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java deleted file mode 100644 index 1d82e4fea71e5..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/rest/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/** - * Package for the rest classes related to rules in WorkloadManagementPlugin - */ -package org.opensearch.plugin.wlm.rule.rest; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleActionTests.java deleted file mode 100644 index b14ebc47c5a0a..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/rest/RestUpdateWlmRuleActionTests.java +++ /dev/null @@ -1,37 +0,0 @@ - -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.rest; - -import org.opensearch.rest.RestHandler; -import org.opensearch.test.OpenSearchTestCase; - -import java.util.List; - -import static org.opensearch.rest.RestRequest.Method.POST; -import static org.opensearch.rest.RestRequest.Method.PUT; - -public class RestUpdateWlmRuleActionTests extends OpenSearchTestCase { - /** - * Test case to validate the construction for RestGetRuleAction - */ - public void testConstruction() { - RestUpdateWlmRuleAction action = new RestUpdateWlmRuleAction(); - assertNotNull(action); - assertEquals("update_rule", action.getName()); - List routes = action.routes(); - assertEquals(2, routes.size()); - RestHandler.Route route = routes.get(0); - assertEquals(POST, route.getMethod()); - assertEquals("_wlm/rule/{_id}", route.getPath()); - route = routes.get(1); - assertEquals(PUT, route.getMethod()); - assertEquals("_wlm/rule/{_id}", route.getPath()); - } -} From 5b4dfc53c963d82abb4ed5bce6d643f8d8c537c0 Mon Sep 17 00:00:00 2001 From: Lingxi Chen Date: Tue, 15 Apr 2025 11:14:25 -0700 Subject: [PATCH 03/11] rebase refactoring Signed-off-by: Lingxi Chen --- .../secure_sm/policy/package-info.java | 12 - .../wlm/action/CreateQueryGroupAction.java | 36 -- .../wlm/action/CreateQueryGroupRequest.java | 82 --- .../wlm/action/CreateQueryGroupResponse.java | 74 --- .../wlm/action/DeleteQueryGroupAction.java | 38 -- .../wlm/action/DeleteQueryGroupRequest.java | 65 --- .../wlm/action/GetQueryGroupAction.java | 36 -- .../wlm/action/GetQueryGroupRequest.java | 64 --- .../wlm/action/GetQueryGroupResponse.java | 82 --- .../TransportCreateQueryGroupAction.java | 95 ---- .../TransportDeleteQueryGroupAction.java | 97 ---- .../action/TransportGetQueryGroupAction.java | 107 ---- .../TransportUpdateQueryGroupAction.java | 96 ---- .../TransportUpdateWorkloadGroupAction.java | 4 + .../wlm/action/UpdateQueryGroupAction.java | 36 -- .../wlm/action/UpdateQueryGroupRequest.java | 83 --- .../wlm/action/UpdateQueryGroupResponse.java | 74 --- .../wlm/rest/RestCreateQueryGroupAction.java | 82 --- .../wlm/rest/RestDeleteQueryGroupAction.java | 66 --- .../wlm/rest/RestGetQueryGroupAction.java | 74 --- .../wlm/rest/RestUpdateQueryGroupAction.java | 81 --- .../service/QueryGroupPersistenceService.java | 372 ------------- .../plugin/wlm/QueryGroupTestUtils.java | 172 ------ .../plugin/wlm/WorkloadGroupTestUtils.java | 6 +- .../action/CreateQueryGroupRequestTests.java | 46 -- .../action/CreateQueryGroupResponseTests.java | 71 --- .../action/DeleteQueryGroupRequestTests.java | 47 -- .../wlm/action/GetQueryGroupRequestTests.java | 58 -- .../action/GetQueryGroupResponseTests.java | 156 ------ .../wlm/action/QueryGroupActionTestUtils.java | 18 - .../TransportDeleteQueryGroupActionTests.java | 69 --- .../TransportGetQueryGroupActionTests.java | 59 -- .../action/UpdateQueryGroupRequestTests.java | 105 ---- .../action/UpdateQueryGroupResponseTests.java | 76 --- .../rest/RestDeleteQueryGroupActionTests.java | 95 ---- .../QueryGroupPersistenceServiceTests.java | 515 ------------------ 36 files changed, 5 insertions(+), 3244 deletions(-) delete mode 100644 libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequest.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponse.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequest.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequest.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponse.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequest.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponse.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceService.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequestTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponseTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequestTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequestTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponseTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/QueryGroupActionTestUtils.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupActionTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupActionTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequestTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponseTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupActionTests.java delete mode 100644 plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceServiceTests.java diff --git a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java deleted file mode 100644 index d182490b8d173..0000000000000 --- a/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/** - * Java Agent Policy - */ -package org.opensearch.secure_sm.policy; 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/action/CreateQueryGroupAction.java deleted file mode 100644 index ee1b40a2f9bbc..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupAction.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionType; - -/** - * Transport action to get WorkloadGroup - * - * @opensearch.experimental - */ -public class GetWorkloadGroupAction extends ActionType { - - /** - * An instance of GetWorkloadGroupAction - */ - public static final GetWorkloadGroupAction INSTANCE = new GetWorkloadGroupAction(); - - /** - * Name for GetWorkloadGroupAction - */ - public static final String NAME = "cluster:admin/opensearch/wlm/workload_group/_get"; - - /** - * Default constructor - */ - private GetWorkloadGroupAction() { - super(NAME, GetWorkloadGroupResponse::new); - } -} 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/action/CreateQueryGroupRequest.java deleted file mode 100644 index ad932667b25e8..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; -import org.opensearch.cluster.metadata.WorkloadGroup; -import org.opensearch.common.UUIDs; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.xcontent.XContentParser; -import org.joda.time.Instant; - -import java.io.IOException; - -/** - * A request for create WorkloadGroup - * User input schema: - * { - * "name": "analytics", - * "resiliency_mode": "enforced", - * "resource_limits": { - * "cpu" : 0.4, - * "memory" : 0.2 - * } - * } - * - * @opensearch.experimental - */ -public class CreateWorkloadGroupRequest extends ClusterManagerNodeRequest { - private final WorkloadGroup workloadGroup; - - /** - * Constructor for CreateWorkloadGroupRequest - * @param workloadGroup - A {@link WorkloadGroup} object - */ - CreateWorkloadGroupRequest(WorkloadGroup workloadGroup) { - this.workloadGroup = workloadGroup; - } - - /** - * Constructor for CreateWorkloadGroupRequest - * @param in - A {@link StreamInput} object - */ - CreateWorkloadGroupRequest(StreamInput in) throws IOException { - super(in); - workloadGroup = new WorkloadGroup(in); - } - - /** - * Generate a CreateWorkloadGroupRequest from XContent - * @param parser - A {@link XContentParser} object - */ - public static CreateWorkloadGroupRequest fromXContent(XContentParser parser) throws IOException { - WorkloadGroup.Builder builder = WorkloadGroup.Builder.fromXContent(parser); - return new CreateWorkloadGroupRequest(builder._id(UUIDs.randomBase64UUID()).updatedAt(Instant.now().getMillis()).build()); - } - - @Override - public ActionRequestValidationException validate() { - return null; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - super.writeTo(out); - workloadGroup.writeTo(out); - } - - /** - * WorkloadGroup getter - */ - public WorkloadGroup getWorkloadGroup() { - return workloadGroup; - } -} 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/action/CreateQueryGroupResponse.java deleted file mode 100644 index b33214e042398..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponse.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.cluster.metadata.WorkloadGroup; -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 java.io.IOException; - -/** - * Response for the create API for WorkloadGroup - * - * @opensearch.experimental - */ -public class CreateWorkloadGroupResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final WorkloadGroup workloadGroup; - private final RestStatus restStatus; - - /** - * Constructor for CreateWorkloadGroupResponse - * @param workloadGroup - The WorkloadGroup to be included in the response - * @param restStatus - The restStatus for the response - */ - public CreateWorkloadGroupResponse(final WorkloadGroup workloadGroup, RestStatus restStatus) { - this.workloadGroup = workloadGroup; - this.restStatus = restStatus; - } - - /** - * Constructor for CreateWorkloadGroupResponse - * @param in - A {@link StreamInput} object - */ - public CreateWorkloadGroupResponse(StreamInput in) throws IOException { - workloadGroup = new WorkloadGroup(in); - restStatus = RestStatus.readFrom(in); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - workloadGroup.writeTo(out); - RestStatus.writeTo(out, restStatus); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return workloadGroup.toXContent(builder, params); - } - - /** - * workloadGroup getter - */ - public WorkloadGroup getWorkloadGroup() { - return workloadGroup; - } - - /** - * restStatus getter - */ - public RestStatus getRestStatus() { - return restStatus; - } -} 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/action/DeleteQueryGroupAction.java deleted file mode 100644 index 39b47d69776f4..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupAction.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionType; -import org.opensearch.action.support.clustermanager.AcknowledgedResponse; - -/** - * Transport action for delete WorkloadGroup - * - * @opensearch.experimental - */ -public class DeleteWorkloadGroupAction extends ActionType { - - /** - /** - * An instance of DeleteWorkloadGroupAction - */ - public static final DeleteWorkloadGroupAction INSTANCE = new DeleteWorkloadGroupAction(); - - /** - * Name for DeleteWorkloadGroupAction - */ - public static final String NAME = "cluster:admin/opensearch/wlm/workload_group/_delete"; - - /** - * Default constructor - */ - private DeleteWorkloadGroupAction() { - super(NAME, AcknowledgedResponse::new); - } -} 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/action/DeleteQueryGroupRequest.java deleted file mode 100644 index 940a3815b1662..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.action.support.clustermanager.AcknowledgedRequest; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; - -import java.io.IOException; - -/** - * Request for delete WorkloadGroup - * - * @opensearch.experimental - */ -public class DeleteWorkloadGroupRequest extends AcknowledgedRequest { - private final String name; - - /** - * Default constructor for DeleteWorkloadGroupRequest - * @param name - name for the WorkloadGroup to get - */ - public DeleteWorkloadGroupRequest(String name) { - this.name = name; - } - - /** - * Constructor for DeleteWorkloadGroupRequest - * @param in - A {@link StreamInput} object - */ - public DeleteWorkloadGroupRequest(StreamInput in) throws IOException { - super(in); - name = in.readOptionalString(); - } - - @Override - public ActionRequestValidationException validate() { - if (name == null) { - ActionRequestValidationException actionRequestValidationException = new ActionRequestValidationException(); - actionRequestValidationException.addValidationError("WorkloadGroup name is missing"); - return actionRequestValidationException; - } - return null; - } - - /** - * Name getter - */ - public String getName() { - return name; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - super.writeTo(out); - out.writeOptionalString(name); - } -} 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/action/GetQueryGroupAction.java deleted file mode 100644 index b4f8e1ce90126..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupAction.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionType; - -/** - * Transport action to update WorkloadGroup - * - * @opensearch.experimental - */ -public class UpdateWorkloadGroupAction extends ActionType { - - /** - * An instance of UpdateWorkloadGroupAction - */ - public static final UpdateWorkloadGroupAction INSTANCE = new UpdateWorkloadGroupAction(); - - /** - * Name for UpdateWorkloadGroupAction - */ - public static final String NAME = "cluster:admin/opensearch/wlm/workload_group/_update"; - - /** - * Default constructor - */ - private UpdateWorkloadGroupAction() { - super(NAME, UpdateWorkloadGroupResponse::new); - } -} 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/action/GetQueryGroupRequest.java deleted file mode 100644 index 4b8a5f85fd236..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.action.support.clustermanager.ClusterManagerNodeReadRequest; -import org.opensearch.cluster.metadata.WorkloadGroup; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; - -import java.io.IOException; - -/** - * Request for get WorkloadGroup - * - * @opensearch.experimental - */ -public class GetWorkloadGroupRequest extends ClusterManagerNodeReadRequest { - final String name; - - /** - * Default constructor for GetWorkloadGroupRequest - * @param name - name for the WorkloadGroup to get - */ - public GetWorkloadGroupRequest(String name) { - this.name = name; - } - - /** - * Constructor for GetWorkloadGroupRequest - * @param in - A {@link StreamInput} object - */ - public GetWorkloadGroupRequest(StreamInput in) throws IOException { - super(in); - name = in.readOptionalString(); - } - - @Override - public ActionRequestValidationException validate() { - if (name != null) { - WorkloadGroup.validateName(name); - } - return null; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - super.writeTo(out); - out.writeOptionalString(name); - } - - /** - * Name getter - */ - public String getName() { - return name; - } -} 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/action/GetQueryGroupResponse.java deleted file mode 100644 index ab8f773088a37..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponse.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.cluster.metadata.WorkloadGroup; -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 java.io.IOException; -import java.util.Collection; - -/** - * Response for the get API for WorkloadGroup - * - * @opensearch.experimental - */ -public class GetWorkloadGroupResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final Collection workloadGroups; - private final RestStatus restStatus; - - /** - * Constructor for GetWorkloadGroupResponse - * @param workloadGroups - The WorkloadGroup list to be fetched - * @param restStatus - The rest status of the request - */ - public GetWorkloadGroupResponse(final Collection workloadGroups, RestStatus restStatus) { - this.workloadGroups = workloadGroups; - this.restStatus = restStatus; - } - - /** - * Constructor for GetWorkloadGroupResponse - * @param in - A {@link StreamInput} object - */ - public GetWorkloadGroupResponse(StreamInput in) throws IOException { - this.workloadGroups = in.readList(WorkloadGroup::new); - restStatus = RestStatus.readFrom(in); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeCollection(workloadGroups); - RestStatus.writeTo(out, restStatus); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.startArray("workload_groups"); - for (WorkloadGroup group : workloadGroups) { - group.toXContent(builder, params); - } - builder.endArray(); - builder.endObject(); - return builder; - } - - /** - * workloadGroups getter - */ - public Collection getWorkloadGroups() { - return workloadGroups; - } - - /** - * restStatus getter - */ - public RestStatus getRestStatus() { - return restStatus; - } -} 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/action/TransportCreateQueryGroupAction.java deleted file mode 100644 index 03dd2ac1f9952..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateQueryGroupAction.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.support.ActionFilters; -import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.block.ClusterBlockException; -import org.opensearch.cluster.block.ClusterBlockLevel; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.common.inject.Inject; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java -import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.TransportService; - -import java.io.IOException; - -import static org.opensearch.threadpool.ThreadPool.Names.SAME; - -/** - * Transport action to update WorkloadGroup - * - * @opensearch.experimental - */ -public class TransportUpdateWorkloadGroupAction extends TransportClusterManagerNodeAction< - UpdateWorkloadGroupRequest, - UpdateWorkloadGroupResponse> { - - private final WorkloadGroupPersistenceService workloadGroupPersistenceService; - - /** - * Constructor for TransportUpdateWorkloadGroupAction - * - * @param threadPool - {@link ThreadPool} object - * @param transportService - a {@link TransportService} object - * @param actionFilters - a {@link ActionFilters} object - * @param indexNameExpressionResolver - {@link IndexNameExpressionResolver} object - * @param workloadGroupPersistenceService - a {@link WorkloadGroupPersistenceService} object - */ - @Inject - public TransportUpdateWorkloadGroupAction( - ThreadPool threadPool, - TransportService transportService, - ActionFilters actionFilters, - IndexNameExpressionResolver indexNameExpressionResolver, - WorkloadGroupPersistenceService workloadGroupPersistenceService - ) { - super( - UpdateWorkloadGroupAction.NAME, - transportService, - workloadGroupPersistenceService.getClusterService(), - threadPool, - actionFilters, - UpdateWorkloadGroupRequest::new, - indexNameExpressionResolver - ); - this.workloadGroupPersistenceService = workloadGroupPersistenceService; - } - - @Override - protected void clusterManagerOperation( - UpdateWorkloadGroupRequest request, - ClusterState clusterState, - ActionListener listener - ) { - workloadGroupPersistenceService.updateInClusterStateMetadata(request, listener); - } - - @Override - protected String executor() { - return SAME; - } - - @Override - protected UpdateWorkloadGroupResponse read(StreamInput in) throws IOException { - return new UpdateWorkloadGroupResponse(in); - } - - @Override - protected ClusterBlockException checkBlock(UpdateWorkloadGroupRequest request, ClusterState state) { - return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); - } -} 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/action/TransportDeleteQueryGroupAction.java deleted file mode 100644 index 5fc8b30bf419c..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupAction.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.support.ActionFilters; -import org.opensearch.action.support.clustermanager.AcknowledgedResponse; -import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.block.ClusterBlockException; -import org.opensearch.cluster.block.ClusterBlockLevel; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.inject.Inject; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java -import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.java -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.TransportService; - -import java.io.IOException; - -/** - * Transport action for delete WorkloadGroup - * - * @opensearch.experimental - */ -public class TransportDeleteWorkloadGroupAction extends TransportClusterManagerNodeAction< - DeleteWorkloadGroupRequest, - AcknowledgedResponse> { - - private final WorkloadGroupPersistenceService workloadGroupPersistenceService; - - /** - * Constructor for TransportDeleteWorkloadGroupAction - * - * @param clusterService - a {@link ClusterService} object - * @param transportService - a {@link TransportService} object - * @param actionFilters - a {@link ActionFilters} object - * @param threadPool - a {@link ThreadPool} object - * @param indexNameExpressionResolver - a {@link IndexNameExpressionResolver} object - * @param workloadGroupPersistenceService - a {@link WorkloadGroupPersistenceService} object - */ - @Inject - public TransportDeleteWorkloadGroupAction( - ClusterService clusterService, - TransportService transportService, - ActionFilters actionFilters, - ThreadPool threadPool, - IndexNameExpressionResolver indexNameExpressionResolver, - WorkloadGroupPersistenceService workloadGroupPersistenceService - ) { - super( - DeleteWorkloadGroupAction.NAME, - transportService, - clusterService, - threadPool, - actionFilters, - DeleteWorkloadGroupRequest::new, - indexNameExpressionResolver - ); - this.workloadGroupPersistenceService = workloadGroupPersistenceService; - } - - @Override - protected void clusterManagerOperation( - DeleteWorkloadGroupRequest request, - ClusterState state, - ActionListener listener - ) throws Exception { - workloadGroupPersistenceService.deleteInClusterStateMetadata(request, listener); - } - - @Override - protected String executor() { - return ThreadPool.Names.SAME; - } - - @Override - protected AcknowledgedResponse read(StreamInput in) throws IOException { - return new AcknowledgedResponse(in); - } - - @Override - protected ClusterBlockException checkBlock(DeleteWorkloadGroupRequest request, ClusterState state) { - return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); - } -} 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/action/TransportGetQueryGroupAction.java deleted file mode 100644 index ab1ff9f247c56..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupAction.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.support.ActionFilters; -import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeReadAction; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.block.ClusterBlockException; -import org.opensearch.cluster.block.ClusterBlockLevel; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.cluster.metadata.WorkloadGroup; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.inject.Inject; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.rest.RestStatus; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java -import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.java -import org.opensearch.search.pipeline.SearchPipelineService; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.TransportService; - -import java.io.IOException; -import java.util.Collection; - -/** - * Transport action to get WorkloadGroup - * - * @opensearch.experimental - */ -public class TransportGetWorkloadGroupAction extends TransportClusterManagerNodeReadAction< - GetWorkloadGroupRequest, - GetWorkloadGroupResponse> { - private static final Logger logger = LogManager.getLogger(SearchPipelineService.class); - - /** - * Constructor for TransportGetWorkloadGroupAction - * - * @param clusterService - a {@link ClusterService} object - * @param transportService - a {@link TransportService} object - * @param actionFilters - a {@link ActionFilters} object - * @param threadPool - a {@link ThreadPool} object - * @param indexNameExpressionResolver - a {@link IndexNameExpressionResolver} object - */ - @Inject - public TransportGetWorkloadGroupAction( - ClusterService clusterService, - TransportService transportService, - ActionFilters actionFilters, - ThreadPool threadPool, - IndexNameExpressionResolver indexNameExpressionResolver - ) { - super( - GetWorkloadGroupAction.NAME, - transportService, - clusterService, - threadPool, - actionFilters, - GetWorkloadGroupRequest::new, - indexNameExpressionResolver, - true - ); - } - - @Override - protected String executor() { - return ThreadPool.Names.SAME; - } - - @Override - protected GetWorkloadGroupResponse read(StreamInput in) throws IOException { - return new GetWorkloadGroupResponse(in); - } - - @Override - protected ClusterBlockException checkBlock(GetWorkloadGroupRequest request, ClusterState state) { - return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ); - } - - @Override - protected void clusterManagerOperation( - GetWorkloadGroupRequest request, - ClusterState state, - ActionListener listener - ) throws Exception { - final String name = request.getName(); - final Collection resultGroups = WorkloadGroupPersistenceService.getFromClusterStateMetadata(name, state); - - if (resultGroups.isEmpty() && name != null && !name.isEmpty()) { - logger.warn("No WorkloadGroup exists with the provided name: {}", name); - throw new ResourceNotFoundException("No WorkloadGroup exists with the provided name: " + name); - } - listener.onResponse(new GetWorkloadGroupResponse(resultGroups, RestStatus.OK)); - } -} 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/action/TransportUpdateQueryGroupAction.java deleted file mode 100644 index e13b682914dd3..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.support.ActionFilters; -import org.opensearch.action.support.clustermanager.TransportClusterManagerNodeAction; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.block.ClusterBlockException; -import org.opensearch.cluster.block.ClusterBlockLevel; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.common.inject.Inject; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java -import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.java -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.TransportService; - -import java.io.IOException; - -import static org.opensearch.threadpool.ThreadPool.Names.SAME; - -/** - * Transport action to create WorkloadGroup - * - * @opensearch.experimental - */ -public class TransportCreateWorkloadGroupAction extends TransportClusterManagerNodeAction< - CreateWorkloadGroupRequest, - CreateWorkloadGroupResponse> { - - private final WorkloadGroupPersistenceService workloadGroupPersistenceService; - - /** - * Constructor for TransportCreateWorkloadGroupAction - * - * @param threadPool - {@link ThreadPool} object - * @param transportService - a {@link TransportService} object - * @param actionFilters - a {@link ActionFilters} object - * @param indexNameExpressionResolver - {@link IndexNameExpressionResolver} object - * @param workloadGroupPersistenceService - a {@link WorkloadGroupPersistenceService} object - */ - @Inject - public TransportCreateWorkloadGroupAction( - ThreadPool threadPool, - TransportService transportService, - ActionFilters actionFilters, - IndexNameExpressionResolver indexNameExpressionResolver, - WorkloadGroupPersistenceService workloadGroupPersistenceService - ) { - super( - CreateWorkloadGroupAction.NAME, - transportService, - workloadGroupPersistenceService.getClusterService(), - threadPool, - actionFilters, - CreateWorkloadGroupRequest::new, - indexNameExpressionResolver - ); - this.workloadGroupPersistenceService = workloadGroupPersistenceService; - } - - @Override - protected void clusterManagerOperation( - CreateWorkloadGroupRequest request, - ClusterState clusterState, - ActionListener listener - ) { - workloadGroupPersistenceService.persistInClusterStateMetadata(request.getWorkloadGroup(), listener); - } - - @Override - protected String executor() { - return SAME; - } - - @Override - protected CreateWorkloadGroupResponse read(StreamInput in) throws IOException { - return new CreateWorkloadGroupResponse(in); - } - - @Override - protected ClusterBlockException checkBlock(CreateWorkloadGroupRequest request, ClusterState state) { - return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); - } - -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java index 03dd2ac1f9952..58e094514f57e 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java @@ -17,11 +17,15 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; +<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java <<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; ======== import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; >>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java +======== +import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; +>>>>>>>> ccb9c34c0d8 (refactoring):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java deleted file mode 100644 index ca9784ebc7e4b..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupAction.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionType; - -/** - * Transport action to create WorkloadGroup - * - * @opensearch.experimental - */ -public class CreateWorkloadGroupAction extends ActionType { - - /** - * An instance of CreateWorkloadGroupAction - */ - public static final CreateWorkloadGroupAction INSTANCE = new CreateWorkloadGroupAction(); - - /** - * Name for CreateWorkloadGroupAction - */ - public static final String NAME = "cluster:admin/opensearch/wlm/workload_group/_create"; - - /** - * Default constructor - */ - private CreateWorkloadGroupAction() { - super(NAME, CreateWorkloadGroupResponse::new); - } -} 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/action/UpdateQueryGroupRequest.java deleted file mode 100644 index 18af58289be13..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; -import org.opensearch.cluster.metadata.QueryGroup; -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.MutableQueryGroupFragment; - -import java.io.IOException; - -/** - * A request for update QueryGroup - * - * @opensearch.experimental - */ -public class UpdateQueryGroupRequest extends ClusterManagerNodeRequest { - private final String name; - private final MutableQueryGroupFragment mutableQueryGroupFragment; - - /** - * Constructor for UpdateQueryGroupRequest - * @param name - QueryGroup name for UpdateQueryGroupRequest - * @param mutableQueryGroupFragment - MutableQueryGroupFragment for UpdateQueryGroupRequest - */ - UpdateQueryGroupRequest(String name, MutableQueryGroupFragment mutableQueryGroupFragment) { - this.name = name; - this.mutableQueryGroupFragment = mutableQueryGroupFragment; - } - - /** - * Constructor for UpdateQueryGroupRequest - * @param in - A {@link StreamInput} object - */ - UpdateQueryGroupRequest(StreamInput in) throws IOException { - this(in.readString(), new MutableQueryGroupFragment(in)); - } - - /** - * Generate a UpdateQueryGroupRequest from XContent - * @param parser - A {@link XContentParser} object - * @param name - name of the QueryGroup to be updated - */ - public static UpdateQueryGroupRequest fromXContent(XContentParser parser, String name) throws IOException { - QueryGroup.Builder builder = QueryGroup.Builder.fromXContent(parser); - return new UpdateQueryGroupRequest(name, builder.getMutableQueryGroupFragment()); - } - - @Override - public ActionRequestValidationException validate() { - QueryGroup.validateName(name); - return null; - } - - /** - * name getter - */ - public String getName() { - return name; - } - - /** - * mutableQueryGroupFragment getter - */ - public MutableQueryGroupFragment getmMutableQueryGroupFragment() { - return mutableQueryGroupFragment; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeString(name); - mutableQueryGroupFragment.writeTo(out); - } -} 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/action/UpdateQueryGroupResponse.java deleted file mode 100644 index 9b8fccbdb5346..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponse.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.cluster.metadata.WorkloadGroup; -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 java.io.IOException; - -/** - * Response for the update API for WorkloadGroup - * - * @opensearch.experimental - */ -public class UpdateWorkloadGroupResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final WorkloadGroup workloadGroup; - private final RestStatus restStatus; - - /** - * Constructor for UpdateWorkloadGroupResponse - * @param workloadGroup - the WorkloadGroup to be updated - * @param restStatus - the rest status for the response - */ - public UpdateWorkloadGroupResponse(final WorkloadGroup workloadGroup, RestStatus restStatus) { - this.workloadGroup = workloadGroup; - this.restStatus = restStatus; - } - - /** - * Constructor for UpdateWorkloadGroupResponse - * @param in - a {@link StreamInput} object - */ - public UpdateWorkloadGroupResponse(StreamInput in) throws IOException { - workloadGroup = new WorkloadGroup(in); - restStatus = RestStatus.readFrom(in); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - workloadGroup.writeTo(out); - RestStatus.writeTo(out, restStatus); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return workloadGroup.toXContent(builder, params); - } - - /** - * workloadGroup getter - */ - public WorkloadGroup getWorkloadGroup() { - return workloadGroup; - } - - /** - * restStatus getter - */ - public RestStatus getRestStatus() { - return restStatus; - } -} 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/rest/RestCreateQueryGroupAction.java deleted file mode 100644 index ee3564dc5c7f6..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateQueryGroupAction.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rest; - -import org.opensearch.core.rest.RestStatus; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.XContentParser; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java -import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupAction; -import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java -import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; -import org.opensearch.rest.RestResponse; -import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.transport.client.node.NodeClient; - -import java.io.IOException; -import java.util.List; - -import static org.opensearch.rest.RestRequest.Method.POST; -import static org.opensearch.rest.RestRequest.Method.PUT; - -/** - * Rest action to update a WorkloadGroup - * - * @opensearch.experimental - */ -public class RestUpdateWorkloadGroupAction extends BaseRestHandler { - - /** - * Constructor for RestUpdateWorkloadGroupAction - */ - public RestUpdateWorkloadGroupAction() {} - - @Override - public String getName() { - return "update_workload_group"; - } - - /** - * The list of {@link Route}s that this RestHandler is responsible for handling. - */ - @Override - public List routes() { - return List.of(new Route(POST, "_wlm/workload_group/{name}"), new Route(PUT, "_wlm/workload_group/{name}")); - } - - @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - try (XContentParser parser = request.contentParser()) { - UpdateWorkloadGroupRequest updateWorkloadGroupRequest = UpdateWorkloadGroupRequest.fromXContent(parser, request.param("name")); - return channel -> client.execute( - UpdateWorkloadGroupAction.INSTANCE, - updateWorkloadGroupRequest, - updateWorkloadGroupResponse(channel) - ); - } - } - - private RestResponseListener updateWorkloadGroupResponse(final RestChannel channel) { - return new RestResponseListener<>(channel) { - @Override - public RestResponse buildResponse(final UpdateWorkloadGroupResponse 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/rest/RestDeleteQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java deleted file mode 100644 index 8a1591b015372..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupAction.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rest; - -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -======== -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupAction.java -import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.RestRequest; -import org.opensearch.rest.action.RestToXContentListener; -import org.opensearch.transport.client.node.NodeClient; - -import java.io.IOException; -import java.util.List; - -import static org.opensearch.rest.RestRequest.Method.DELETE; - -/** - * Rest action to delete a WorkloadGroup - * - * @opensearch.experimental - */ -public class RestDeleteWorkloadGroupAction extends BaseRestHandler { - - /** - * Constructor for RestDeleteWorkloadGroupAction - */ - public RestDeleteWorkloadGroupAction() {} - - @Override - public String getName() { - return "delete_workload_group"; - } - - /** - * The list of {@link Route}s that this RestHandler is responsible for handling. - */ - @Override - public List routes() { - return List.of(new Route(DELETE, "_wlm/workload_group/{name}")); - } - - @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - DeleteWorkloadGroupRequest deleteWorkloadGroupRequest = new DeleteWorkloadGroupRequest(request.param("name")); - deleteWorkloadGroupRequest.clusterManagerNodeTimeout( - request.paramAsTime("cluster_manager_timeout", deleteWorkloadGroupRequest.clusterManagerNodeTimeout()) - ); - deleteWorkloadGroupRequest.timeout(request.paramAsTime("timeout", deleteWorkloadGroupRequest.timeout())); - return channel -> client.execute( - DeleteWorkloadGroupAction.INSTANCE, - deleteWorkloadGroupRequest, - new RestToXContentListener<>(channel) - ); - } -} 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/rest/RestGetQueryGroupAction.java deleted file mode 100644 index 4879adc6898c2..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetQueryGroupAction.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rest; - -import org.opensearch.core.rest.RestStatus; -import org.opensearch.core.xcontent.ToXContent; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java -import org.opensearch.plugin.wlm.action.GetWorkloadGroupAction; -import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupResponse; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java -import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; -import org.opensearch.rest.RestResponse; -import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.transport.client.node.NodeClient; - -import java.io.IOException; -import java.util.List; - -import static org.opensearch.rest.RestRequest.Method.GET; - -/** - * Rest action to get a WorkloadGroup - * - * @opensearch.experimental - */ -public class RestGetWorkloadGroupAction extends BaseRestHandler { - - /** - * Constructor for RestGetWorkloadGroupAction - */ - public RestGetWorkloadGroupAction() {} - - @Override - public String getName() { - return "get_workload_group"; - } - - /** - * The list of {@link Route}s that this RestHandler is responsible for handling. - */ - @Override - public List routes() { - return List.of(new Route(GET, "_wlm/workload_group/{name}"), new Route(GET, "_wlm/workload_group/")); - } - - @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - final GetWorkloadGroupRequest getWorkloadGroupRequest = new GetWorkloadGroupRequest(request.param("name")); - return channel -> client.execute(GetWorkloadGroupAction.INSTANCE, getWorkloadGroupRequest, getWorkloadGroupResponse(channel)); - } - - private RestResponseListener getWorkloadGroupResponse(final RestChannel channel) { - return new RestResponseListener<>(channel) { - @Override - public RestResponse buildResponse(final GetWorkloadGroupResponse 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/rest/RestUpdateQueryGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java deleted file mode 100644 index 06624664d46eb..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateQueryGroupAction.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rest; - -import org.opensearch.core.rest.RestStatus; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.XContentParser; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java -import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; -import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java -import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; -import org.opensearch.rest.RestResponse; -import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.transport.client.node.NodeClient; - -import java.io.IOException; -import java.util.List; - -import static org.opensearch.rest.RestRequest.Method.POST; -import static org.opensearch.rest.RestRequest.Method.PUT; - -/** - * Rest action to create a WorkloadGroup - * - * @opensearch.experimental - */ -public class RestCreateWorkloadGroupAction extends BaseRestHandler { - - /** - * Constructor for RestCreateWorkloadGroupAction - */ - public RestCreateWorkloadGroupAction() {} - - @Override - public String getName() { - return "create_workload_group"; - } - - /** - * The list of {@link Route}s that this RestHandler is responsible for handling. - */ - @Override - public List routes() { - return List.of(new Route(POST, "_wlm/workload_group/"), new Route(PUT, "_wlm/workload_group/")); - } - - @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - try (XContentParser parser = request.contentParser()) { - CreateWorkloadGroupRequest createWorkloadGroupRequest = CreateWorkloadGroupRequest.fromXContent(parser); - return channel -> client.execute( - CreateWorkloadGroupAction.INSTANCE, - createWorkloadGroupRequest, - createWorkloadGroupResponse(channel) - ); - } - } - - private RestResponseListener createWorkloadGroupResponse(final RestChannel channel) { - return new RestResponseListener<>(channel) { - @Override - public RestResponse buildResponse(final CreateWorkloadGroupResponse 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/service/QueryGroupPersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceService.java deleted file mode 100644 index 39b259410dfd5..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceService.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.service; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.support.clustermanager.AcknowledgedResponse; -import org.opensearch.cluster.AckedClusterStateUpdateTask; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.ClusterStateUpdateTask; -import org.opensearch.cluster.metadata.Metadata; -import org.opensearch.cluster.metadata.WorkloadGroup; -import org.opensearch.cluster.service.ClusterManagerTaskThrottler; -import org.opensearch.cluster.service.ClusterManagerTaskThrottler.ThrottlingKey; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.Priority; -import org.opensearch.common.inject.Inject; -import org.opensearch.common.settings.ClusterSettings; -import org.opensearch.common.settings.Setting; -import org.opensearch.common.settings.Settings; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.rest.RestStatus; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/WorkloadGroupPersistenceService.java -import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; -import org.opensearch.wlm.MutableWorkloadGroupFragment; -======== -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; -import org.opensearch.wlm.MutableQueryGroupFragment; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.java -import org.opensearch.wlm.ResourceType; - -import java.util.Collection; -import java.util.EnumMap; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.opensearch.cluster.metadata.WorkloadGroup.updateExistingWorkloadGroup; - -/** - * This class defines the functions for WorkloadGroup persistence - */ -public class WorkloadGroupPersistenceService { - static final String SOURCE = "query-group-persistence-service"; - private static final String CREATE_QUERY_GROUP_THROTTLING_KEY = "create-query-group"; - private static final String DELETE_QUERY_GROUP_THROTTLING_KEY = "delete-query-group"; - private static final String UPDATE_QUERY_GROUP_THROTTLING_KEY = "update-query-group"; - private static final Logger logger = LogManager.getLogger(WorkloadGroupPersistenceService.class); - /** - * max WorkloadGroup count setting name - */ - public static final String QUERY_GROUP_COUNT_SETTING_NAME = "node.workload_group.max_count"; - /** - * default max workloadGroup count on any node at any given point in time - */ - private static final int DEFAULT_MAX_QUERY_GROUP_COUNT_VALUE = 100; - /** - * min workloadGroup count on any node at any given point in time - */ - private static final int MIN_QUERY_GROUP_COUNT_VALUE = 1; - /** - * max WorkloadGroup count setting - */ - public static final Setting MAX_QUERY_GROUP_COUNT = Setting.intSetting( - QUERY_GROUP_COUNT_SETTING_NAME, - DEFAULT_MAX_QUERY_GROUP_COUNT_VALUE, - 0, - WorkloadGroupPersistenceService::validateMaxWorkloadGroupCount, - Setting.Property.Dynamic, - Setting.Property.NodeScope - ); - private final ClusterService clusterService; - private volatile int maxWorkloadGroupCount; - final ThrottlingKey createWorkloadGroupThrottlingKey; - final ThrottlingKey deleteWorkloadGroupThrottlingKey; - final ThrottlingKey updateWorkloadGroupThrottlingKey; - - /** - * Constructor for WorkloadGroupPersistenceService - * - * @param clusterService {@link ClusterService} - The cluster service to be used by WorkloadGroupPersistenceService - * @param settings {@link Settings} - The settings to be used by WorkloadGroupPersistenceService - * @param clusterSettings {@link ClusterSettings} - The cluster settings to be used by WorkloadGroupPersistenceService - */ - @Inject - public WorkloadGroupPersistenceService( - final ClusterService clusterService, - final Settings settings, - final ClusterSettings clusterSettings - ) { - this.clusterService = clusterService; - this.createWorkloadGroupThrottlingKey = clusterService.registerClusterManagerTask(CREATE_QUERY_GROUP_THROTTLING_KEY, true); - this.deleteWorkloadGroupThrottlingKey = clusterService.registerClusterManagerTask(DELETE_QUERY_GROUP_THROTTLING_KEY, true); - this.updateWorkloadGroupThrottlingKey = clusterService.registerClusterManagerTask(UPDATE_QUERY_GROUP_THROTTLING_KEY, true); - setMaxWorkloadGroupCount(MAX_QUERY_GROUP_COUNT.get(settings)); - clusterSettings.addSettingsUpdateConsumer(MAX_QUERY_GROUP_COUNT, this::setMaxWorkloadGroupCount); - } - - /** - * Set maxWorkloadGroupCount to be newMaxWorkloadGroupCount - * @param newMaxWorkloadGroupCount - the max number of WorkloadGroup allowed - */ - public void setMaxWorkloadGroupCount(int newMaxWorkloadGroupCount) { - validateMaxWorkloadGroupCount(newMaxWorkloadGroupCount); - this.maxWorkloadGroupCount = newMaxWorkloadGroupCount; - } - - /** - * Validator for maxWorkloadGroupCount - * @param maxWorkloadGroupCount - the maxWorkloadGroupCount number to be verified - */ - private static void validateMaxWorkloadGroupCount(int maxWorkloadGroupCount) { - if (maxWorkloadGroupCount > DEFAULT_MAX_QUERY_GROUP_COUNT_VALUE || maxWorkloadGroupCount < MIN_QUERY_GROUP_COUNT_VALUE) { - throw new IllegalArgumentException(QUERY_GROUP_COUNT_SETTING_NAME + " should be in range [1-100]."); - } - } - - /** - * Update cluster state to include the new WorkloadGroup - * @param workloadGroup {@link WorkloadGroup} - the WorkloadGroup we're currently creating - * @param listener - ActionListener for CreateWorkloadGroupResponse - */ - public void persistInClusterStateMetadata(WorkloadGroup workloadGroup, ActionListener listener) { - clusterService.submitStateUpdateTask(SOURCE, new ClusterStateUpdateTask(Priority.NORMAL) { - @Override - public ClusterState execute(ClusterState currentState) throws Exception { - return saveWorkloadGroupInClusterState(workloadGroup, currentState); - } - - @Override - public ThrottlingKey getClusterManagerThrottlingKey() { - return createWorkloadGroupThrottlingKey; - } - - @Override - public void onFailure(String source, Exception e) { - logger.warn("failed to save WorkloadGroup object due to error: {}, for source: {}.", e.getMessage(), source); - listener.onFailure(e); - } - - @Override - public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) { - CreateWorkloadGroupResponse response = new CreateWorkloadGroupResponse(workloadGroup, RestStatus.OK); - listener.onResponse(response); - } - }); - } - - /** - * This method will be executed before we submit the new cluster state - * @param workloadGroup - the WorkloadGroup we're currently creating - * @param currentClusterState - the cluster state before the update - */ - ClusterState saveWorkloadGroupInClusterState(final WorkloadGroup workloadGroup, final ClusterState currentClusterState) { - final Map existingWorkloadGroups = currentClusterState.metadata().workloadGroups(); - String groupName = workloadGroup.getName(); - - // check if maxWorkloadGroupCount will breach - if (existingWorkloadGroups.size() == maxWorkloadGroupCount) { - logger.warn("{} value exceeded its assigned limit of {}.", QUERY_GROUP_COUNT_SETTING_NAME, maxWorkloadGroupCount); - throw new IllegalStateException("Can't create more than " + maxWorkloadGroupCount + " WorkloadGroups in the system."); - } - - // check for duplicate name - Optional findExistingGroup = existingWorkloadGroups.values() - .stream() - .filter(group -> group.getName().equals(groupName)) - .findFirst(); - if (findExistingGroup.isPresent()) { - logger.warn("WorkloadGroup with name {} already exists. Not creating a new one.", groupName); - throw new IllegalArgumentException("WorkloadGroup with name " + groupName + " already exists. Not creating a new one."); - } - - // check if there's any resource allocation that exceed limit of 1.0 - validateTotalUsage(existingWorkloadGroups, groupName, workloadGroup.getResourceLimits()); - - return ClusterState.builder(currentClusterState) - .metadata(Metadata.builder(currentClusterState.metadata()).put(workloadGroup).build()) - .build(); - } - - /** - * Get the WorkloadGroups with the specified name from cluster state - * @param name - the WorkloadGroup name we are getting - * @param currentState - current cluster state - */ - public static Collection getFromClusterStateMetadata(String name, ClusterState currentState) { - final Map currentGroups = currentState.getMetadata().workloadGroups(); - if (name == null || name.isEmpty()) { - return currentGroups.values(); - } - return currentGroups.values() - .stream() - .filter(group -> group.getName().equals(name)) - .findAny() - .stream() - .collect(Collectors.toList()); - } - - /** - * Modify cluster state to delete the WorkloadGroup - * @param deleteWorkloadGroupRequest - request to delete a WorkloadGroup - * @param listener - ActionListener for AcknowledgedResponse - */ - public void deleteInClusterStateMetadata( - DeleteWorkloadGroupRequest deleteWorkloadGroupRequest, - ActionListener listener - ) { - clusterService.submitStateUpdateTask(SOURCE, new AckedClusterStateUpdateTask<>(deleteWorkloadGroupRequest, listener) { - @Override - public ClusterState execute(ClusterState currentState) { - return deleteWorkloadGroupInClusterState(deleteWorkloadGroupRequest.getName(), currentState); - } - - @Override - public ClusterManagerTaskThrottler.ThrottlingKey getClusterManagerThrottlingKey() { - return deleteWorkloadGroupThrottlingKey; - } - - @Override - protected AcknowledgedResponse newResponse(boolean acknowledged) { - return new AcknowledgedResponse(acknowledged); - } - }); - } - - /** - * Modify cluster state to delete the WorkloadGroup, and return the new cluster state - * @param name - the name for WorkloadGroup to be deleted - * @param currentClusterState - current cluster state - */ - ClusterState deleteWorkloadGroupInClusterState(final String name, final ClusterState currentClusterState) { - final Metadata metadata = currentClusterState.metadata(); - final WorkloadGroup workloadGroupToRemove = metadata.workloadGroups() - .values() - .stream() - .filter(workloadGroup -> workloadGroup.getName().equals(name)) - .findAny() - .orElseThrow(() -> new ResourceNotFoundException("No WorkloadGroup exists with the provided name: " + name)); - - return ClusterState.builder(currentClusterState).metadata(Metadata.builder(metadata).remove(workloadGroupToRemove).build()).build(); - } - - /** - * Modify cluster state to update the WorkloadGroup - * @param toUpdateGroup {@link WorkloadGroup} - the WorkloadGroup that we want to update - * @param listener - ActionListener for UpdateWorkloadGroupResponse - */ - public void updateInClusterStateMetadata( - UpdateWorkloadGroupRequest toUpdateGroup, - ActionListener listener - ) { - clusterService.submitStateUpdateTask(SOURCE, new ClusterStateUpdateTask(Priority.NORMAL) { - @Override - public ClusterState execute(ClusterState currentState) { - return updateWorkloadGroupInClusterState(toUpdateGroup, currentState); - } - - @Override - public ThrottlingKey getClusterManagerThrottlingKey() { - return updateWorkloadGroupThrottlingKey; - } - - @Override - public void onFailure(String source, Exception e) { - logger.warn("Failed to update WorkloadGroup due to error: {}, for source: {}", e.getMessage(), source); - listener.onFailure(e); - } - - @Override - public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) { - String name = toUpdateGroup.getName(); - Optional findUpdatedGroup = newState.metadata() - .workloadGroups() - .values() - .stream() - .filter(group -> group.getName().equals(name)) - .findFirst(); - assert findUpdatedGroup.isPresent(); - WorkloadGroup updatedGroup = findUpdatedGroup.get(); - UpdateWorkloadGroupResponse response = new UpdateWorkloadGroupResponse(updatedGroup, RestStatus.OK); - listener.onResponse(response); - } - }); - } - - /** - * Modify cluster state to update the existing WorkloadGroup - * @param updateWorkloadGroupRequest {@link WorkloadGroup} - the WorkloadGroup that we want to update - * @param currentState - current cluster state - */ - ClusterState updateWorkloadGroupInClusterState(UpdateWorkloadGroupRequest updateWorkloadGroupRequest, ClusterState currentState) { - final Metadata metadata = currentState.metadata(); - final Map existingGroups = currentState.metadata().workloadGroups(); - String name = updateWorkloadGroupRequest.getName(); - MutableWorkloadGroupFragment mutableWorkloadGroupFragment = updateWorkloadGroupRequest.getmMutableWorkloadGroupFragment(); - - final WorkloadGroup existingGroup = existingGroups.values() - .stream() - .filter(group -> group.getName().equals(name)) - .findFirst() - .orElseThrow(() -> new ResourceNotFoundException("No WorkloadGroup exists with the provided name: " + name)); - - validateTotalUsage(existingGroups, name, mutableWorkloadGroupFragment.getResourceLimits()); - return ClusterState.builder(currentState) - .metadata( - Metadata.builder(metadata) - .remove(existingGroup) - .put(updateExistingWorkloadGroup(existingGroup, mutableWorkloadGroupFragment)) - .build() - ) - .build(); - } - - /** - * This method checks if there's any resource allocation that exceed limit of 1.0 - * @param existingWorkloadGroups - existing WorkloadGroups in the system - * @param resourceLimits - the WorkloadGroup we're creating or updating - */ - private void validateTotalUsage( - Map existingWorkloadGroups, - String name, - Map resourceLimits - ) { - if (resourceLimits == null || resourceLimits.isEmpty()) { - return; - } - final Map totalUsage = new EnumMap<>(ResourceType.class); - totalUsage.putAll(resourceLimits); - for (WorkloadGroup currGroup : existingWorkloadGroups.values()) { - if (!currGroup.getName().equals(name)) { - for (ResourceType resourceType : resourceLimits.keySet()) { - totalUsage.compute(resourceType, (k, v) -> v + currGroup.getResourceLimits().getOrDefault(resourceType, 0.0)); - } - } - } - totalUsage.forEach((resourceType, total) -> { - if (total > 1.0) { - logger.warn("Total resource allocation for {} will go above the max limit of 1.0.", resourceType.getName()); - throw new IllegalArgumentException( - "Total resource allocation for " + resourceType.getName() + " will go above the max limit of 1.0." - ); - } - }); - } - - /** - * maxWorkloadGroupCount getter - */ - public int getMaxWorkloadGroupCount() { - return maxWorkloadGroupCount; - } - - /** - * clusterService getter - */ - public ClusterService getClusterService() { - return clusterService; - } -} 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 deleted file mode 100644 index d206238118734..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/QueryGroupTestUtils.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm; - -import org.opensearch.cluster.ClusterName; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.metadata.Metadata; -import org.opensearch.cluster.metadata.WorkloadGroup; -import org.opensearch.cluster.service.ClusterApplierService; -import org.opensearch.cluster.service.ClusterManagerService; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.collect.Tuple; -import org.opensearch.common.settings.ClusterSettings; -import org.opensearch.common.settings.Setting; -import org.opensearch.common.settings.Settings; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java -import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/QueryGroupTestUtils.java -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.wlm.MutableWorkloadGroupFragment; -import org.opensearch.wlm.ResourceType; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.opensearch.cluster.metadata.WorkloadGroup.builder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -public class WorkloadGroupTestUtils { - public static final String NAME_ONE = "workload_group_one"; - public static final String NAME_TWO = "workload_group_two"; - public static final String _ID_ONE = "AgfUO5Ja9yfsYlONlYi3TQ=="; - public static final String _ID_TWO = "G5iIqHy4g7eK1qIAAAAIH53=1"; - public static final String NAME_NONE_EXISTED = "workload_group_none_existed"; - public static final long TIMESTAMP_ONE = 4513232413L; - public static final long TIMESTAMP_TWO = 4513232415L; - public static final WorkloadGroup workloadGroupOne = builder().name(NAME_ONE) - ._id(_ID_ONE) - .mutableWorkloadGroupFragment( - new MutableWorkloadGroupFragment(MutableWorkloadGroupFragment.ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.3)) - ) - .updatedAt(TIMESTAMP_ONE) - .build(); - - public static final WorkloadGroup workloadGroupTwo = builder().name(NAME_TWO) - ._id(_ID_TWO) - .mutableWorkloadGroupFragment( - new MutableWorkloadGroupFragment(MutableWorkloadGroupFragment.ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.6)) - ) - .updatedAt(TIMESTAMP_TWO) - .build(); - - public static List workloadGroupList() { - List list = new ArrayList<>(); - list.add(workloadGroupOne); - list.add(workloadGroupTwo); - return list; - } - - public static ClusterState clusterState() { - final Metadata metadata = Metadata.builder().workloadGroups(Map.of(_ID_ONE, workloadGroupOne, _ID_TWO, workloadGroupTwo)).build(); - return ClusterState.builder(new ClusterName("_name")).metadata(metadata).build(); - } - - public static Set> clusterSettingsSet() { - Set> set = new HashSet<>(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); - set.add(WorkloadGroupPersistenceService.MAX_QUERY_GROUP_COUNT); - assertFalse(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS.contains(WorkloadGroupPersistenceService.MAX_QUERY_GROUP_COUNT)); - return set; - } - - public static Settings settings() { - return Settings.builder().build(); - } - - public static ClusterSettings clusterSettings() { - return new ClusterSettings(settings(), clusterSettingsSet()); - } - - public static WorkloadGroupPersistenceService workloadGroupPersistenceService() { - ClusterApplierService clusterApplierService = new ClusterApplierService( - "name", - settings(), - clusterSettings(), - mock(ThreadPool.class) - ); - clusterApplierService.setInitialState(clusterState()); - ClusterService clusterService = new ClusterService( - settings(), - clusterSettings(), - mock(ClusterManagerService.class), - clusterApplierService - ); - return new WorkloadGroupPersistenceService(clusterService, settings(), clusterSettings()); - } - - public static Tuple preparePersistenceServiceSetup( - Map workloadGroups - ) { - Metadata metadata = Metadata.builder().workloadGroups(workloadGroups).build(); - Settings settings = Settings.builder().build(); - ClusterState clusterState = ClusterState.builder(new ClusterName("_name")).metadata(metadata).build(); - ClusterSettings clusterSettings = new ClusterSettings(settings, clusterSettingsSet()); - ClusterApplierService clusterApplierService = new ClusterApplierService( - "name", - settings(), - clusterSettings(), - mock(ThreadPool.class) - ); - clusterApplierService.setInitialState(clusterState); - ClusterService clusterService = new ClusterService( - settings(), - clusterSettings(), - mock(ClusterManagerService.class), - clusterApplierService - ); - WorkloadGroupPersistenceService workloadGroupPersistenceService = new WorkloadGroupPersistenceService( - clusterService, - settings, - clusterSettings - ); - return new Tuple(workloadGroupPersistenceService, clusterState); - } - - public static void assertEqualResourceLimits( - Map resourceLimitMapOne, - Map resourceLimitMapTwo - ) { - assertTrue(resourceLimitMapOne.keySet().containsAll(resourceLimitMapTwo.keySet())); - assertTrue(resourceLimitMapOne.values().containsAll(resourceLimitMapTwo.values())); - } - - public static void assertEqualWorkloadGroups( - Collection collectionOne, - Collection collectionTwo, - boolean assertUpdateAt - ) { - assertEquals(collectionOne.size(), collectionTwo.size()); - List listOne = new ArrayList<>(collectionOne); - List listTwo = new ArrayList<>(collectionTwo); - listOne.sort(Comparator.comparing(WorkloadGroup::getName)); - listTwo.sort(Comparator.comparing(WorkloadGroup::getName)); - for (int i = 0; i < listOne.size(); i++) { - if (assertUpdateAt) { - WorkloadGroup one = listOne.get(i); - WorkloadGroup two = listTwo.get(i); - assertEquals(one.getName(), two.getName()); - assertEquals(one.getResourceLimits(), two.getResourceLimits()); - assertEquals(one.getResiliencyMode(), two.getResiliencyMode()); - assertEquals(one.get_id(), two.get_id()); - } else { - assertEquals(listOne.get(i), listTwo.get(i)); - } - } - } -} diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java index 49e258f05619b..bac644a172c1e 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup; +package org.opensearch.plugin.wlm; import org.opensearch.cluster.ClusterName; import org.opensearch.cluster.ClusterState; @@ -19,11 +19,7 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/WorkloadGroupTestUtils.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/QueryGroupTestUtils.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.wlm.MutableWorkloadGroupFragment; import org.opensearch.wlm.ResourceType; 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/action/CreateQueryGroupRequestTests.java deleted file mode 100644 index a756e2dadb2c6..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupRequestTests.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.querygroup.action; - -import org.opensearch.cluster.metadata.WorkloadGroup; -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.assertEqualWorkloadGroups; -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.assertEqualQueryGroups; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequestTests.java - -public class CreateWorkloadGroupRequestTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of CreateWorkloadGroupRequest. - */ - public void testSerialization() throws IOException { - CreateWorkloadGroupRequest request = new CreateWorkloadGroupRequest(workloadGroupOne); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - CreateWorkloadGroupRequest otherRequest = new CreateWorkloadGroupRequest(streamInput); - List list1 = new ArrayList<>(); - List list2 = new ArrayList<>(); - list1.add(workloadGroupOne); - list2.add(otherRequest.getWorkloadGroup()); - assertEqualWorkloadGroups(list1, list2, false); - } -} 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/action/CreateQueryGroupResponseTests.java deleted file mode 100644 index 59d2fa5fd97fa..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateQueryGroupResponseTests.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.cluster.metadata.WorkloadGroup; -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; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java -import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponseTests.java -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.Mockito.mock; - -public class CreateWorkloadGroupResponseTests extends OpenSearchTestCase { - - /** - * Test case to verify serialization and deserialization of CreateWorkloadGroupResponse. - */ - public void testSerialization() throws IOException { - CreateWorkloadGroupResponse response = new CreateWorkloadGroupResponse(WorkloadGroupTestUtils.workloadGroupOne, RestStatus.OK); - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - CreateWorkloadGroupResponse otherResponse = new CreateWorkloadGroupResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); - WorkloadGroup responseGroup = response.getWorkloadGroup(); - WorkloadGroup otherResponseGroup = otherResponse.getWorkloadGroup(); - List listOne = new ArrayList<>(); - List listTwo = new ArrayList<>(); - listOne.add(responseGroup); - listTwo.add(otherResponseGroup); - WorkloadGroupTestUtils.assertEqualWorkloadGroups(listOne, listTwo, false); - } - - /** - * Test case to validate the toXContent method of CreateWorkloadGroupResponse. - */ - public void testToXContentCreateWorkloadGroup() throws IOException { - XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - CreateWorkloadGroupResponse response = new CreateWorkloadGroupResponse(WorkloadGroupTestUtils.workloadGroupOne, RestStatus.OK); - String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" - + " \"_id\" : \"AgfUO5Ja9yfsYlONlYi3TQ==\",\n" - + " \"name\" : \"workload_group_one\",\n" - + " \"resiliency_mode\" : \"monitor\",\n" - + " \"resource_limits\" : {\n" - + " \"memory\" : 0.3\n" - + " },\n" - + " \"updated_at\" : 4513232413\n" - + "}"; - assertEquals(expected, actual); - } -} 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/action/DeleteQueryGroupRequestTests.java deleted file mode 100644 index c7fecfc3095ae..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteQueryGroupRequestTests.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java -import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequestTests.java -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; - -public class DeleteWorkloadGroupRequestTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of DeleteWorkloadGroupRequest. - */ - public void testSerialization() throws IOException { - DeleteWorkloadGroupRequest request = new DeleteWorkloadGroupRequest(WorkloadGroupTestUtils.NAME_ONE); - assertEquals(WorkloadGroupTestUtils.NAME_ONE, request.getName()); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - DeleteWorkloadGroupRequest otherRequest = new DeleteWorkloadGroupRequest(streamInput); - assertEquals(request.getName(), otherRequest.getName()); - } - - /** - * Test case to validate a DeleteWorkloadGroupRequest. - */ - public void testSerializationWithNull() throws IOException { - DeleteWorkloadGroupRequest request = new DeleteWorkloadGroupRequest((String) null); - ActionRequestValidationException actionRequestValidationException = request.validate(); - assertFalse(actionRequestValidationException.getMessage().isEmpty()); - } -} 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/action/GetQueryGroupRequestTests.java deleted file mode 100644 index 683e88251b733..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupRequestTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java -import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequestTests.java -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; - -public class GetWorkloadGroupRequestTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of GetWorkloadGroupRequest. - */ - public void testSerialization() throws IOException { - GetWorkloadGroupRequest request = new GetWorkloadGroupRequest(WorkloadGroupTestUtils.NAME_ONE); - assertEquals(WorkloadGroupTestUtils.NAME_ONE, request.getName()); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - GetWorkloadGroupRequest otherRequest = new GetWorkloadGroupRequest(streamInput); - assertEquals(request.getName(), otherRequest.getName()); - } - - /** - * Test case to verify the serialization and deserialization of GetWorkloadGroupRequest when name is null. - */ - public void testSerializationWithNull() throws IOException { - GetWorkloadGroupRequest request = new GetWorkloadGroupRequest((String) null); - assertNull(request.getName()); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - GetWorkloadGroupRequest otherRequest = new GetWorkloadGroupRequest(streamInput); - assertEquals(request.getName(), otherRequest.getName()); - } - - /** - * Test case the validation function of GetWorkloadGroupRequest - */ - public void testValidation() { - GetWorkloadGroupRequest request = new GetWorkloadGroupRequest("a".repeat(51)); - assertThrows(IllegalArgumentException.class, request::validate); - } -} 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/action/GetQueryGroupResponseTests.java deleted file mode 100644 index b0ce2da8f07b8..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetQueryGroupResponseTests.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.cluster.metadata.WorkloadGroup; -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; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java -import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponseTests.java -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.Mockito.mock; - -public class GetWorkloadGroupResponseTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of GetWorkloadGroupResponse. - */ - public void testSerializationSingleWorkloadGroup() throws IOException { - List list = new ArrayList<>(); - list.add(WorkloadGroupTestUtils.workloadGroupOne); - GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(list, RestStatus.OK); - assertEquals(response.getWorkloadGroups(), list); - - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - - GetWorkloadGroupResponse otherResponse = new GetWorkloadGroupResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); - WorkloadGroupTestUtils.assertEqualWorkloadGroups(response.getWorkloadGroups(), otherResponse.getWorkloadGroups(), false); - } - - /** - * Test case to verify the serialization and deserialization of GetWorkloadGroupResponse when the result contains multiple WorkloadGroups. - */ - public void testSerializationMultipleWorkloadGroup() throws IOException { - GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(WorkloadGroupTestUtils.workloadGroupList(), RestStatus.OK); - assertEquals(response.getWorkloadGroups(), WorkloadGroupTestUtils.workloadGroupList()); - - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - - GetWorkloadGroupResponse otherResponse = new GetWorkloadGroupResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); - assertEquals(2, otherResponse.getWorkloadGroups().size()); - WorkloadGroupTestUtils.assertEqualWorkloadGroups(response.getWorkloadGroups(), otherResponse.getWorkloadGroups(), false); - } - - /** - * Test case to verify the serialization and deserialization of GetWorkloadGroupResponse when the result is empty. - */ - public void testSerializationNull() throws IOException { - List list = new ArrayList<>(); - GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(list, RestStatus.OK); - assertEquals(response.getWorkloadGroups(), list); - - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - - GetWorkloadGroupResponse otherResponse = new GetWorkloadGroupResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); - assertEquals(0, otherResponse.getWorkloadGroups().size()); - } - - /** - * Test case to verify the toXContent of GetWorkloadGroupResponse. - */ - public void testToXContentGetSingleWorkloadGroup() throws IOException { - List workloadGroupList = new ArrayList<>(); - workloadGroupList.add(WorkloadGroupTestUtils.workloadGroupOne); - XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(workloadGroupList, RestStatus.OK); - String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" - + " \"workload_groups\" : [\n" - + " {\n" - + " \"_id\" : \"AgfUO5Ja9yfsYlONlYi3TQ==\",\n" - + " \"name\" : \"workload_group_one\",\n" - + " \"resiliency_mode\" : \"monitor\",\n" - + " \"resource_limits\" : {\n" - + " \"memory\" : 0.3\n" - + " },\n" - + " \"updated_at\" : 4513232413\n" - + " }\n" - + " ]\n" - + "}"; - assertEquals(expected, actual); - } - - /** - * Test case to verify the toXContent of GetWorkloadGroupResponse when the result contains multiple WorkloadGroups. - */ - public void testToXContentGetMultipleWorkloadGroup() throws IOException { - List workloadGroupList = new ArrayList<>(); - workloadGroupList.add(WorkloadGroupTestUtils.workloadGroupOne); - workloadGroupList.add(WorkloadGroupTestUtils.workloadGroupTwo); - XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - GetWorkloadGroupResponse response = new GetWorkloadGroupResponse(workloadGroupList, RestStatus.OK); - String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" - + " \"workload_groups\" : [\n" - + " {\n" - + " \"_id\" : \"AgfUO5Ja9yfsYlONlYi3TQ==\",\n" - + " \"name\" : \"workload_group_one\",\n" - + " \"resiliency_mode\" : \"monitor\",\n" - + " \"resource_limits\" : {\n" - + " \"memory\" : 0.3\n" - + " },\n" - + " \"updated_at\" : 4513232413\n" - + " },\n" - + " {\n" - + " \"_id\" : \"G5iIqHy4g7eK1qIAAAAIH53=1\",\n" - + " \"name\" : \"workload_group_two\",\n" - + " \"resiliency_mode\" : \"monitor\",\n" - + " \"resource_limits\" : {\n" - + " \"memory\" : 0.6\n" - + " },\n" - + " \"updated_at\" : 4513232415\n" - + " }\n" - + " ]\n" - + "}"; - assertEquals(expected, actual); - } - - /** - * Test case to verify toXContent of GetWorkloadGroupResponse when the result contains zero WorkloadGroup. - */ - public void testToXContentGetZeroWorkloadGroup() throws IOException { - XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - GetWorkloadGroupResponse otherResponse = new GetWorkloadGroupResponse(new ArrayList<>(), RestStatus.OK); - String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" + " \"workload_groups\" : [ ]\n" + "}"; - assertEquals(expected, actual); - } -} 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/action/QueryGroupActionTestUtils.java deleted file mode 100644 index 618db92643a8f..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/QueryGroupActionTestUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.plugin.wlm.action.UpdateQueryGroupRequest; -import org.opensearch.wlm.MutableQueryGroupFragment; - -public class QueryGroupActionTestUtils { - public static UpdateQueryGroupRequest updateQueryGroupRequest(String name, MutableQueryGroupFragment mutableQueryGroupFragment) { - return new UpdateQueryGroupRequest(name, 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/action/TransportDeleteQueryGroupActionTests.java deleted file mode 100644 index 0f891cf46bc4a..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteQueryGroupActionTests.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.action.support.ActionFilters; -import org.opensearch.action.support.clustermanager.AcknowledgedResponse; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.core.action.ActionListener; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.TransportDeleteWorkloadGroupAction; -import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.java -import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.TransportService; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class TransportDeleteWorkloadGroupActionTests extends OpenSearchTestCase { - - ClusterService clusterService = mock(ClusterService.class); - TransportService transportService = mock(TransportService.class); - ActionFilters actionFilters = mock(ActionFilters.class); - ThreadPool threadPool = mock(ThreadPool.class); - IndexNameExpressionResolver indexNameExpressionResolver = mock(IndexNameExpressionResolver.class); - WorkloadGroupPersistenceService workloadGroupPersistenceService = mock(WorkloadGroupPersistenceService.class); - - TransportDeleteWorkloadGroupAction action = new TransportDeleteWorkloadGroupAction( - clusterService, - transportService, - actionFilters, - threadPool, - indexNameExpressionResolver, - workloadGroupPersistenceService - ); - - /** - * Test case to validate the construction for TransportDeleteWorkloadGroupAction - */ - public void testConstruction() { - assertNotNull(action); - assertEquals(ThreadPool.Names.SAME, action.executor()); - } - - /** - * Test case to validate the clusterManagerOperation function in TransportDeleteWorkloadGroupAction - */ - public void testClusterManagerOperation() throws Exception { - DeleteWorkloadGroupRequest request = new DeleteWorkloadGroupRequest("testGroup"); - @SuppressWarnings("unchecked") - ActionListener listener = mock(ActionListener.class); - ClusterState clusterState = mock(ClusterState.class); - action.clusterManagerOperation(request, clusterState, listener); - verify(workloadGroupPersistenceService).deleteInClusterStateMetadata(eq(request), eq(listener)); - } -} 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/action/TransportGetQueryGroupActionTests.java deleted file mode 100644 index c38b53206f63e..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetQueryGroupActionTests.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.support.ActionFilters; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.core.action.ActionListener; -import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.TransportGetWorkloadGroupAction; -import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.TransportService; - -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_NONE_EXISTED; -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.clusterState; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_NONE_EXISTED; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterState; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupActionTests.java -import static org.mockito.Mockito.mock; - -public class TransportGetWorkloadGroupActionTests extends OpenSearchTestCase { - - /** - * Test case for ClusterManagerOperation function - */ - @SuppressWarnings("unchecked") - public void testClusterManagerOperation() throws Exception { - GetWorkloadGroupRequest getWorkloadGroupRequest1 = new GetWorkloadGroupRequest(NAME_NONE_EXISTED); - GetWorkloadGroupRequest getWorkloadGroupRequest2 = new GetWorkloadGroupRequest(NAME_ONE); - TransportGetWorkloadGroupAction transportGetWorkloadGroupAction = new TransportGetWorkloadGroupAction( - mock(ClusterService.class), - mock(TransportService.class), - mock(ActionFilters.class), - mock(ThreadPool.class), - mock(IndexNameExpressionResolver.class) - ); - assertThrows( - ResourceNotFoundException.class, - () -> transportGetWorkloadGroupAction.clusterManagerOperation( - getWorkloadGroupRequest1, - clusterState(), - mock(ActionListener.class) - ) - ); - transportGetWorkloadGroupAction.clusterManagerOperation(getWorkloadGroupRequest2, clusterState(), mock(ActionListener.class)); - } -} 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/action/UpdateQueryGroupRequestTests.java deleted file mode 100644 index db7c3a1540bf8..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupRequestTests.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.querygroup.action; - -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.wlm.MutableWorkloadGroupFragment; -import org.opensearch.wlm.MutableWorkloadGroupFragment.ResiliencyMode; -import org.opensearch.wlm.ResourceType; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequestTests.java - -public class UpdateWorkloadGroupRequestTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of UpdateWorkloadGroupRequest. - */ - public void testSerialization() throws IOException { - UpdateWorkloadGroupRequest request = new UpdateWorkloadGroupRequest(NAME_ONE, workloadGroupOne.getMutableWorkloadGroupFragment()); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - UpdateWorkloadGroupRequest otherRequest = new UpdateWorkloadGroupRequest(streamInput); - assertEquals(request.getName(), otherRequest.getName()); - assertEquals(request.getmMutableWorkloadGroupFragment(), otherRequest.getmMutableWorkloadGroupFragment()); - } - - /** - * Test case to verify the serialization and deserialization of UpdateWorkloadGroupRequest with only name field. - */ - public void testSerializationOnlyName() throws IOException { - UpdateWorkloadGroupRequest request = new UpdateWorkloadGroupRequest( - NAME_ONE, - new MutableWorkloadGroupFragment(null, new HashMap<>()) - ); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - UpdateWorkloadGroupRequest otherRequest = new UpdateWorkloadGroupRequest(streamInput); - assertEquals(request.getName(), otherRequest.getName()); - assertEquals(request.getmMutableWorkloadGroupFragment(), otherRequest.getmMutableWorkloadGroupFragment()); - } - - /** - * Test case to verify the serialization and deserialization of UpdateWorkloadGroupRequest with only resourceLimits field. - */ - public void testSerializationOnlyResourceLimit() throws IOException { - UpdateWorkloadGroupRequest request = new UpdateWorkloadGroupRequest( - NAME_ONE, - new MutableWorkloadGroupFragment(null, Map.of(ResourceType.MEMORY, 0.4)) - ); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - UpdateWorkloadGroupRequest otherRequest = new UpdateWorkloadGroupRequest(streamInput); - assertEquals(request.getName(), otherRequest.getName()); - assertEquals(request.getmMutableWorkloadGroupFragment(), otherRequest.getmMutableWorkloadGroupFragment()); - } - - /** - * Tests invalid ResourceType. - */ - public void testInvalidResourceLimitList() { - assertThrows( - IllegalArgumentException.class, - () -> new UpdateWorkloadGroupRequest( - NAME_ONE, - new MutableWorkloadGroupFragment( - ResiliencyMode.MONITOR, - Map.of(ResourceType.MEMORY, 0.3, ResourceType.fromName("random"), 0.4) - ) - ) - ); - } - - /** - * Tests invalid resiliencyMode. - */ - public void testInvalidEnforcement() { - assertThrows( - IllegalArgumentException.class, - () -> new UpdateWorkloadGroupRequest( - NAME_ONE, - new MutableWorkloadGroupFragment(ResiliencyMode.fromName("random"), Map.of(ResourceType.fromName("memory"), 0.3)) - ) - ); - } -} 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/action/UpdateQueryGroupResponseTests.java deleted file mode 100644 index 8923d069c396a..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateQueryGroupResponseTests.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.action; - -import org.opensearch.cluster.metadata.WorkloadGroup; -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; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java -import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java -import static org.mockito.Mockito.mock; - -public class UpdateWorkloadGroupResponseTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of UpdateWorkloadGroupResponse. - */ - public void testSerialization() throws IOException { - UpdateWorkloadGroupResponse response = new UpdateWorkloadGroupResponse(workloadGroupOne, RestStatus.OK); - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - UpdateWorkloadGroupResponse otherResponse = new UpdateWorkloadGroupResponse(streamInput); - assertEquals(response.getRestStatus(), otherResponse.getRestStatus()); - WorkloadGroup responseGroup = response.getWorkloadGroup(); - WorkloadGroup otherResponseGroup = otherResponse.getWorkloadGroup(); - List list1 = new ArrayList<>(); - List list2 = new ArrayList<>(); - list1.add(responseGroup); - list2.add(otherResponseGroup); - WorkloadGroupTestUtils.assertEqualWorkloadGroups(list1, list2, false); - } - - /** - * Test case to verify the toXContent method of UpdateWorkloadGroupResponse. - */ - public void testToXContentUpdateSingleWorkloadGroup() throws IOException { - XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - UpdateWorkloadGroupResponse otherResponse = new UpdateWorkloadGroupResponse(workloadGroupOne, RestStatus.OK); - String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" - + " \"_id\" : \"AgfUO5Ja9yfsYlONlYi3TQ==\",\n" - + " \"name\" : \"workload_group_one\",\n" - + " \"resiliency_mode\" : \"monitor\",\n" - + " \"resource_limits\" : {\n" - + " \"memory\" : 0.3\n" - + " },\n" - + " \"updated_at\" : 4513232413\n" - + "}"; - assertEquals(expected, actual); - } -} 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/rest/RestDeleteQueryGroupActionTests.java deleted file mode 100644 index 1fb83e02ad12d..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteQueryGroupActionTests.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rest; - -import org.opensearch.action.support.clustermanager.AcknowledgedResponse; -import org.opensearch.common.CheckedConsumer; -import org.opensearch.common.unit.TimeValue; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -======== -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java -import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; -import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestHandler; -import org.opensearch.rest.RestRequest; -import org.opensearch.rest.action.RestToXContentListener; -import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.test.rest.FakeRestRequest; -import org.opensearch.transport.client.node.NodeClient; - -import java.util.List; - -import org.mockito.ArgumentCaptor; - -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java -import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java -import static org.opensearch.rest.RestRequest.Method.DELETE; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -public class RestDeleteWorkloadGroupActionTests extends OpenSearchTestCase { - /** - * Test case to validate the construction for RestDeleteWorkloadGroupAction - */ - public void testConstruction() { - RestDeleteWorkloadGroupAction action = new RestDeleteWorkloadGroupAction(); - assertNotNull(action); - assertEquals("delete_workload_group", action.getName()); - List routes = action.routes(); - assertEquals(1, routes.size()); - RestHandler.Route route = routes.get(0); - assertEquals(DELETE, route.getMethod()); - assertEquals("_wlm/workload_group/{name}", route.getPath()); - } - - /** - * Test case to validate the prepareRequest logic for RestDeleteWorkloadGroupAction - */ - @SuppressWarnings("unchecked") - public void testPrepareRequest() throws Exception { - RestDeleteWorkloadGroupAction restDeleteWorkloadGroupAction = new RestDeleteWorkloadGroupAction(); - NodeClient nodeClient = mock(NodeClient.class); - RestRequest realRequest = new FakeRestRequest(); - realRequest.params().put("name", NAME_ONE); - ; - RestRequest spyRequest = spy(realRequest); - - doReturn(TimeValue.timeValueSeconds(30)).when(spyRequest).paramAsTime(eq("cluster_manager_timeout"), any(TimeValue.class)); - doReturn(TimeValue.timeValueSeconds(60)).when(spyRequest).paramAsTime(eq("timeout"), any(TimeValue.class)); - - CheckedConsumer consumer = restDeleteWorkloadGroupAction.prepareRequest(spyRequest, nodeClient); - assertNotNull(consumer); - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(DeleteWorkloadGroupRequest.class); - ArgumentCaptor> listenerCaptor = ArgumentCaptor.forClass(RestToXContentListener.class); - doNothing().when(nodeClient).execute(eq(DeleteWorkloadGroupAction.INSTANCE), requestCaptor.capture(), listenerCaptor.capture()); - - consumer.accept(mock(RestChannel.class)); - DeleteWorkloadGroupRequest capturedRequest = requestCaptor.getValue(); - assertEquals(NAME_ONE, capturedRequest.getName()); - assertEquals(TimeValue.timeValueSeconds(30), capturedRequest.clusterManagerNodeTimeout()); - assertEquals(TimeValue.timeValueSeconds(60), capturedRequest.timeout()); - verify(nodeClient).execute( - eq(DeleteWorkloadGroupAction.INSTANCE), - any(DeleteWorkloadGroupRequest.class), - any(RestToXContentListener.class) - ); - } -} 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/service/QueryGroupPersistenceServiceTests.java deleted file mode 100644 index 4b95a63394118..0000000000000 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/service/QueryGroupPersistenceServiceTests.java +++ /dev/null @@ -1,515 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.service; - -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.support.clustermanager.AcknowledgedResponse; -import org.opensearch.cluster.AckedClusterStateUpdateTask; -import org.opensearch.cluster.ClusterName; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.ClusterStateUpdateTask; -import org.opensearch.cluster.metadata.Metadata; -import org.opensearch.cluster.metadata.QueryGroup; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.collect.Tuple; -import org.opensearch.common.settings.ClusterSettings; -import org.opensearch.common.settings.Settings; -import org.opensearch.core.action.ActionListener; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; -import org.opensearch.plugin.wlm.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; -import org.opensearch.wlm.MutableQueryGroupFragment.ResiliencyMode; -import org.opensearch.wlm.ResourceType; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import org.mockito.ArgumentCaptor; - -import static org.opensearch.cluster.metadata.QueryGroup.builder; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_NONE_EXISTED; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_TWO; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils._ID_ONE; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils._ID_TWO; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.assertEqualQueryGroups; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterSettings; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterSettingsSet; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterState; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.preparePersistenceServiceSetup; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupList; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupPersistenceService; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupTwo; -import static org.opensearch.plugin.wlm.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; -import static org.mockito.Mockito.argThat; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -public class QueryGroupPersistenceServiceTests extends OpenSearchTestCase { - - /** - * Test case to validate the creation logic of a QueryGroup - */ - public void testCreateQueryGroup() { - Tuple setup = preparePersistenceServiceSetup(new HashMap<>()); - QueryGroupPersistenceService queryGroupPersistenceService1 = setup.v1(); - ClusterState clusterState = setup.v2(); - ClusterState newClusterState = queryGroupPersistenceService1.saveQueryGroupInClusterState(queryGroupOne, clusterState); - Map updatedGroupsMap = newClusterState.getMetadata().queryGroups(); - assertEquals(1, updatedGroupsMap.size()); - assertTrue(updatedGroupsMap.containsKey(_ID_ONE)); - List listOne = new ArrayList<>(); - List listTwo = new ArrayList<>(); - listOne.add(queryGroupOne); - listTwo.add(updatedGroupsMap.get(_ID_ONE)); - assertEqualQueryGroups(listOne, listTwo, false); - } - - /** - * Test case to validate the logic for adding a new QueryGroup to a cluster state that already contains - * an existing QueryGroup - */ - public void testCreateAnotherQueryGroup() { - Tuple setup = preparePersistenceServiceSetup(Map.of(_ID_ONE, queryGroupOne)); - QueryGroupPersistenceService queryGroupPersistenceService1 = setup.v1(); - ClusterState clusterState = setup.v2(); - ClusterState newClusterState = queryGroupPersistenceService1.saveQueryGroupInClusterState(queryGroupTwo, clusterState); - Map updatedGroups = newClusterState.getMetadata().queryGroups(); - assertEquals(2, updatedGroups.size()); - assertTrue(updatedGroups.containsKey(_ID_TWO)); - Collection values = updatedGroups.values(); - assertEqualQueryGroups(queryGroupList(), new ArrayList<>(values), false); - } - - /** - * Test case to ensure the error is thrown when we try to create another QueryGroup with duplicate name - */ - public void testCreateQueryGroupDuplicateName() { - Tuple setup = preparePersistenceServiceSetup(Map.of(_ID_ONE, queryGroupOne)); - QueryGroupPersistenceService queryGroupPersistenceService1 = setup.v1(); - ClusterState clusterState = setup.v2(); - QueryGroup toCreate = builder().name(NAME_ONE) - ._id("W5iIqHyhgi4K1qIAAAAIHw==") - .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.3))) - .updatedAt(1690934400000L) - .build(); - assertThrows(RuntimeException.class, () -> queryGroupPersistenceService1.saveQueryGroupInClusterState(toCreate, clusterState)); - } - - /** - * Test case to ensure the error is thrown when we try to create another QueryGroup that will make - * the total resource limits go above 1 - */ - public void testCreateQueryGroupOverflowAllocation() { - Tuple setup = preparePersistenceServiceSetup(Map.of(_ID_TWO, queryGroupTwo)); - QueryGroup toCreate = builder().name(NAME_ONE) - ._id("W5iIqHyhgi4K1qIAAAAIHw==") - .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.41))) - .updatedAt(1690934400000L) - .build(); - - QueryGroupPersistenceService queryGroupPersistenceService1 = setup.v1(); - ClusterState clusterState = setup.v2(); - assertThrows(RuntimeException.class, () -> queryGroupPersistenceService1.saveQueryGroupInClusterState(toCreate, clusterState)); - } - - /** - * Test case to ensure the error is thrown when we already have the max allowed number of QueryGroups, but - * we want to create another one - */ - public void testCreateQueryGroupOverflowCount() { - QueryGroup toCreate = builder().name(NAME_NONE_EXISTED) - ._id("W5iIqHyhgi4K1qIAAAAIHw==") - .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.5))) - .updatedAt(1690934400000L) - .build(); - Metadata metadata = Metadata.builder().queryGroups(Map.of(_ID_ONE, queryGroupOne, _ID_TWO, queryGroupTwo)).build(); - Settings settings = Settings.builder().put(QUERY_GROUP_COUNT_SETTING_NAME, 2).build(); - ClusterSettings clusterSettings = new ClusterSettings(settings, clusterSettingsSet()); - ClusterService clusterService = new ClusterService(settings, clusterSettings, mock(ThreadPool.class)); - ClusterState clusterState = ClusterState.builder(new ClusterName("_name")).metadata(metadata).build(); - QueryGroupPersistenceService queryGroupPersistenceService1 = new QueryGroupPersistenceService( - clusterService, - settings, - clusterSettings - ); - assertThrows(RuntimeException.class, () -> queryGroupPersistenceService1.saveQueryGroupInClusterState(toCreate, clusterState)); - } - - /** - * Tests the invalid value of {@code node.query_group.max_count} - */ - public void testInvalidMaxQueryGroupCount() { - Settings settings = Settings.builder().put(QUERY_GROUP_COUNT_SETTING_NAME, 2).build(); - ClusterSettings clusterSettings = new ClusterSettings(settings, clusterSettingsSet()); - ClusterService clusterService = new ClusterService(settings, clusterSettings, mock(ThreadPool.class)); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - settings, - clusterSettings - ); - assertThrows(IllegalArgumentException.class, () -> queryGroupPersistenceService.setMaxQueryGroupCount(-1)); - } - - /** - * Tests the valid value of {@code node.query_group.max_count} - */ - public void testValidMaxSandboxCountSetting() { - Settings settings = Settings.builder().put(QUERY_GROUP_COUNT_SETTING_NAME, 100).build(); - ClusterService clusterService = new ClusterService(settings, clusterSettings(), mock(ThreadPool.class)); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - settings, - clusterSettings() - ); - queryGroupPersistenceService.setMaxQueryGroupCount(50); - assertEquals(50, queryGroupPersistenceService.getMaxQueryGroupCount()); - } - - /** - * Tests PersistInClusterStateMetadata function - */ - public void testPersistInClusterStateMetadata() { - ClusterService clusterService = mock(ClusterService.class); - @SuppressWarnings("unchecked") - ActionListener listener = mock(ActionListener.class); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - QueryGroupTestUtils.settings(), - clusterSettings() - ); - queryGroupPersistenceService.persistInClusterStateMetadata(queryGroupOne, listener); - verify(clusterService).submitStateUpdateTask(eq(SOURCE), any()); - } - - /** - * Tests PersistInClusterStateMetadata function with inner functions - */ - public void testPersistInClusterStateMetadataInner() { - ClusterService clusterService = mock(ClusterService.class); - @SuppressWarnings("unchecked") - ActionListener listener = mock(ActionListener.class); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - QueryGroupTestUtils.settings(), - clusterSettings() - ); - ArgumentCaptor captor = ArgumentCaptor.forClass(ClusterStateUpdateTask.class); - queryGroupPersistenceService.persistInClusterStateMetadata(queryGroupOne, listener); - verify(clusterService, times(1)).submitStateUpdateTask(eq(SOURCE), captor.capture()); - ClusterStateUpdateTask capturedTask = captor.getValue(); - assertEquals(queryGroupPersistenceService.createQueryGroupThrottlingKey, capturedTask.getClusterManagerThrottlingKey()); - - doAnswer(invocation -> { - ClusterStateUpdateTask task = invocation.getArgument(1); - task.clusterStateProcessed(SOURCE, mock(ClusterState.class), mock(ClusterState.class)); - return null; - }).when(clusterService).submitStateUpdateTask(anyString(), any()); - queryGroupPersistenceService.persistInClusterStateMetadata(queryGroupOne, listener); - verify(listener).onResponse(any(CreateQueryGroupResponse.class)); - } - - /** - * Tests PersistInClusterStateMetadata function with failure - */ - public void testPersistInClusterStateMetadataFailure() { - ClusterService clusterService = mock(ClusterService.class); - @SuppressWarnings("unchecked") - ActionListener listener = mock(ActionListener.class); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - QueryGroupTestUtils.settings(), - clusterSettings() - ); - doAnswer(invocation -> { - ClusterStateUpdateTask task = invocation.getArgument(1); - Exception exception = new RuntimeException("Test Exception"); - task.onFailure(SOURCE, exception); - return null; - }).when(clusterService).submitStateUpdateTask(anyString(), any()); - queryGroupPersistenceService.persistInClusterStateMetadata(queryGroupOne, listener); - verify(listener).onFailure(any(RuntimeException.class)); - } - - /** - * Tests getting a single QueryGroup - */ - public void testGetSingleQueryGroup() { - Collection groupsCollections = QueryGroupPersistenceService.getFromClusterStateMetadata(NAME_ONE, clusterState()); - List groups = new ArrayList<>(groupsCollections); - assertEquals(1, groups.size()); - QueryGroup queryGroup = groups.get(0); - List listOne = new ArrayList<>(); - List listTwo = new ArrayList<>(); - listOne.add(QueryGroupTestUtils.queryGroupOne); - listTwo.add(queryGroup); - QueryGroupTestUtils.assertEqualQueryGroups(listOne, listTwo, false); - } - - /** - * Tests getting all QueryGroups - */ - public void testGetAllQueryGroups() { - assertEquals(2, QueryGroupTestUtils.clusterState().metadata().queryGroups().size()); - Collection groupsCollections = QueryGroupPersistenceService.getFromClusterStateMetadata(null, clusterState()); - List res = new ArrayList<>(groupsCollections); - assertEquals(2, res.size()); - Set currentNAME = res.stream().map(QueryGroup::getName).collect(Collectors.toSet()); - assertTrue(currentNAME.contains(QueryGroupTestUtils.NAME_ONE)); - assertTrue(currentNAME.contains(QueryGroupTestUtils.NAME_TWO)); - QueryGroupTestUtils.assertEqualQueryGroups(QueryGroupTestUtils.queryGroupList(), res, false); - } - - /** - * Tests getting a QueryGroup with invalid name - */ - public void testGetNonExistedQueryGroups() { - Collection groupsCollections = QueryGroupPersistenceService.getFromClusterStateMetadata( - NAME_NONE_EXISTED, - clusterState() - ); - List groups = new ArrayList<>(groupsCollections); - assertEquals(0, groups.size()); - } - - /** - * Tests setting maxQueryGroupCount - */ - public void testMaxQueryGroupCount() { - assertThrows(IllegalArgumentException.class, () -> QueryGroupTestUtils.queryGroupPersistenceService().setMaxQueryGroupCount(-1)); - QueryGroupPersistenceService queryGroupPersistenceService = QueryGroupTestUtils.queryGroupPersistenceService(); - queryGroupPersistenceService.setMaxQueryGroupCount(50); - assertEquals(50, queryGroupPersistenceService.getMaxQueryGroupCount()); - } - - /** - * Tests delete a single QueryGroup - */ - public void testDeleteSingleQueryGroup() { - ClusterState newClusterState = queryGroupPersistenceService().deleteQueryGroupInClusterState(NAME_TWO, clusterState()); - Map afterDeletionGroups = newClusterState.getMetadata().queryGroups(); - assertFalse(afterDeletionGroups.containsKey(_ID_TWO)); - assertEquals(1, afterDeletionGroups.size()); - List oldQueryGroups = new ArrayList<>(); - oldQueryGroups.add(queryGroupOne); - assertEqualQueryGroups(new ArrayList<>(afterDeletionGroups.values()), oldQueryGroups, false); - } - - /** - * Tests delete a QueryGroup with invalid name - */ - public void testDeleteNonExistedQueryGroup() { - assertThrows( - ResourceNotFoundException.class, - () -> queryGroupPersistenceService().deleteQueryGroupInClusterState(NAME_NONE_EXISTED, clusterState()) - ); - } - - /** - * Tests DeleteInClusterStateMetadata function - */ - @SuppressWarnings("unchecked") - public void testDeleteInClusterStateMetadata() throws Exception { - DeleteQueryGroupRequest request = new DeleteQueryGroupRequest(NAME_ONE); - ClusterService clusterService = mock(ClusterService.class); - - ActionListener listener = mock(ActionListener.class); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - QueryGroupTestUtils.settings(), - clusterSettings() - ); - doAnswer(invocation -> { - AckedClusterStateUpdateTask task = invocation.getArgument(1); - ClusterState initialState = clusterState(); - ClusterState newState = task.execute(initialState); - assertNotNull(newState); - assertEquals(queryGroupPersistenceService.deleteQueryGroupThrottlingKey, task.getClusterManagerThrottlingKey()); - task.onAllNodesAcked(null); - verify(listener).onResponse(argThat(response -> response.isAcknowledged())); - return null; - }).when(clusterService).submitStateUpdateTask(anyString(), any()); - queryGroupPersistenceService.deleteInClusterStateMetadata(request, listener); - verify(clusterService).submitStateUpdateTask(eq(SOURCE), any(AckedClusterStateUpdateTask.class)); - } - - /** - * Tests updating a QueryGroup with all fields - */ - public void testUpdateQueryGroupAllFields() { - QueryGroup updated = builder().name(NAME_ONE) - ._id(_ID_ONE) - .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.ENFORCED, Map.of(ResourceType.MEMORY, 0.15))) - .updatedAt(1690934400000L) - .build(); - UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest(NAME_ONE, updated.getMutableQueryGroupFragment()); - ClusterState newClusterState = queryGroupPersistenceService().updateQueryGroupInClusterState( - updateQueryGroupRequest, - clusterState() - ); - List updatedQueryGroups = new ArrayList<>(newClusterState.getMetadata().queryGroups().values()); - assertEquals(2, updatedQueryGroups.size()); - List expectedList = new ArrayList<>(); - expectedList.add(queryGroupTwo); - expectedList.add(updated); - assertEqualQueryGroups(expectedList, updatedQueryGroups, true); - } - - /** - * Tests updating a QueryGroup with only updated resourceLimits - */ - public void testUpdateQueryGroupResourceLimitsOnly() { - QueryGroup updated = builder().name(NAME_ONE) - ._id(_ID_ONE) - .mutableQueryGroupFragment(new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.15))) - .updatedAt(1690934400000L) - .build(); - UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest(NAME_ONE, updated.getMutableQueryGroupFragment()); - ClusterState newClusterState = queryGroupPersistenceService().updateQueryGroupInClusterState( - updateQueryGroupRequest, - clusterState() - ); - List updatedQueryGroups = new ArrayList<>(newClusterState.getMetadata().queryGroups().values()); - assertEquals(2, updatedQueryGroups.size()); - Optional findUpdatedGroupOne = newClusterState.metadata() - .queryGroups() - .values() - .stream() - .filter(group -> group.getName().equals(NAME_ONE)) - .findFirst(); - Optional findUpdatedGroupTwo = newClusterState.metadata() - .queryGroups() - .values() - .stream() - .filter(group -> group.getName().equals(NAME_TWO)) - .findFirst(); - assertTrue(findUpdatedGroupOne.isPresent()); - assertTrue(findUpdatedGroupTwo.isPresent()); - List list1 = new ArrayList<>(); - list1.add(updated); - List list2 = new ArrayList<>(); - list2.add(findUpdatedGroupOne.get()); - assertEqualQueryGroups(list1, list2, true); - } - - /** - * Tests updating a QueryGroup with invalid name - */ - public void testUpdateQueryGroupNonExistedName() { - QueryGroupPersistenceService queryGroupPersistenceService = queryGroupPersistenceService(); - UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest( - NAME_NONE_EXISTED, - new MutableQueryGroupFragment(ResiliencyMode.MONITOR, Map.of(ResourceType.MEMORY, 0.15)) - ); - assertThrows( - RuntimeException.class, - () -> queryGroupPersistenceService.updateQueryGroupInClusterState(updateQueryGroupRequest, clusterState()) - ); - List updatedQueryGroups = new ArrayList<>( - queryGroupPersistenceService.getClusterService().state().metadata().queryGroups().values() - ); - assertEquals(2, updatedQueryGroups.size()); - List expectedList = new ArrayList<>(); - expectedList.add(queryGroupTwo); - expectedList.add(queryGroupOne); - assertEqualQueryGroups(expectedList, updatedQueryGroups, true); - } - - /** - * Tests UpdateInClusterStateMetadata function - */ - public void testUpdateInClusterStateMetadata() { - ClusterService clusterService = mock(ClusterService.class); - @SuppressWarnings("unchecked") - ActionListener listener = mock(ActionListener.class); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - QueryGroupTestUtils.settings(), - clusterSettings() - ); - queryGroupPersistenceService.updateInClusterStateMetadata(null, listener); - verify(clusterService).submitStateUpdateTask(eq(SOURCE), any()); - } - - /** - * Tests UpdateInClusterStateMetadata function with inner functions - */ - public void testUpdateInClusterStateMetadataInner() { - ClusterService clusterService = mock(ClusterService.class); - @SuppressWarnings("unchecked") - ActionListener listener = mock(ActionListener.class); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - QueryGroupTestUtils.settings(), - clusterSettings() - ); - UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest( - NAME_TWO, - new MutableQueryGroupFragment(ResiliencyMode.SOFT, new HashMap<>()) - ); - ArgumentCaptor captor = ArgumentCaptor.forClass(ClusterStateUpdateTask.class); - queryGroupPersistenceService.updateInClusterStateMetadata(updateQueryGroupRequest, listener); - verify(clusterService, times(1)).submitStateUpdateTask(eq(SOURCE), captor.capture()); - ClusterStateUpdateTask capturedTask = captor.getValue(); - assertEquals(queryGroupPersistenceService.updateQueryGroupThrottlingKey, capturedTask.getClusterManagerThrottlingKey()); - - doAnswer(invocation -> { - ClusterStateUpdateTask task = invocation.getArgument(1); - task.clusterStateProcessed(SOURCE, clusterState(), clusterState()); - return null; - }).when(clusterService).submitStateUpdateTask(anyString(), any()); - queryGroupPersistenceService.updateInClusterStateMetadata(updateQueryGroupRequest, listener); - verify(listener).onResponse(any(UpdateQueryGroupResponse.class)); - } - - /** - * Tests UpdateInClusterStateMetadata function with failure - */ - public void testUpdateInClusterStateMetadataFailure() { - ClusterService clusterService = mock(ClusterService.class); - @SuppressWarnings("unchecked") - ActionListener listener = mock(ActionListener.class); - QueryGroupPersistenceService queryGroupPersistenceService = new QueryGroupPersistenceService( - clusterService, - QueryGroupTestUtils.settings(), - clusterSettings() - ); - UpdateQueryGroupRequest updateQueryGroupRequest = updateQueryGroupRequest( - NAME_TWO, - new MutableQueryGroupFragment(ResiliencyMode.SOFT, new HashMap<>()) - ); - doAnswer(invocation -> { - ClusterStateUpdateTask task = invocation.getArgument(1); - Exception exception = new RuntimeException("Test Exception"); - task.onFailure(SOURCE, exception); - return null; - }).when(clusterService).submitStateUpdateTask(anyString(), any()); - queryGroupPersistenceService.updateInClusterStateMetadata(updateQueryGroupRequest, listener); - verify(listener).onFailure(any(RuntimeException.class)); - } -} From 86b79585c3897cf36aab4e847b9b50bc653e16db Mon Sep 17 00:00:00 2001 From: Lingxi Chen Date: Tue, 15 Apr 2025 12:52:10 -0700 Subject: [PATCH 04/11] rebase Signed-off-by: Lingxi Chen --- .../wlm/action/TransportCreateWorkloadGroupAction.java | 4 ---- .../wlm/action/TransportDeleteWorkloadGroupAction.java | 4 ---- .../wlm/action/TransportGetWorkloadGroupAction.java | 4 ---- .../wlm/action/TransportUpdateWorkloadGroupAction.java | 8 -------- .../plugin/wlm/rest/RestCreateWorkloadGroupAction.java | 5 ----- .../plugin/wlm/rest/RestDeleteWorkloadGroupAction.java | 5 ----- .../plugin/wlm/rest/RestGetWorkloadGroupAction.java | 6 ------ .../plugin/wlm/rest/RestUpdateWorkloadGroupAction.java | 6 ------ .../wlm/service/WorkloadGroupPersistenceService.java | 7 ------- .../wlm/action/CreateWorkloadGroupRequestTests.java | 7 +------ .../wlm/action/CreateWorkloadGroupResponseTests.java | 5 ----- .../wlm/action/DeleteWorkloadGroupRequestTests.java | 5 ----- .../plugin/wlm/action/GetWorkloadGroupRequestTests.java | 5 ----- .../plugin/wlm/action/GetWorkloadGroupResponseTests.java | 5 ----- .../action/TransportDeleteWorkloadGroupActionTests.java | 6 ------ .../wlm/action/TransportGetWorkloadGroupActionTests.java | 6 ------ .../wlm/action/UpdateWorkloadGroupRequestTests.java | 7 +------ .../wlm/action/UpdateWorkloadGroupResponseTests.java | 8 -------- .../wlm/rest/RestDeleteWorkloadGroupActionTests.java | 9 --------- 19 files changed, 2 insertions(+), 110 deletions(-) diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java index e13b682914dd3..2039f1cb590ff 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportCreateWorkloadGroupAction.java @@ -17,11 +17,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java index 5fc8b30bf419c..2bfbadba4d51d 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupAction.java @@ -19,11 +19,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java index ab1ff9f247c56..bb2fbab047343 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupAction.java @@ -23,11 +23,7 @@ import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.rest.RestStatus; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupAction.java import org.opensearch.search.pipeline.SearchPipelineService; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java index 58e094514f57e..ef639d44b4155 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java @@ -17,15 +17,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateWorkloadGroupAction.java -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/action/TransportCreateQueryGroupAction.java -======== -import org.opensearch.plugin.wlm.service.QueryGroupPersistenceService; ->>>>>>>> ccb9c34c0d8 (refactoring):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/action/TransportUpdateQueryGroupAction.java import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java index 06624664d46eb..5ef59602f7893 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestCreateWorkloadGroupAction.java @@ -11,14 +11,9 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.CreateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java index 8a1591b015372..d0d82f43679fa 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupAction.java @@ -8,13 +8,8 @@ package org.opensearch.plugin.wlm.rest; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -======== -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupAction.java 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/RestGetWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java index 4879adc6898c2..818531352f4d3 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestGetWorkloadGroupAction.java @@ -10,15 +10,9 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.GetWorkloadGroupAction; import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.GetQueryGroupResponse; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestGetQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java index ee3564dc5c7f6..db77dc5963037 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rest/RestUpdateWorkloadGroupAction.java @@ -11,15 +11,9 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentParser; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestUpdateWorkloadGroupAction.java import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupAction; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; -======== -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/rest/RestCreateQueryGroupAction.java import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java index 4d7f7d9aabc4d..8fd5fe5dfcfed 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/service/WorkloadGroupPersistenceService.java @@ -27,18 +27,11 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.action.ActionListener; import org.opensearch.core.rest.RestStatus; -<<<<<<<< HEAD:plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/WorkloadGroupPersistenceService.java import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupRequest; import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; import org.opensearch.wlm.MutableWorkloadGroupFragment; -======== -import org.opensearch.plugin.wlm.querygroup.action.CreateQueryGroupResponse; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; -import org.opensearch.plugin.wlm.querygroup.action.UpdateQueryGroupResponse; -import org.opensearch.wlm.MutableQueryGroupFragment; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/querygroup/service/QueryGroupPersistenceService.java import org.opensearch.wlm.ResourceType; import java.util.Collection; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java index a756e2dadb2c6..c8669fbc8c8f4 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; @@ -18,13 +18,8 @@ import java.util.ArrayList; import java.util.List; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupRequestTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.assertEqualWorkloadGroups; import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.assertEqualQueryGroups; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupRequestTests.java public class CreateWorkloadGroupRequestTests extends OpenSearchTestCase { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java index 59d2fa5fd97fa..d25050341f997 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupResponseTests.java @@ -15,12 +15,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateWorkloadGroupResponseTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.CreateWorkloadGroupResponse; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/CreateQueryGroupResponseTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java index c7fecfc3095ae..a7fa0939583c5 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/DeleteWorkloadGroupRequestTests.java @@ -11,12 +11,7 @@ import org.opensearch.action.ActionRequestValidationException; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteWorkloadGroupRequestTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/DeleteQueryGroupRequestTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java index 683e88251b733..832761d5084bb 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupRequestTests.java @@ -10,12 +10,7 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupRequestTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupRequestTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java index b0ce2da8f07b8..dc0aeabc7a033 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/GetWorkloadGroupResponseTests.java @@ -15,12 +15,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetWorkloadGroupResponseTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== -import org.opensearch.plugin.wlm.action.GetWorkloadGroupResponse; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/GetQueryGroupResponseTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java index 0f891cf46bc4a..7ffa33aa8a80a 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportDeleteWorkloadGroupActionTests.java @@ -14,13 +14,7 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.action.ActionListener; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteWorkloadGroupActionTests.java -import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.TransportDeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -======== -import org.opensearch.plugin.wlm.querygroup.service.QueryGroupPersistenceService; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportDeleteQueryGroupActionTests.java import org.opensearch.test.OpenSearchTestCase; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java index c38b53206f63e..6c6ef9072355a 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java @@ -19,15 +19,9 @@ import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetWorkloadGroupActionTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_NONE_EXISTED; import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.clusterState; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_NONE_EXISTED; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.clusterState; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/TransportGetQueryGroupActionTests.java import static org.mockito.Mockito.mock; public class TransportGetWorkloadGroupActionTests extends OpenSearchTestCase { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java index db7c3a1540bf8..e8d883da5c6eb 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupRequestTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.querygroup.action; +package org.opensearch.plugin.wlm.action; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; @@ -19,13 +19,8 @@ import java.util.HashMap; import java.util.Map; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupRequestTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupRequestTests.java public class UpdateWorkloadGroupRequestTests extends OpenSearchTestCase { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java index 8923d069c396a..3e515d19197b7 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java @@ -15,23 +15,15 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -======== import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; -import org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; import java.util.ArrayList; import java.util.List; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateWorkloadGroupResponseTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.workloadGroupOne; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.queryGroupOne; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/action/UpdateQueryGroupResponseTests.java import static org.mockito.Mockito.mock; public class UpdateWorkloadGroupResponseTests extends OpenSearchTestCase { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java index 1fb83e02ad12d..357ea2598142f 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java @@ -11,13 +11,8 @@ import org.opensearch.action.support.clustermanager.AcknowledgedResponse; import org.opensearch.common.CheckedConsumer; import org.opensearch.common.unit.TimeValue; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -======== -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupAction; -import org.opensearch.plugin.wlm.querygroup.action.DeleteQueryGroupRequest; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestHandler; @@ -31,11 +26,7 @@ >>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src import org.mockito.ArgumentCaptor; -<<<<<<<< HEAD:plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteWorkloadGroupActionTests.java import static org.opensearch.plugin.wlm.WorkloadGroupTestUtils.NAME_ONE; -======== -import static org.opensearch.plugin.wlm.querygroup.QueryGroupTestUtils.NAME_ONE; ->>>>>>>> c83500db863 (add update rule api logic):plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/querygroup/rest/RestDeleteQueryGroupActionTests.java import static org.opensearch.rest.RestRequest.Method.DELETE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; From dedea140a6c35f7fa0cdd711aca704333ee5eacb Mon Sep 17 00:00:00 2001 From: Lingxi Chen Date: Tue, 15 Apr 2025 14:03:17 -0700 Subject: [PATCH 05/11] rebase Signed-off-by: Lingxi Chen --- .../plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java index 357ea2598142f..8ce5c869f4481 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rest/RestDeleteWorkloadGroupActionTests.java @@ -13,7 +13,6 @@ import org.opensearch.common.unit.TimeValue; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupAction; import org.opensearch.plugin.wlm.action.DeleteWorkloadGroupRequest; -import org.opensearch.plugin.wlm.rest.RestDeleteWorkloadGroupAction; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestHandler; import org.opensearch.rest.RestRequest; From 7734098dfef1d3938bda535fc00c4b090687576b Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Tue, 29 Apr 2025 04:14:36 -0700 Subject: [PATCH 06/11] rebase update rule api Signed-off-by: Ruirui Zhang --- .../secure_sm/policy}/package-info.java | 4 +- .../rule/action/GetRuleResponse.java | 105 -------- .../opensearch/rule/action/package-info.java | 12 - .../opensearch/rule/rest/package-info.java | 12 - .../IndexStoredRulePersistenceService.java | 241 ------------------ .../rule/service/RulePersistenceService.java | 26 -- .../opensearch/rule/service/package-info.java | 13 - .../rule/utils/IndexStoredRuleParser.java | 51 ---- .../rule/utils/IndexStoredRuleUtils.java | 108 -------- .../rule/action/UpdateRuleRequestTests.java | 60 ----- .../rule/action/UpdateRuleResponseTests.java | 60 ----- ...ndexStoredRulePersistenceServiceTests.java | 47 ---- .../utils/IndexStoredRuleParserTests.java | 52 ---- .../rule/utils/IndexStoredRuleUtilsTests.java | 102 -------- .../opensearch/rule/utils/RuleTestUtils.java | 157 ------------ .../opensearch/rule/DuplicateRuleChecker.java | 28 ++ .../rule/RulePersistenceService.java | 7 + .../java/org/opensearch/rule/RuleUtils.java | 25 ++ .../opensearch/rule}/UpdateRuleRequest.java | 20 +- .../opensearch/rule}/UpdateRuleResponse.java | 10 +- .../org/opensearch/rule/autotagging/Rule.java | 4 + .../rule/autotagging/RuleValidator.java | 24 +- .../IndexStoredRulePersistenceService.java | 66 +++++ .../IndexBasedDuplicateRuleChecker.java | 59 +++++ .../opensearch/rule/RuleFrameworkPlugin.java | 8 +- .../rule/action/TransportGetRuleAction.java | 2 +- .../action/TransportUpdateRuleAction.java | 53 ++++ .../rule/action/UpdateRuleAction.java | 36 +++ .../rule/rest/RestUpdateRuleAction.java | 39 ++- .../InMemoryRuleProcessingServiceTests.java | 1 + .../plugin/wlm/WorkloadManagementPlugin.java | 1 + .../wlm/WorkloadManagementPluginModule.java | 3 - .../plugin/wlm/rule/QueryGroupAttribute.java | 61 ----- .../wlm/rule/QueryGroupFeatureType.java | 64 ----- .../action/TransportUpdateWlmRuleAction.java | 61 ----- .../wlm/rule/action/UpdateWlmRuleAction.java | 37 --- .../plugin/wlm/rule/action/package-info.java | 12 - .../CreateWorkloadGroupRequestTests.java | 1 - .../TransportGetWorkloadGroupActionTests.java | 2 - .../UpdateWorkloadGroupResponseTests.java | 1 - 40 files changed, 342 insertions(+), 1333 deletions(-) rename libs/{autotagging-commons/src/main/java/org/opensearch/rule/utils => agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy}/package-info.java (71%) delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java delete mode 100644 libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java delete mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java delete mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java delete mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java delete mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java delete mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java delete mode 100644 libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java create mode 100644 modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DuplicateRuleChecker.java rename {libs/autotagging-commons/src/main/java/org/opensearch/rule/action => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/UpdateRuleRequest.java (88%) rename {libs/autotagging-commons/src/main/java/org/opensearch/rule/action => modules/autotagging-commons/common/src/main/java/org/opensearch/rule}/UpdateRuleResponse.java (89%) create mode 100644 modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedDuplicateRuleChecker.java create mode 100644 modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java create mode 100644 modules/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleAction.java rename {libs => modules}/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java (64%) delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/UpdateWlmRuleAction.java delete mode 100644 plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java similarity index 71% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java rename to libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java index c3437a5f6a77a..d182490b8d173 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/package-info.java +++ b/libs/agent-sm/agent-policy/src/main/java/org/opensearch/secure_sm/policy/package-info.java @@ -7,6 +7,6 @@ */ /** - * This package contains utility classes for rules + * Java Agent Policy */ -package org.opensearch.rule.utils; +package org.opensearch.secure_sm.policy; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java deleted file mode 100644 index 5ddb9eb712e7d..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleResponse.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.action; - -import org.opensearch.autotagging.Rule; -import org.opensearch.common.annotation.ExperimentalApi; -import org.opensearch.core.action.ActionResponse; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.ToXContentObject; -import org.opensearch.core.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.Map; - -import static org.opensearch.autotagging.Rule._ID_STRING; - -/** - * Response for the get API for Rule. - * Example response: - * { - * "rules": [ - * { - * "_id": "z1MJApUB0zgMcDmz-UQq", - * "description": "Rule for tagging query_group_id to index123" - * "index_pattern": ["index123"], - * "query_group": "query_group_id", - * "updated_at": "2025-02-14T01:19:22.589Z" - * }, - * ... - * ], - * "search_after": ["z1MJApUB0zgMcDmz-UQq"] - * } - * @opensearch.experimental - */ -@ExperimentalApi -public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final Map rules; - private final String searchAfter; - private final RestStatus restStatus; - - /** - * Constructor for GetRuleResponse - * @param rules - Rules get from the request - * @param searchAfter - The sort value used for pagination. - * @param restStatus - Status of the GetRuleResponse - */ - public GetRuleResponse(final Map rules, String searchAfter, RestStatus restStatus) { - this.rules = rules; - this.searchAfter = searchAfter; - this.restStatus = restStatus; - } - - /** - * Constructs a GetRuleResponse from a StreamInput for deserialization - * @param in - The {@link StreamInput} instance to read from. - */ - public GetRuleResponse(StreamInput in) throws IOException { - this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString(), RestStatus.readFrom(in)); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeMap(rules, StreamOutput::writeString, (outStream, rule) -> rule.writeTo(outStream)); - out.writeOptionalString(searchAfter); - RestStatus.writeTo(out, restStatus); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.startArray("rules"); - for (Map.Entry entry : rules.entrySet()) { - entry.getValue().toXContent(builder, new MapParams(Map.of(_ID_STRING, entry.getKey()))); - } - builder.endArray(); - if (searchAfter != null && !searchAfter.isEmpty()) { - builder.field("search_after", new Object[] { searchAfter }); - } - builder.endObject(); - return builder; - } - - /** - * rules getter - */ - public Map getRules() { - return rules; - } - - /** - * restStatus getter - */ - public RestStatus getRestStatus() { - return restStatus; - } -} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java deleted file mode 100644 index 91913aff23eac..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/** - * This package contains abstract action classes for rules - */ -package org.opensearch.rule.action; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java deleted file mode 100644 index c1000b90b1856..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/** - * This package contains abstract rest classes for rules - */ -package org.opensearch.rule.rest; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java deleted file mode 100644 index 993de0e6a6b7e..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.service; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.search.SearchRequestBuilder; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.action.update.UpdateRequest; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; -import org.opensearch.cluster.service.ClusterService; -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.index.query.BoolQueryBuilder; -import org.opensearch.rule.action.GetRuleResponse; -import org.opensearch.rule.action.UpdateRuleRequest; -import org.opensearch.rule.action.UpdateRuleResponse; -import org.opensearch.rule.utils.IndexStoredRuleParser; -import org.opensearch.rule.utils.IndexStoredRuleUtils; -import org.opensearch.search.SearchHit; -import org.opensearch.search.sort.SortOrder; -import org.opensearch.transport.client.Client; - -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.opensearch.autotagging.Rule._ID_STRING; - -/** - * This class encapsulates the logic to manage the lifecycle of rules at index level - * @opensearch.experimental - */ -public class IndexStoredRulePersistenceService implements RulePersistenceService { - /** - * The system index name used for storing rules - */ - private final String indexName; - private final ClusterService clusterService; - private final Client client; - private final FeatureType featureType; - private final int maxRulesPerPage; - private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); - - /** - * Constructs an instance of {@link IndexStoredRulePersistenceService} with the specified parameters. - * This service handles persistence and retrieval of stored rules within an OpenSearch index. - * @param indexName - The name of the OpenSearch index where the rules are stored. - * @param clusterService - The clusterService used in IndexStoredRulePersistenceService. - * @param client - The OpenSearch client used to interact with the OpenSearch cluster. - * @param featureType - The feature type associated with the stored rules. - * @param maxRulesPerPage - The maximum number of rules that can be returned in a single get request. - */ - public IndexStoredRulePersistenceService( - String indexName, - ClusterService clusterService, - Client client, - FeatureType featureType, - int maxRulesPerPage - ) { - this.indexName = indexName; - this.clusterService = clusterService; - this.client = client; - this.featureType = featureType; - this.maxRulesPerPage = maxRulesPerPage; - } - - /** - * Entry point for the update rule api logic in persistence service. - * @param request - The UpdateRuleRequest - * @param listener - ActionListener for UpdateRuleResponse - */ - public void updateRule(UpdateRuleRequest request, ActionListener listener) { - String ruleId = request.get_id(); - try (ThreadContext.StoredContext context = getContext()) { - getRuleFromIndex(ruleId, new HashMap<>(), null, new ActionListener<>() { - @Override - public void onResponse(GetRuleResponse getRuleResponse) { - if (getRuleResponse == null || getRuleResponse.getRules().isEmpty()) { - listener.onFailure(new ResourceNotFoundException("Rule with ID " + ruleId + " not found.")); - return; - } - Rule updatedRule = IndexStoredRuleUtils.composeUpdatedRule( - getRuleResponse.getRules().get(ruleId), - request, - featureType - ); - validateNoDuplicateRule(updatedRule, new ActionListener<>() { - @Override - public void onResponse(Void unused) { - persistUpdatedRule(ruleId, updatedRule, listener); - } - - @Override - public void onFailure(Exception e) { - listener.onFailure(e); - } - }); - } - - @Override - public void onFailure(Exception e) { - listener.onFailure(e); - } - }); - } - } - - /** - * Validates that no duplicate rule exists with the same attribute map. - * If a conflict is found, fails the listener - * @param rule - the rule we check duplicate against - * @param listener - listener for validateNoDuplicateRule response - */ - private void validateNoDuplicateRule(Rule rule, ActionListener listener) { - try (ThreadContext.StoredContext ctx = getContext()) { - getRuleFromIndex(null, rule.getAttributeMap(), null, new ActionListener<>() { - @Override - public void onResponse(GetRuleResponse getRuleResponse) { - Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(rule, getRuleResponse.getRules()); - duplicateRuleId.ifPresentOrElse( - id -> listener.onFailure(new IllegalArgumentException("Rule already exists under rule id " + id)), - () -> listener.onResponse(null) - ); - } - - @Override - public void onFailure(Exception e) { - listener.onFailure(e); - } - }); - } - } - - /** - * Persist the updated rule in index - * @param ruleId - the rule id to update - * @param updatedRule - the rule we update to - * @param listener - ActionListener for UpdateRuleResponse - */ - private void persistUpdatedRule(String ruleId, Rule updatedRule, ActionListener listener) { - try (ThreadContext.StoredContext context = getContext()) { - UpdateRequest updateRequest = new UpdateRequest(indexName, ruleId).doc( - updatedRule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) - ); - client.update( - updateRequest, - ActionListener.wrap(updateResponse -> { listener.onResponse(new UpdateRuleResponse(ruleId, updatedRule)); }, e -> { - logger.error("Failed to update Rule object due to error: {}", e.getMessage()); - listener.onFailure(e); - }) - ); - } catch (IOException e) { - logger.error("Error updating rule in index: {}", indexName); - listener.onFailure(new RuntimeException("Failed to update rule to index.")); - } - } - - /** - * Entry point for the get rule api logic in persistence service. If id is provided, we only get a single rule. - * Otherwise, we get all rules that satisfy the attributeFilters. - * @param id - The id of the rule to get. - * @param attributeFilters - A map containing the attributes that user want to filter on - * @param searchAfter - The sort values from the last document of the previous page, used for pagination - * @param listener - ActionListener for GetRuleResponse - */ - private void getRuleFromIndex( - String id, - Map> attributeFilters, - String searchAfter, - ActionListener listener - ) { - // Stash the current thread context when interacting with system index to perform - // operations as the system itself, bypassing authorization checks. This ensures that - // actions within this block are trusted and executed with system-level privileges. - try (ThreadContext.StoredContext context = getContext()) { - BoolQueryBuilder boolQuery = IndexStoredRuleUtils.buildGetRuleQuery(id, attributeFilters, featureType); - SearchRequestBuilder searchRequest = client.prepareSearch(indexName).setQuery(boolQuery).setSize(maxRulesPerPage); - if (searchAfter != null) { - searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); - } - searchRequest.execute(ActionListener.wrap(searchResponse -> handleGetRuleResponse(id, searchResponse, listener), e -> { - logger.error("Failed to fetch all rules: {}", e.getMessage()); - listener.onFailure(e); - })); - } - } - - /** - * Process searchResponse from index and send a GetRuleResponse - * @param searchResponse - Response received from index - * @param listener - ActionListener for GetRuleResponse - */ - private void handleGetRuleResponse(String id, SearchResponse searchResponse, ActionListener listener) { - List hits = Arrays.asList(searchResponse.getHits().getHits()); - if (id != null && hits.isEmpty()) { - logger.error("Rule with ID " + id + " not found."); - listener.onFailure(new ResourceNotFoundException("Rule with ID " + id + " doesn't exist in the .rules index.")); - return; - } - Map ruleMap = hits.stream() - .collect(Collectors.toMap(SearchHit::getId, hit -> IndexStoredRuleParser.parseRule(hit.getSourceAsString(), featureType))); - String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); - listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter, RestStatus.OK)); - } - - private ThreadContext.StoredContext getContext() { - return client.threadPool().getThreadContext().stashContext(); - } - - /** - * client getter - */ - public Client getClient() { - return client; - } - - /** - * clusterService getter - */ - public ClusterService getClusterService() { - return clusterService; - } -} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java deleted file mode 100644 index f0264e8829536..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/RulePersistenceService.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.service; - -import org.opensearch.core.action.ActionListener; -import org.opensearch.rule.action.UpdateRuleRequest; -import org.opensearch.rule.action.UpdateRuleResponse; - -/** - * Interface for a service that handles rule persistence CRUD operations. - * @opensearch.experimental - */ -public interface RulePersistenceService { - /** - * Update rule based on the provided request. - * @param request The request containing the details for updating the rule. - * @param listener The listener that will handle the response or failure. - */ - void updateRule(UpdateRuleRequest request, ActionListener listener); -} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java deleted file mode 100644 index a1ec9ea7c8521..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/service/package-info.java +++ /dev/null @@ -1,13 +0,0 @@ - -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/** - * This package contains abstract service classes for rules - */ -package org.opensearch.rule.service; diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java deleted file mode 100644 index ccf48cceb645a..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleParser.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.utils; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; -import org.opensearch.core.xcontent.DeprecationHandler; -import org.opensearch.core.xcontent.MediaTypeRegistry; -import org.opensearch.core.xcontent.NamedXContentRegistry; -import org.opensearch.core.xcontent.XContentParser; - -import java.io.IOException; - -/** - * Utility class for parsing index stored rules into Rule objects. - * @opensearch.experimental - */ -public class IndexStoredRuleParser { - - /** - * constructor for IndexStoredRuleParser - */ - private IndexStoredRuleParser() {} - - private static final Logger logger = LogManager.getLogger(IndexStoredRuleParser.class); - - /** - * Parses a source string into a Rule object - * @param source - The raw source string representing the rule to be parsed - * @param featureType - The feature type to associate with the parsed rule - */ - public static Rule parseRule(String source, FeatureType featureType) { - try ( - XContentParser parser = MediaTypeRegistry.JSON.xContent() - .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source) - ) { - return Rule.Builder.fromXContent(parser, featureType).build(); - } catch (IOException e) { - logger.info("Issue met when parsing rule {}: {}", source, e.getMessage()); - throw new RuntimeException("Cannot parse rule from index: " + source); - } - } -} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java b/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java deleted file mode 100644 index 072c682f3d3d8..0000000000000 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/utils/IndexStoredRuleUtils.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.utils; - -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; -import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.index.query.QueryBuilders; -import org.opensearch.rule.action.UpdateRuleRequest; - -import java.time.Instant; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static org.opensearch.autotagging.Rule._ID_STRING; - -/** - * Utility class that provides methods for the lifecycle of rules. - * @opensearch.experimental - */ -public class IndexStoredRuleUtils { - - /** - * constructor for IndexStoredRuleUtils - */ - private IndexStoredRuleUtils() {} - - /** - * Builds a Boolean query to retrieve a rule by its ID or attribute filters. - * @param id The ID of the rule to search for. If null, no ID-based filtering is applied. - * @param attributeFilters A map of attributes and their corresponding filter values. This allows filtering by specific attribute values. - * @param featureType The feature type that is required in the query. - */ - public static BoolQueryBuilder buildGetRuleQuery(String id, Map> attributeFilters, FeatureType featureType) { - BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); - if (id != null) { - return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); - } - for (Map.Entry> entry : attributeFilters.entrySet()) { - Attribute attribute = entry.getKey(); - Set values = entry.getValue(); - if (values != null && !values.isEmpty()) { - BoolQueryBuilder attributeQuery = QueryBuilders.boolQuery(); - for (String value : values) { - attributeQuery.should(QueryBuilders.matchQuery(attribute.getName(), value)); - } - boolQuery.must(attributeQuery); - } - } - boolQuery.filter(QueryBuilders.existsQuery(featureType.getName())); - return boolQuery; - } - - /** - * Checks if a duplicate rule exists based on the attribute map. - * A rule is considered a duplicate when the attribute value already exists in the index, and the number of - * attributes in the new rule is equal to the number of attributes in an existing rule. - * - * For example, if an existing rule has: - * attribute1 = ['a'] and attribute2 = ['c'] - * And we are creating a new rule with: - * attribute1 = ['a'] - * Then it's not a duplicate because the existing rule has attribute2 and is more granular - * - * @param rule The rule to be validated against ruleMap. - * @param ruleMap This map entries are Rules that contain the attribute values from rule, meaning they - * have a partial or complete overlap with the new rule being created. - */ - public static Optional getDuplicateRuleId(Rule rule, Map ruleMap) { - Map> attributeMapToValidate = rule.getAttributeMap(); - for (Map.Entry entry : ruleMap.entrySet()) { - String ruleId = entry.getKey(); - Rule currRule = entry.getValue(); - // Compare the size of the attribute maps to ensure we only check for duplicates with the same number of attributes. - if (attributeMapToValidate.size() == currRule.getAttributeMap().size()) { - return Optional.of(ruleId); - } - } - return Optional.empty(); - } - - /** - * Compose the updated rule from the original rule and the UpdateRuleRequest - * @param originalRule - the existing rule - * @param request - the UpdateRuleRequest - * @param featureType - the featureType for the rule - */ - public static Rule composeUpdatedRule(Rule originalRule, UpdateRuleRequest request, FeatureType featureType) { - String requestDescription = request.getDescription(); - Map> requestMap = request.getAttributeMap(); - String requestLabel = request.getFeatureValue(); - return new Rule( - requestDescription == null ? originalRule.getDescription() : requestDescription, - requestMap == null || requestMap.isEmpty() ? originalRule.getAttributeMap() : requestMap, - featureType, - requestLabel == null ? originalRule.getFeatureValue() : requestLabel, - Instant.now().toString() - ); - } -} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java deleted file mode 100644 index 34d5c06aaa131..0000000000000 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.action; - -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.utils.RuleTestUtils; -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; - -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.FEATURE_VALUE_ONE; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; - -public class UpdateRuleRequestTests extends OpenSearchTestCase { - - /** - * Test case to verify the serialization and deserialization of UpdateRuleRequest. - */ - public void testSerialization() throws IOException { - UpdateRuleRequest request = new UpdateRuleRequest( - _ID_ONE, - DESCRIPTION_ONE, - ATTRIBUTE_MAP, - FEATURE_VALUE_ONE, - RuleTestUtils.MockRuleFeatureType.INSTANCE - ); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - UpdateRuleRequest otherRequest = new UpdateRuleRequest(streamInput); - assertEquals(request.get_id(), otherRequest.get_id()); - assertEquals(request.getFeatureValue(), otherRequest.getFeatureValue()); - assertEquals(request.getAttributeMap(), otherRequest.getAttributeMap()); - assertEquals(request.getDescription(), otherRequest.getDescription()); - } - - /** - * Test case to verify the serialization and deserialization of UpdateRuleRequest when there's null values. - */ - public void testSerializationWithNull() throws IOException { - UpdateRuleRequest request = new UpdateRuleRequest(_ID_ONE, null, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE); - BytesStreamOutput out = new BytesStreamOutput(); - request.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - UpdateRuleRequest otherRequest = new UpdateRuleRequest(streamInput); - assertEquals(request.get_id(), otherRequest.get_id()); - assertEquals(request.getFeatureValue(), otherRequest.getFeatureValue()); - assertEquals(request.getAttributeMap(), otherRequest.getAttributeMap()); - assertEquals(request.getDescription(), otherRequest.getDescription()); - } -} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java deleted file mode 100644 index fac087603125c..0000000000000 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.action; - -import org.opensearch.autotagging.Rule; -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.common.xcontent.json.JsonXContent; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; - -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRule; -import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; -import static org.mockito.Mockito.mock; - -public class UpdateRuleResponseTests extends OpenSearchTestCase { - - /** - * Test case to verify serialization and deserialization of UpdateRuleResponse - */ - public void testSerialization() throws IOException { - UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); - BytesStreamOutput out = new BytesStreamOutput(); - response.writeTo(out); - StreamInput streamInput = out.bytes().streamInput(); - UpdateRuleResponse otherResponse = new UpdateRuleResponse(streamInput); - Rule responseRule = response.getRule(); - Rule otherResponseRule = otherResponse.getRule(); - assertEqualRule(responseRule, otherResponseRule, true); - } - - /** - * Test case to validate the toXContent method of UpdateRuleResponse - */ - public void testToXContentUpdateRule() throws IOException { - XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); - String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" - + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" - + " \"description\" : \"description_1\",\n" - + " \"mock_attribute_one\" : [\n" - + " \"mock_attribute_one\"\n" - + " ],\n" - + " \"mock_feature_type\" : \"feature_value_one\",\n" - + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" - + "}"; - assertEquals(expected, actual); - } -} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java deleted file mode 100644 index 47c0382368083..0000000000000 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.service; - -import org.opensearch.test.OpenSearchTestCase; - -@SuppressWarnings("unchecked") -public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { - // public void testPersistUpdatedRule_Success() throws IOException { - // IndexStoredRulePersistenceService indexStoredRulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - // Client client = indexStoredRulePersistenceService.getClient(); - // UpdateResponse updateResponse = mock(UpdateResponse.class); - // when(updateResponse.status()).thenReturn(RestStatus.OK); - // ActionListener listener = mock(ActionListener.class); - // ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(UpdateRequest.class); - // doAnswer(invocation -> { - // ActionListener callback = invocation.getArgument(1); - // callback.onResponse(updateResponse); - // return null; - // }).when(client).update(requestCaptor.capture(), any()); - // indexStoredRulePersistenceService.persistUpdatedRule(_ID_ONE, ruleTwo, listener); - // verify(listener, times(1)).onResponse(any(UpdateRuleResponse.class)); - // verify(listener, never()).onFailure(any()); - // assertEquals(_ID_ONE, requestCaptor.getValue().id()); - // } - // - // public void testPersistUpdatedRule_UpdateFailure() { - // IndexStoredRulePersistenceService indexStoredRulePersistenceService = setUpIndexStoredRulePersistenceService(new HashMap<>()); - // Client client = indexStoredRulePersistenceService.getClient(); - // ActionListener listener = mock(ActionListener.class); - // doAnswer(invocation -> { - // ActionListener callback = invocation.getArgument(1); - // callback.onFailure(new Exception("Update failure")); - // return null; - // }).when(client).update(any(UpdateRequest.class), any()); - // indexStoredRulePersistenceService.persistUpdatedRule(_ID_ONE, ruleTwo, listener); - // - // verify(listener, times(1)).onFailure(any(Exception.class)); - // verify(listener, never()).onResponse(any()); - // } -} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java deleted file mode 100644 index 18e1bb99926b7..0000000000000 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleParserTests.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.utils; - -import org.opensearch.autotagging.Rule; -import org.opensearch.test.OpenSearchTestCase; - -import java.io.IOException; -import java.time.Instant; -import java.util.Locale; - -import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; - -public class IndexStoredRuleParserTests extends OpenSearchTestCase { - public static final String VALID_JSON = String.format(Locale.ROOT, """ - { - "description": "%s", - "mock_feature_type": "feature value", - "mock_attribute_one": ["attribute_value_one", "attribute_value_two"], - "updated_at": "%s" - } - """, DESCRIPTION_ONE, Instant.now().toString()); - - private static final String INVALID_JSON = """ - { - "name": "TestRule", - "description": "A test rule for unit testing", - "mock_attribute_three": ["attribute_value_one", "attribute_value_two"] - } - """; - - public void testParseRule_Success() throws IOException { - Rule parsedRule = IndexStoredRuleParser.parseRule(VALID_JSON, RuleTestUtils.MockRuleFeatureType.INSTANCE); - assertNotNull(parsedRule); - assertEquals(DESCRIPTION_ONE, parsedRule.getDescription()); - assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, parsedRule.getFeatureType()); - } - - public void testParseRule_InvalidJson() { - Exception exception = assertThrows( - RuntimeException.class, - () -> IndexStoredRuleParser.parseRule(INVALID_JSON, RuleTestUtils.MockRuleFeatureType.INSTANCE) - ); - assertTrue(exception.getMessage().contains("mock_attribute_three is not a valid attribute within the mock_feature_type feature.")); - } -} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java deleted file mode 100644 index 2009ef8f5ee1c..0000000000000 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/IndexStoredRuleUtilsTests.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.utils; - -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.Rule; -import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.action.UpdateRuleRequest; -import org.opensearch.test.OpenSearchTestCase; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_TWO; -import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_TWO; -import static org.opensearch.rule.utils.RuleTestUtils.FEATURE_VALUE_TWO; -import static org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class IndexStoredRuleUtilsTests extends OpenSearchTestCase { - public void testBuildGetRuleQuery_WithId() { - BoolQueryBuilder query = IndexStoredRuleUtils.buildGetRuleQuery( - _ID_ONE, - new HashMap<>(), - RuleTestUtils.MockRuleFeatureType.INSTANCE - ); - assertNotNull(query); - assertEquals(1, query.must().size()); - QueryBuilder idQuery = query.must().get(0); - assertTrue(idQuery.toString().contains(_ID_ONE)); - } - - public void testBuildGetRuleQuery_WithAttributes() { - BoolQueryBuilder query = IndexStoredRuleUtils.buildGetRuleQuery(null, ATTRIBUTE_MAP, RuleTestUtils.MockRuleFeatureType.INSTANCE); - assertNotNull(query); - assertTrue(query.must().size() == 1); - assertTrue(query.toString().contains(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE.getName())); - assertTrue(query.toString().contains(ATTRIBUTE_VALUE_ONE)); - } - - public void testGetDuplicateRuleId_Found() { - Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(ruleOne, Map.of(_ID_ONE, ruleOne)); - assertFalse(duplicateRuleId.isEmpty()); - assertEquals(_ID_ONE, duplicateRuleId.get()); - } - - public void testGetDuplicateRuleId_NotFound() { - Rule rule = mock(Rule.class); - Map> map = Map.of( - RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, - Set.of(ATTRIBUTE_VALUE_ONE), - RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, - Set.of(ATTRIBUTE_VALUE_TWO) - ); - when(rule.getAttributeMap()).thenReturn(map); - Optional duplicateRuleId = IndexStoredRuleUtils.getDuplicateRuleId(rule, Map.of(_ID_ONE, ruleOne)); - assertTrue(duplicateRuleId.isEmpty()); - } - - public void testComposeUpdatedRule() { - UpdateRuleRequest request = mock(UpdateRuleRequest.class); - Map> attributeMap = new HashMap<>(); - attributeMap.put(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_TWO)); - when(request.getDescription()).thenReturn(DESCRIPTION_TWO); - when(request.getAttributeMap()).thenReturn(attributeMap); - when(request.getFeatureValue()).thenReturn(FEATURE_VALUE_TWO); - Rule updatedRule = IndexStoredRuleUtils.composeUpdatedRule(ruleOne, request, MockRuleFeatureType.INSTANCE); - assertEquals(DESCRIPTION_TWO, updatedRule.getDescription()); - assertEquals(attributeMap, updatedRule.getAttributeMap()); - assertEquals(FEATURE_VALUE_TWO, updatedRule.getFeatureValue()); - assertEquals(MockRuleFeatureType.INSTANCE, updatedRule.getFeatureType()); - } - - public void testComposeUpdatedRule_WithNull() { - UpdateRuleRequest request = mock(UpdateRuleRequest.class); - Map> attributeMap = new HashMap<>(); - attributeMap.put(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_TWO)); - when(request.getDescription()).thenReturn(null); - when(request.getAttributeMap()).thenReturn(attributeMap); - when(request.getFeatureValue()).thenReturn(FEATURE_VALUE_TWO); - Rule updatedRule = IndexStoredRuleUtils.composeUpdatedRule(ruleOne, request, MockRuleFeatureType.INSTANCE); - assertEquals(DESCRIPTION_ONE, updatedRule.getDescription()); - assertEquals(attributeMap, updatedRule.getAttributeMap()); - assertEquals(FEATURE_VALUE_TWO, updatedRule.getFeatureValue()); - assertEquals(MockRuleFeatureType.INSTANCE, updatedRule.getFeatureType()); - } -} diff --git a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java deleted file mode 100644 index fd9a228370af4..0000000000000 --- a/libs/autotagging-commons/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.utils; - -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.AutoTaggingRegistry; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.metadata.Metadata; -import org.opensearch.cluster.metadata.QueryGroup; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rule.service.IndexStoredRulePersistenceService; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.client.Client; - -import java.util.Map; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class RuleTestUtils { - public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; - public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; - public static final String FEATURE_VALUE_ONE = "feature_value_one"; - public static final String FEATURE_VALUE_TWO = "feature_value_two"; - public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; - public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two"; - public static final String DESCRIPTION_ONE = "description_1"; - public static final String DESCRIPTION_TWO = "description_2"; - public static final String SEARCH_AFTER = "search_after_id"; - public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; - public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; - public static final String FEATURE_TYPE_NAME = "mock_feature_type"; - public static final String TEST_INDEX_NAME = ".test_index_for_rule"; - public static final Map> ATTRIBUTE_MAP = Map.of( - MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, - Set.of(ATTRIBUTE_VALUE_ONE) - ); - public static final Rule ruleOne = Rule.builder() - .description(DESCRIPTION_ONE) - .featureType(MockRuleFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_ONE) - .attributeMap(ATTRIBUTE_MAP) - .updatedAt(TIMESTAMP_ONE) - .build(); - - public static final Rule ruleTwo = Rule.builder() - .description(DESCRIPTION_TWO) - .featureType(MockRuleFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_TWO) - .attributeMap(Map.of(MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, Set.of(ATTRIBUTE_VALUE_TWO))) - .updatedAt(TIMESTAMP_TWO) - .build(); - - public static Map ruleMap() { - return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); - } - - public static IndexStoredRulePersistenceService setUpIndexStoredRulePersistenceService(Map queryGroupMap) { - Client client = mock(Client.class); - ClusterService clusterService = mock(ClusterService.class); - ClusterState clusterState = mock(ClusterState.class); - Metadata metadata = mock(Metadata.class); - ThreadPool threadPool = mock(ThreadPool.class); - - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - when(client.threadPool()).thenReturn(threadPool); - when(threadPool.getThreadContext()).thenReturn(threadContext); - when(clusterService.state()).thenReturn(clusterState); - when(clusterState.metadata()).thenReturn(metadata); - when(metadata.queryGroups()).thenReturn(queryGroupMap); - return new IndexStoredRulePersistenceService(TEST_INDEX_NAME, clusterService, client, MockRuleFeatureType.INSTANCE, 50); - } - - public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { - assertEquals(mapOne.size(), mapTwo.size()); - for (Map.Entry entry : mapOne.entrySet()) { - String id = entry.getKey(); - assertTrue(mapTwo.containsKey(id)); - Rule one = mapOne.get(id); - Rule two = mapTwo.get(id); - assertEqualRule(one, two, ruleUpdated); - } - } - - public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { - if (ruleUpdated) { - assertEquals(one.getDescription(), two.getDescription()); - assertEquals(one.getFeatureType(), two.getFeatureType()); - assertEquals(one.getFeatureValue(), two.getFeatureValue()); - assertEquals(one.getAttributeMap(), two.getAttributeMap()); - assertEquals(one.getAttributeMap(), two.getAttributeMap()); - } else { - assertEquals(one, two); - } - } - - public static class MockRuleFeatureType implements FeatureType { - - public static final MockRuleFeatureType INSTANCE = new MockRuleFeatureType(); - - private MockRuleFeatureType() {} - - static { - INSTANCE.registerFeatureType(); - } - - @Override - public String getName() { - return FEATURE_TYPE_NAME; - } - - @Override - public Map getAllowedAttributesRegistry() { - return Map.of( - ATTRIBUTE_VALUE_ONE, - MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, - ATTRIBUTE_VALUE_TWO, - MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO - ); - } - - @Override - public void registerFeatureType() { - AutoTaggingRegistry.registerFeatureType(INSTANCE); - } - } - - public enum MockRuleAttributes implements Attribute { - MOCK_RULE_ATTRIBUTE_ONE(ATTRIBUTE_VALUE_ONE), - MOCK_RULE_ATTRIBUTE_TWO(ATTRIBUTE_VALUE_TWO); - ; - - private final String name; - - MockRuleAttributes(String name) { - this.name = name; - } - - @Override - public String getName() { - return name; - } - } -} diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DuplicateRuleChecker.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DuplicateRuleChecker.java new file mode 100644 index 0000000000000..a852dcc3d4f21 --- /dev/null +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DuplicateRuleChecker.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.rule.autotagging.Rule; + +import java.util.Map; +import java.util.Optional; + +/** + * Interface to check for rule duplication. + */ +@ExperimentalApi +public interface DuplicateRuleChecker { + /** + * Checks if the given rule already exists in the provided rule map. + * @param rule the rule to check for duplication + * @param ruleMap a map of existing rules, keyed by rule ID + */ + Optional getDuplicateRuleId(Rule rule, Map ruleMap); +} diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java index b29323da421e7..d956a1e9602dd 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java @@ -37,4 +37,11 @@ public interface RulePersistenceService { * @param listener The listener that will handle the response or failure. */ void deleteRule(DeleteRuleRequest request, ActionListener listener); + + /** + * Update rule based on the provided request. + * @param request The request containing the details for updating the rule. + * @param listener The listener that will handle the response or failure. + */ + void updateRule(UpdateRuleRequest request, ActionListener listener); } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java index 7c66eac988f9b..d3711b9b6fbd5 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java @@ -15,6 +15,11 @@ import java.util.Collections; import java.util.Map; import java.util.Optional; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.Rule; + +import java.time.Instant; +import java.util.Map; import java.util.Set; /** @@ -64,4 +69,24 @@ public static Optional getDuplicateRuleId(Rule rule, Map r } return Optional.empty(); } + + /** + * Creates an updated {@link Rule} object by applying non-null fields from the given {@link UpdateRuleRequest} + * to the original rule. Fields not provided in the request will retain their values from the original rule. + * @param originalRule the original rule to update + * @param request the request containing the new values for the rule + * @param featureType the feature type to assign to the updated rule + */ + public static Rule composeUpdatedRule(Rule originalRule, UpdateRuleRequest request, FeatureType featureType) { + String requestDescription = request.getDescription(); + Map> requestMap = request.getAttributeMap(); + String requestLabel = request.getFeatureValue(); + return new Rule( + requestDescription == null ? originalRule.getDescription() : requestDescription, + requestMap == null || requestMap.isEmpty() ? originalRule.getAttributeMap() : requestMap, + featureType, + requestLabel == null ? originalRule.getFeatureValue() : requestLabel, + Instant.now().toString() + ); + } } diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java similarity index 88% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java index 36db5213dfec0..8172687586090 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java @@ -6,16 +6,16 @@ * compatible open source license. */ -package org.opensearch.rule.action; +package org.opensearch.rule; import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.RuleValidator; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.RuleValidator; import java.io.IOException; import java.util.HashSet; @@ -26,12 +26,11 @@ /** * A request for update Rule * Example request: - * Note that the endpoint "localhost:9200/_wlm/rule" serves only as an example endpoint here - * curl -XPUT "localhost:9200/_wlm/rule/{rule_id}" -H 'Content-Type: application/json' -d ' + * curl -XPUT "localhost:9200/_rules/{featureType}/{_id}" -H 'Content-Type: application/json' -d ' * { * "description": "description", * "index_pattern": ["log*", "event*"], - * "query_group": "dev_query_group_id_2" + * "workload_group": "dev_workload_group_id_2" * }' * @opensearch.experimental */ @@ -121,6 +120,13 @@ public Map> getAttributeMap() { return attributeMap; } + /** + * featureType getter + */ + public FeatureType getFeatureType() { + return featureType; + } + /** * featureValue getter */ diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java similarity index 89% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java index 163618b36d014..e867e25ce13ab 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java @@ -6,9 +6,8 @@ * compatible open source license. */ -package org.opensearch.rule.action; +package org.opensearch.rule; -import org.opensearch.autotagging.Rule; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.StreamInput; @@ -16,20 +15,21 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.rule.autotagging.Rule; import java.io.IOException; import java.util.Map; -import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.autotagging.Rule._ID_STRING; /** * Response for the update API for Rule * Example response: * { * _id": "z1MJApUB0zgMcDmz-UQq", - * "description": "Rule for tagging query_group_id to index123" + * "description": "Rule for tagging workload_group_id to index123" * "index_pattern": ["index123"], - * "query_group": "query_group_id", + * "workload_group": "workload_group_id", * "updated_at": "2025-02-14T01:19:22.589Z" * } * @opensearch.experimental diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java index 17e789c58a7f7..79c8782202cf8 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java @@ -369,6 +369,10 @@ public Map> getAttributeMap() { return attributeMap; } + /** + * Returns description + * @return + */ public String getDescription() { return description; } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java index f1472b78441cc..e7d0f817b4b17 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java @@ -74,16 +74,27 @@ public void validate() { } } + /** + * validates the updated rule object fields + */ public List validateUpdatingRuleParams() { List errorMessages = new ArrayList<>(); - if (isInvalidUpdatedValue(description)) { + if (isEmpty(description)) { errorMessages.add("Rule description can't be empty"); } - if (isInvalidUpdatedValue(featureValue)) { + if (isEmpty(featureValue)) { errorMessages.add("Rule featureValue can't be empty"); } + FeatureValueValidator featureValueValidator = featureType.getFeatureValueValidator(); + if (featureValue != null && !featureValue.isEmpty() && featureValueValidator != null) { + try { + featureValueValidator.validate(featureValue); + } catch (Exception e) { + errorMessages.add(e.getMessage()); + } + } if (attributeMap != null && !attributeMap.isEmpty()) { - validateAttributeMap(); + errorMessages.addAll(validateAttributeMap()); } return errorMessages; } @@ -108,7 +119,12 @@ private boolean isNullOrEmpty(String str) { return str == null || str.isEmpty(); } - private boolean isInvalidUpdatedValue(String str) { + /** + * Utility method which checks the empty string in context of Rule + * @param str + * @return + */ + public static boolean isEmpty(String str) { return str != null && str.isEmpty(); } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index b0d31a829b2b6..813e9c22c9aab 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -18,6 +18,7 @@ import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; +import org.opensearch.action.update.UpdateRequest; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.xcontent.XContentFactory; @@ -28,18 +29,26 @@ import org.opensearch.rule.CreateRuleRequest; import org.opensearch.rule.CreateRuleResponse; import org.opensearch.rule.DeleteRuleRequest; + +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.DuplicateRuleChecker; import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; import org.opensearch.rule.RuleUtils; +import org.opensearch.rule.UpdateRuleRequest; +import org.opensearch.rule.UpdateRuleResponse; +import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule; import org.opensearch.search.SearchHit; import org.opensearch.search.sort.SortOrder; import org.opensearch.transport.client.Client; +import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -62,6 +71,7 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService private final RuleEntityParser parser; private final RuleQueryMapper queryBuilder; private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); + private static final Map indexSettings = Map.of("index.number_of_shards", 1, "index.auto_expand_replicas", "0-all"); /** * Constructs an instance of {@link IndexStoredRulePersistenceService} with the specified parameters. @@ -228,6 +238,38 @@ public void deleteRule(DeleteRuleRequest request, ActionListener listener) { + String ruleId = request.get_id(); + FeatureType featureType = request.getFeatureType(); + try (ThreadContext.StoredContext context = stashContext()) { + QueryBuilder query = queryBuilder.from(new GetRuleRequest(ruleId, new HashMap<>(), null, featureType)); + getRuleFromIndex(ruleId, query, null, new ActionListener<>() { + @Override + public void onResponse(GetRuleResponse getRuleResponse) { + if (getRuleResponse == null || getRuleResponse.getRules().isEmpty()) { + listener.onFailure(new ResourceNotFoundException("Rule with ID " + ruleId + " not found.")); + return; + } + Rule updatedRule = RuleUtils.composeUpdatedRule(getRuleResponse.getRules().get(ruleId), request, featureType); + validateNoDuplicateRule( + updatedRule, + ActionListener.wrap(unused -> persistUpdatedRule(ruleId, updatedRule, listener), listener::onFailure) + ); + } + + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + } + }); + } + } + /** * indexName getter */ @@ -235,6 +277,30 @@ public String getIndexName() { return indexName; } + /** + * Persist the updated rule in index + * @param ruleId - the rule id to update + * @param updatedRule - the rule we update to + * @param listener - ActionListener for UpdateRuleResponse + */ + private void persistUpdatedRule(String ruleId, Rule updatedRule, ActionListener listener) { + try (ThreadContext.StoredContext context = stashContext()) { + UpdateRequest updateRequest = new UpdateRequest(indexName, ruleId).doc( + updatedRule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) + ); + client.update( + updateRequest, + ActionListener.wrap(updateResponse -> { listener.onResponse(new UpdateRuleResponse(ruleId, updatedRule)); }, e -> { + logger.error("Failed to update Rule object due to error: {}", e.getMessage()); + listener.onFailure(e); + }) + ); + } catch (IOException e) { + logger.error("Error updating rule in index: {}", indexName); + listener.onFailure(new RuntimeException("Failed to update rule to index.")); + } + } + private ThreadContext.StoredContext stashContext() { return client.threadPool().getThreadContext().stashContext(); } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedDuplicateRuleChecker.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedDuplicateRuleChecker.java new file mode 100644 index 0000000000000..7eb5457eab8fe --- /dev/null +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedDuplicateRuleChecker.java @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.storage; + +import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.rule.DuplicateRuleChecker; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.Rule; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * This class is used to check rule duplication for indexed based rules. + */ +@ExperimentalApi +public class IndexBasedDuplicateRuleChecker implements DuplicateRuleChecker { + + /** + * Default constructor + */ + public IndexBasedDuplicateRuleChecker() {} + + /** + * Checks if a duplicate rule exists based on the attribute map. + * A rule is considered a duplicate when the attribute value already exists in the index, and the number of + * attributes in the new rule is equal to the number of attributes in an existing rule. + * + * For example, if an existing rule has: + * attribute1 = ['a'] and attribute2 = ['c'] + * And we are creating a new rule with: + * attribute1 = ['a'] + * Then it's not a duplicate because the existing rule has attribute2 and is more granular + * + * @param rule The rule to be validated against ruleMap. + * @param ruleMap This map entries are Rules that contain the attribute values from rule, meaning they + * have a partial or complete overlap with the new rule being created. + */ + @Override + public Optional getDuplicateRuleId(Rule rule, Map ruleMap) { + Map> attributeMapToValidate = rule.getAttributeMap(); + for (Map.Entry entry : ruleMap.entrySet()) { + String ruleId = entry.getKey(); + Rule currRule = entry.getValue(); + // Compare the size of the attribute maps to ensure we only check for duplicates with the same number of attributes. + if (attributeMapToValidate.size() == currRule.getAttributeMap().size()) { + return Optional.of(ruleId); + } + } + return Optional.empty(); + } +} diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java index cd6197cf890f7..ddccbf2d308e7 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/RuleFrameworkPlugin.java @@ -28,11 +28,14 @@ import org.opensearch.rule.action.TransportCreateRuleAction; import org.opensearch.rule.action.TransportDeleteRuleAction; import org.opensearch.rule.action.TransportGetRuleAction; +import org.opensearch.rule.action.TransportUpdateRuleAction; +import org.opensearch.rule.action.UpdateRuleAction; import org.opensearch.rule.autotagging.AutoTaggingRegistry; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.rest.RestCreateRuleAction; import org.opensearch.rule.rest.RestDeleteRuleAction; import org.opensearch.rule.rest.RestGetRuleAction; +import org.opensearch.rule.rest.RestUpdateRuleAction; import org.opensearch.rule.spi.RuleFrameworkExtension; import org.opensearch.threadpool.ExecutorBuilder; import org.opensearch.threadpool.FixedExecutorBuilder; @@ -78,7 +81,8 @@ public RuleFrameworkPlugin() {} return List.of( new ActionPlugin.ActionHandler<>(GetRuleAction.INSTANCE, TransportGetRuleAction.class), new ActionPlugin.ActionHandler<>(DeleteRuleAction.INSTANCE, TransportDeleteRuleAction.class), - new ActionPlugin.ActionHandler<>(CreateRuleAction.INSTANCE, TransportCreateRuleAction.class) + new ActionPlugin.ActionHandler<>(CreateRuleAction.INSTANCE, TransportCreateRuleAction.class), + new ActionPlugin.ActionHandler<>(UpdateRuleAction.INSTANCE, TransportUpdateRuleAction.class) ); } @@ -92,7 +96,7 @@ public List getRestHandlers( IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster ) { - return List.of(new RestGetRuleAction(), new RestDeleteRuleAction(), new RestCreateRuleAction()); + return List.of(new RestGetRuleAction(), new RestDeleteRuleAction(), new RestCreateRuleAction(), new RestUpdateRuleAction()); } @Override diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java index 94321e5d40713..7a7d7258af216 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java @@ -28,7 +28,7 @@ public class TransportGetRuleAction extends HandledTransportAction { + + private final RulePersistenceServiceRegistry rulePersistenceServiceRegistry; + + /** + * Constructor for TransportUpdateRuleAction + * @param transportService - a {@link TransportService} object + * @param actionFilters - a {@link ActionFilters} object + * @param rulePersistenceServiceRegistry - a {@link RulePersistenceServiceRegistry} object + */ + @Inject + public TransportUpdateRuleAction( + TransportService transportService, + ActionFilters actionFilters, + RulePersistenceServiceRegistry rulePersistenceServiceRegistry + ) { + super(UpdateRuleAction.NAME, transportService, actionFilters, UpdateRuleRequest::new); + this.rulePersistenceServiceRegistry = rulePersistenceServiceRegistry; + } + + @Override + protected void doExecute(Task task, UpdateRuleRequest request, ActionListener listener) { + final RulePersistenceService rulePersistenceService = rulePersistenceServiceRegistry.getRulePersistenceService( + request.getFeatureType() + ); + rulePersistenceService.updateRule(request, listener); + } +} diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleAction.java new file mode 100644 index 0000000000000..5888e4e96b06f --- /dev/null +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleAction.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.rule.action; + +import org.opensearch.action.ActionType; +import org.opensearch.rule.UpdateRuleResponse; + +/** + * Action type for updating Rules + * @opensearch.experimental + */ +public class UpdateRuleAction extends ActionType { + + /** + * An instance of UpdateRuleAction + */ + public static final UpdateRuleAction INSTANCE = new UpdateRuleAction(); + + /** + * Name for UpdateRuleAction + */ + public static final String NAME = "cluster:admin/opensearch/rule/_update"; + + /** + * Default constructor for UpdateRuleAction + */ + private UpdateRuleAction() { + super(NAME, UpdateRuleResponse::new); + } +} diff --git a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java similarity index 64% rename from libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java rename to modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java index c68dd43105409..c33430fa98a0a 100644 --- a/libs/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java @@ -8,9 +8,6 @@ package org.opensearch.rule.rest; -import org.opensearch.action.ActionType; -import org.opensearch.autotagging.FeatureType; -import org.opensearch.autotagging.Rule.Builder; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.rest.RestStatus; import org.opensearch.core.xcontent.ToXContent; @@ -18,17 +15,24 @@ import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestHandler; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.rule.action.UpdateRuleRequest; -import org.opensearch.rule.action.UpdateRuleResponse; +import org.opensearch.rule.UpdateRuleRequest; +import org.opensearch.rule.UpdateRuleResponse; +import org.opensearch.rule.action.UpdateRuleAction; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.Rule.Builder; import org.opensearch.transport.client.node.NodeClient; import java.io.IOException; import java.util.List; -import static org.opensearch.autotagging.Rule._ID_STRING; +import static org.opensearch.rest.RestRequest.Method.POST; +import static org.opensearch.rest.RestRequest.Method.PUT; +import static org.opensearch.rule.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.rest.RestGetRuleAction.FEATURE_TYPE; /** * Rest action to update a Rule @@ -36,37 +40,24 @@ */ @ExperimentalApi public class RestUpdateRuleAction extends BaseRestHandler { - private final String name; - private final List routes; - private final FeatureType featureType; - private final ActionType updateRuleAction; - /** * constructor for RestUpdateRuleAction - * @param name - RestUpdateRuleAction name - * @param routes the list of REST routes this action handles - * @param featureType the feature type associated with the rule - * @param updateRuleAction the action to execute for updating a rule */ - public RestUpdateRuleAction(String name, List routes, FeatureType featureType, ActionType updateRuleAction) { - this.name = name; - this.routes = routes; - this.featureType = featureType; - this.updateRuleAction = updateRuleAction; - } + public RestUpdateRuleAction() {} @Override public String getName() { - return name; + return "update_rule"; } @Override public List routes() { - return routes; + return List.of(new RestHandler.Route(PUT, "_rules/{featureType}/{_id}"), new RestHandler.Route(POST, "_rules/{featureType}/{_id}")); } @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + final FeatureType featureType = FeatureType.from(request.param(FEATURE_TYPE)); try (XContentParser parser = request.contentParser()) { Builder builder = Builder.fromXContent(parser, featureType); UpdateRuleRequest updateRuleRequest = new UpdateRuleRequest( @@ -76,7 +67,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli builder.getFeatureValue(), featureType ); - return channel -> client.execute(updateRuleAction, updateRuleRequest, updateRuleResponse(channel)); + return channel -> client.execute(UpdateRuleAction.INSTANCE, updateRuleRequest, updateRuleResponse(channel)); } } diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java index 67e015ad01254..21882753210c6 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java @@ -12,6 +12,7 @@ import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.AutoTaggingRegistry; import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.FeatureValueValidator; import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.storage.AttributeValueStoreFactory; import org.opensearch.rule.storage.DefaultAttributeValueStore; 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 369397cc1ae43..27ccad1cf5f36 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 @@ -61,6 +61,7 @@ import org.opensearch.rule.spi.RuleFrameworkExtension; import org.opensearch.rule.storage.AttributeValueStoreFactory; import org.opensearch.rule.storage.DefaultAttributeValueStore; +import org.opensearch.rule.storage.IndexBasedDuplicateRuleChecker; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.storage.XContentRuleParser; import org.opensearch.script.ScriptService; 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 2008c3217a85d..bb0f4c7e90122 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPluginModule.java @@ -11,8 +11,6 @@ import org.opensearch.common.inject.AbstractModule; import org.opensearch.common.inject.Singleton; import org.opensearch.plugin.wlm.service.WorkloadGroupPersistenceService; -import org.opensearch.rule.service.IndexStoredRulePersistenceService; -import org.opensearch.rule.service.RulePersistenceService; /** * Guice Module to manage WorkloadManagement related objects @@ -29,6 +27,5 @@ protected void configure() { // Bind WorkloadGroupPersistenceService as a singleton to ensure a single instance is used, // preventing multiple throttling key registrations in the constructor. bind(WorkloadGroupPersistenceService.class).in(Singleton.class); - bind(RulePersistenceService.class).to(IndexStoredRulePersistenceService.class); } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java deleted file mode 100644 index 5357a344da407..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupAttribute.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule; - -import org.opensearch.autotagging.Attribute; - -import java.util.HashMap; -import java.util.Map; - -/** - * Attributes specific to the query group feature. - * @opensearch.experimental - */ -public enum QueryGroupAttribute implements Attribute { - /** - * Represents the index_pattern attribute in QueryGroupAttribute - */ - INDEX_PATTERN("index_pattern"); - - private final String name; - - QueryGroupAttribute(String name) { - this.name = name; - validateAttribute(); - } - - @Override - public String getName() { - return name; - } - - /** - * Retrieves the QueryGroupAttribute from a name string - * @param name - attribute name - */ - public static QueryGroupAttribute fromName(String name) { - for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { - if (attr.getName().equals(name)) { - return attr; - } - } - throw new IllegalArgumentException("Unknown QueryGroupAttribute: " + name); - } - - /** - * Converts the QueryGroupAttribute values into a map with attribute names as keys. - */ - public static Map toMap() { - Map map = new HashMap<>(); - for (QueryGroupAttribute attr : QueryGroupAttribute.values()) { - map.put(attr.getName(), attr); - } - return map; - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java deleted file mode 100644 index 42f45d3d7c5d6..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/QueryGroupFeatureType.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule; - -import org.opensearch.autotagging.Attribute; -import org.opensearch.autotagging.AutoTaggingRegistry; -import org.opensearch.autotagging.FeatureType; - -import java.util.Map; - -/** - * Represents a feature type specific to the query group feature - * @opensearch.experimental - */ -public class QueryGroupFeatureType implements FeatureType { - /** - * The instance for QueryGroupFeatureType - */ - public static final QueryGroupFeatureType INSTANCE = new QueryGroupFeatureType(); - /** - * Name for QueryGroupFeatureType - */ - public static final String NAME = "query_group"; - private static final int MAX_ATTRIBUTE_VALUES = 10; - private static final int MAX_ATTRIBUTE_VALUE_LENGTH = 100; - private static final Map ALLOWED_ATTRIBUTES = QueryGroupAttribute.toMap(); - - private QueryGroupFeatureType() {} - - static { - INSTANCE.registerFeatureType(); - } - - @Override - public String getName() { - return NAME; - } - - @Override - public int getMaxNumberOfValuesPerAttribute() { - return MAX_ATTRIBUTE_VALUES; - } - - @Override - public int getMaxCharLengthPerAttributeValue() { - return MAX_ATTRIBUTE_VALUE_LENGTH; - } - - @Override - public Map getAllowedAttributesRegistry() { - return ALLOWED_ATTRIBUTES; - } - - @Override - public void registerFeatureType() { - AutoTaggingRegistry.registerFeatureType(INSTANCE); - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java deleted file mode 100644 index 10df593f7bb81..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/TransportUpdateWlmRuleAction.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.action; - -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.support.ActionFilters; -import org.opensearch.action.support.HandledTransportAction; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.inject.Inject; -import org.opensearch.core.action.ActionListener; -import org.opensearch.rule.action.UpdateRuleRequest; -import org.opensearch.rule.action.UpdateRuleResponse; -import org.opensearch.rule.service.RulePersistenceService; -import org.opensearch.tasks.Task; -import org.opensearch.transport.TransportService; - -/** - * Transport action to update Rule in workload management - * @opensearch.experimental - */ -public class TransportUpdateWlmRuleAction extends HandledTransportAction { - - private final ClusterService clusterService; - private final RulePersistenceService rulePersistenceService; - - /** - * Constructor for TransportUpdateWlmRuleAction - * - * @param transportService - a {@link TransportService} object - * @param actionFilters - a {@link ActionFilters} object - * @param clusterService - a {@link ClusterService} object} - * @param rulePersistenceService - a {@link RulePersistenceService} object - */ - @Inject - public TransportUpdateWlmRuleAction( - TransportService transportService, - ActionFilters actionFilters, - ClusterService clusterService, - RulePersistenceService rulePersistenceService - ) { - super(UpdateWlmRuleAction.NAME, transportService, actionFilters, UpdateRuleRequest::new); - this.clusterService = clusterService; - this.rulePersistenceService = rulePersistenceService; - } - - @Override - protected void doExecute(Task task, UpdateRuleRequest request, ActionListener listener) { - String queryGroupId = request.getFeatureValue(); - if (queryGroupId != null && !clusterService.state().metadata().queryGroups().containsKey(queryGroupId)) { - listener.onFailure(new ResourceNotFoundException("Couldn't find an existing query group with id: " + queryGroupId)); - return; - } - rulePersistenceService.updateRule(request, listener); - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/UpdateWlmRuleAction.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/UpdateWlmRuleAction.java deleted file mode 100644 index a7182f20f9fb5..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/UpdateWlmRuleAction.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugin.wlm.rule.action; - -import org.opensearch.action.ActionType; -import org.opensearch.rule.action.UpdateRuleResponse; - -/** - * Action type for updating a Rule in workload management - * - * @opensearch.experimental - */ -public class UpdateWlmRuleAction extends ActionType { - - /** - * An instance of UpdateWlmRuleAction - */ - public static final UpdateWlmRuleAction INSTANCE = new UpdateWlmRuleAction(); - - /** - * Name for UpdateWlmRuleAction - */ - public static final String NAME = "cluster:admin/opensearch/wlm/rule/_update"; - - /** - * Default constructor - */ - private UpdateWlmRuleAction() { - super(NAME, UpdateRuleResponse::new); - } -} diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java deleted file mode 100644 index b9fb278dae5b0..0000000000000 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/action/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/** - * Package for the action classes related to rules in WorkloadManagementPlugin - */ -package org.opensearch.plugin.wlm.rule.action; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java index c8669fbc8c8f4..31d3ea00b7bda 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/CreateWorkloadGroupRequestTests.java @@ -11,7 +11,6 @@ import org.opensearch.cluster.metadata.WorkloadGroup; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.plugin.wlm.action.CreateWorkloadGroupRequest; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java index 6c6ef9072355a..cf12d9f6408cf 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/TransportGetWorkloadGroupActionTests.java @@ -13,8 +13,6 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.action.ActionListener; -import org.opensearch.plugin.wlm.action.GetWorkloadGroupRequest; -import org.opensearch.plugin.wlm.action.TransportGetWorkloadGroupAction; 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/UpdateWorkloadGroupResponseTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java index 3e515d19197b7..97b9b9029373f 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/action/UpdateWorkloadGroupResponseTests.java @@ -16,7 +16,6 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.plugin.wlm.WorkloadGroupTestUtils; -import org.opensearch.plugin.wlm.action.UpdateWorkloadGroupResponse; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; From 9cbd5d76f444ee95100ae23e5b8ea44db2f0ea13 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Wed, 30 Apr 2025 01:47:15 -0700 Subject: [PATCH 07/11] modify based on comments Signed-off-by: Ruirui Zhang --- CHANGELOG.md | 1 + ...RuleUtils.java => UpdatedRuleBuilder.java} | 21 ++++-- .../IndexStoredRulePersistenceService.java | 4 +- .../rule/action/UpdateRuleRequestTests.java | 73 +++++++++++++++++++ .../rule/action/UpdateRuleResponseTests.java | 62 ++++++++++++++++ 5 files changed, 151 insertions(+), 10 deletions(-) rename modules/autotagging-commons/common/src/main/java/org/opensearch/rule/{RuleUtils.java => UpdatedRuleBuilder.java} (86%) create mode 100644 modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java create mode 100644 modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 273c4c3164b71..6b472e38ac6e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Implement parallel shard refresh behind cluster settings ([#17782](https://github.com/opensearch-project/OpenSearch/pull/17782)) - Bump OpenSearch Core main branch to 3.0.0 ([#18039](https://github.com/opensearch-project/OpenSearch/pull/18039)) - [Rule based Auto-tagging] Add wlm `ActionFilter` ([#17791](https://github.com/opensearch-project/OpenSearch/pull/17791)) +- [Rule based auto-tagging] Add update rule API ([#17797](https://github.com/opensearch-project/OpenSearch/pull/17797)) - Update API of Message in index to add the timestamp for lag calculation in ingestion polling ([#17977](https://github.com/opensearch-project/OpenSearch/pull/17977/)) - Add Warm Disk Threshold Allocation Decider for Warm shards ([#18082](https://github.com/opensearch-project/OpenSearch/pull/18082)) - Add composite directory factory ([#17988](https://github.com/opensearch-project/OpenSearch/pull/17988)) diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java similarity index 86% rename from modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java index d3711b9b6fbd5..a5a014cdd127c 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java @@ -27,12 +27,20 @@ * @opensearch.experimental */ @ExperimentalApi -public class RuleUtils { +public class UpdatedRuleBuilder { + + private final Rule originalRule; + private final UpdateRuleRequest request; /** - * constructor for RuleUtils + * constructor for UpdatedRuleBuilder + * @param originalRule - the existing rule to update + * @param updateRuleRequest - the update request containing updating details */ - public RuleUtils() {} + public UpdatedRuleBuilder(Rule originalRule, UpdateRuleRequest updateRuleRequest) { + this.originalRule = originalRule; + this.request = updateRuleRequest; + } /** * Checks if a duplicate rule exists and returns its id. @@ -73,18 +81,15 @@ public static Optional getDuplicateRuleId(Rule rule, Map r /** * Creates an updated {@link Rule} object by applying non-null fields from the given {@link UpdateRuleRequest} * to the original rule. Fields not provided in the request will retain their values from the original rule. - * @param originalRule the original rule to update - * @param request the request containing the new values for the rule - * @param featureType the feature type to assign to the updated rule */ - public static Rule composeUpdatedRule(Rule originalRule, UpdateRuleRequest request, FeatureType featureType) { + public Rule build() { String requestDescription = request.getDescription(); Map> requestMap = request.getAttributeMap(); String requestLabel = request.getFeatureValue(); return new Rule( requestDescription == null ? originalRule.getDescription() : requestDescription, requestMap == null || requestMap.isEmpty() ? originalRule.getAttributeMap() : requestMap, - featureType, + originalRule.getFeatureType(), requestLabel == null ? originalRule.getFeatureValue() : requestLabel, Instant.now().toString() ); diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index 813e9c22c9aab..ce7679cde29f0 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -37,7 +37,7 @@ import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; -import org.opensearch.rule.RuleUtils; +import org.opensearch.rule.UpdatedRuleBuilder; import org.opensearch.rule.UpdateRuleRequest; import org.opensearch.rule.UpdateRuleResponse; import org.opensearch.rule.autotagging.FeatureType; @@ -255,7 +255,7 @@ public void onResponse(GetRuleResponse getRuleResponse) { listener.onFailure(new ResourceNotFoundException("Rule with ID " + ruleId + " not found.")); return; } - Rule updatedRule = RuleUtils.composeUpdatedRule(getRuleResponse.getRules().get(ruleId), request, featureType); + Rule updatedRule = new UpdatedRuleBuilder(getRuleResponse.getRules().get(ruleId), request).build(); validateNoDuplicateRule( updatedRule, ActionListener.wrap(unused -> persistUpdatedRule(ruleId, updatedRule, listener), listener::onFailure) diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java new file mode 100644 index 0000000000000..5cb9e9f059cf6 --- /dev/null +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java @@ -0,0 +1,73 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.action; + +import org.opensearch.common.io.stream.BytesStreamOutput; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.rule.GetRuleRequest; +import org.opensearch.rule.UpdateRuleRequest; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.Rule; +import org.opensearch.rule.utils.RuleTestUtils; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.rule.action.GetRuleRequestTests._ID_ONE; +import static org.opensearch.rule.action.GetRuleRequestTests.ATTRIBUTE_MAP; +import static org.opensearch.rule.action.GetRuleRequestTests.FEATURE_VALUE_ONE; +import static org.opensearch.rule.action.GetRuleRequestTests.DESCRIPTION_ONE; +import static org.opensearch.rule.action.GetRuleRequestTests.DESCRIPTION_TWO; + +public class UpdateRuleRequestTests extends OpenSearchTestCase { + /** + * Test case to verify the serialization and deserialization of UpdateRuleRequest + */ + public void testSerialization() throws IOException { + UpdateRuleRequest request = new UpdateRuleRequest(_ID_ONE, DESCRIPTION_TWO, ATTRIBUTE_MAP, FEATURE_VALUE_ONE, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertEquals(_ID_ONE, request.get_id()); + assertNull(request.validate()); + assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, request.getFeatureType()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateRuleRequest otherRequest = new UpdateRuleRequest(streamInput); + assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getAttributeMap(), otherRequest.getAttributeMap()); + assertEquals(request.getDescription(), otherRequest.getDescription()); + assertEquals(request.getFeatureValue(), otherRequest.getFeatureValue()); + } + + /** + * Test case to verify the serialization and deserialization of UpdateRuleRequest when some fields are null + */ + public void testSerializationWithNull() throws IOException { + UpdateRuleRequest request = new UpdateRuleRequest(_ID_ONE, null, ATTRIBUTE_MAP, null, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertNull(request.getDescription()); + assertNull(request.getFeatureValue()); + BytesStreamOutput out = new BytesStreamOutput(); + request.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateRuleRequest otherRequest = new UpdateRuleRequest(streamInput); + assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getAttributeMap(), otherRequest.getAttributeMap()); + assertEquals(request.getDescription(), otherRequest.getDescription()); + assertEquals(request.getFeatureValue(), otherRequest.getFeatureValue()); + } + + public void testValidate() { + UpdateRuleRequest request = new UpdateRuleRequest(_ID_ONE, "", ATTRIBUTE_MAP, FEATURE_VALUE_ONE, RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertNotNull(request.validate()); + request = new UpdateRuleRequest(_ID_ONE, DESCRIPTION_ONE, ATTRIBUTE_MAP, "", RuleTestUtils.MockRuleFeatureType.INSTANCE); + assertNotNull(request.validate()); + } +} diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java new file mode 100644 index 0000000000000..75cc323495490 --- /dev/null +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.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.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.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.rule.GetRuleResponse; +import org.opensearch.rule.UpdateRuleResponse; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.Rule; +import org.opensearch.rule.utils.RuleTestUtils; +import org.opensearch.test.OpenSearchTestCase; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.mockito.Mockito.mock; +import static org.opensearch.rule.action.GetRuleRequestTests.*; + +public class UpdateRuleResponseTests extends OpenSearchTestCase { + /** + * Test case to verify the serialization and deserialization of UpdateRuleResponse + */ + public void testSerialization() throws IOException { + UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); + BytesStreamOutput out = new BytesStreamOutput(); + response.writeTo(out); + StreamInput streamInput = out.bytes().streamInput(); + UpdateRuleResponse otherResponse = new UpdateRuleResponse(streamInput); + assertEqualRule(response.getRule(), otherResponse.getRule(), false); + } + + /** + * Test case to verify the toXContent of GetRuleResponse + */ + public void testToXContent() throws IOException { + UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); + XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); + String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); + String expected = "{\n" + + " \"_id\" : \"id_1\",\n" + + " \"description\" : \"description_1\",\n" + + " \"mock_attribute_one\" : [\n" + + " \"mock_attribute_one\"\n" + + " ],\n" + + " \"mock_feature_type\" : \"feature_value_one\",\n" + + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + + "}"; + assertEquals(expected, actual); + } +} From 30fec41987f309da8fa72a660fb3b12cc97353c9 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Fri, 2 May 2025 02:19:47 -0700 Subject: [PATCH 08/11] change the structure to update a rule to make testing easier Signed-off-by: Ruirui Zhang --- .../opensearch/rule/DuplicateRuleChecker.java | 28 -- .../java/org/opensearch/rule/RuleUtils.java | 89 +++++ .../opensearch/rule/UpdatedRuleBuilder.java | 26 +- .../IndexStoredRulePersistenceService.java | 13 +- .../IndexBasedDuplicateRuleChecker.java | 59 ---- .../rule/action/UpdateRuleRequestTests.java | 26 +- .../rule/action/UpdateRuleResponseTests.java | 29 +- ...ndexStoredRulePersistenceServiceTests.java | 312 ++++-------------- .../plugin/wlm/WorkloadManagementPlugin.java | 9 +- 9 files changed, 207 insertions(+), 384 deletions(-) delete mode 100644 modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DuplicateRuleChecker.java create mode 100644 modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java delete mode 100644 modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedDuplicateRuleChecker.java diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DuplicateRuleChecker.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DuplicateRuleChecker.java deleted file mode 100644 index a852dcc3d4f21..0000000000000 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DuplicateRuleChecker.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule; - -import org.opensearch.common.annotation.ExperimentalApi; -import org.opensearch.rule.autotagging.Rule; - -import java.util.Map; -import java.util.Optional; - -/** - * Interface to check for rule duplication. - */ -@ExperimentalApi -public interface DuplicateRuleChecker { - /** - * Checks if the given rule already exists in the provided rule map. - * @param rule the rule to check for duplication - * @param ruleMap a map of existing rules, keyed by rule ID - */ - Optional getDuplicateRuleId(Rule rule, Map ruleMap); -} diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java new file mode 100644 index 0000000000000..40f56289df8e5 --- /dev/null +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java @@ -0,0 +1,89 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule; + +import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.Rule; + +import java.time.Instant; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Utility class for operations related to {@link Rule} objects. + * @opensearch.experimental + */ +@ExperimentalApi +public class RuleUtils { + + /** + * constructor for RuleUtils + */ + public RuleUtils() {} + + /** + * Checks if a duplicate rule exists and returns its id. + * Two rules are considered to be duplicate when meeting all the criteria below + * 1. They have the same feature type + * 2. They have the exact same attributes + * 3. For each attribute, the sets of values must intersect — i.e., at least one common value must exist + * between the current rule and the one being checked. + * + * @param rule The rule to be validated against ruleMap. + * @param ruleMap This map contains existing rules to be checked + */ + public static Optional getDuplicateRuleId(Rule rule, Map ruleMap) { + Map> targetAttributeMap = rule.getAttributeMap(); + for (Map.Entry entry : ruleMap.entrySet()) { + Rule currRule = entry.getValue(); + Map> existingAttributeMap = currRule.getAttributeMap(); + + if (rule.getFeatureType() != currRule.getFeatureType() || targetAttributeMap.size() != existingAttributeMap.size()) { + continue; + } + boolean allAttributesIntersect = true; + for (Attribute attribute : targetAttributeMap.keySet()) { + Set targetAttributeValues = targetAttributeMap.get(attribute); + Set existingAttributeValues = existingAttributeMap.get(attribute); + if (existingAttributeValues == null || Collections.disjoint(targetAttributeValues, existingAttributeValues)) { + allAttributesIntersect = false; + break; + } + } + if (allAttributesIntersect) { + return Optional.of(entry.getKey()); + } + } + return Optional.empty(); + } + + /** + * Creates an updated {@link Rule} object by applying non-null fields from the given {@link UpdateRuleRequest} + * to the original rule. Fields not provided in the request will retain their values from the original rule. + * @param originalRule the original rule to update + * @param request the request containing the new values for the rule + * @param featureType the feature type to assign to the updated rule + */ + public static Rule composeUpdatedRule(Rule originalRule, UpdateRuleRequest request, FeatureType featureType) { + String requestDescription = request.getDescription(); + Map> requestMap = request.getAttributeMap(); + String requestLabel = request.getFeatureValue(); + return new Rule( + requestDescription == null ? originalRule.getDescription() : requestDescription, + requestMap == null || requestMap.isEmpty() ? originalRule.getAttributeMap() : requestMap, + featureType, + requestLabel == null ? originalRule.getFeatureValue() : requestLabel, + Instant.now().toString() + ); + } +} diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java index a5a014cdd127c..fd729fa3e05c6 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java @@ -9,6 +9,7 @@ package org.opensearch.rule; import org.opensearch.common.annotation.ExperimentalApi; +<<<<<<< HEAD import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.Rule; @@ -16,27 +17,23 @@ import java.util.Map; import java.util.Optional; import org.opensearch.rule.autotagging.FeatureType; +======= +>>>>>>> 0dfab231d13 (change the structure to update a rule to make testing easier) import org.opensearch.rule.autotagging.Rule; -import java.time.Instant; -import java.util.Map; -import java.util.Set; - /** - * Utility class for operations related to {@link Rule} objects. + * A functional interface for updating an existing {@link Rule} using an {@link UpdateRuleRequest}. * @opensearch.experimental */ @ExperimentalApi -public class UpdatedRuleBuilder { - - private final Rule originalRule; - private final UpdateRuleRequest request; - +@FunctionalInterface +public interface UpdatedRuleBuilder { /** - * constructor for UpdatedRuleBuilder - * @param originalRule - the existing rule to update - * @param updateRuleRequest - the update request containing updating details + * Applies updates to an existing rule based on the provided update request. + * @param existingRule the rule to update + * @param request the update request containing new values */ +<<<<<<< HEAD public UpdatedRuleBuilder(Rule originalRule, UpdateRuleRequest updateRuleRequest) { this.originalRule = originalRule; this.request = updateRuleRequest; @@ -94,4 +91,7 @@ public Rule build() { Instant.now().toString() ); } +======= + Rule apply(Rule existingRule, UpdateRuleRequest request); +>>>>>>> 0dfab231d13 (change the structure to update a rule to make testing easier) } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index ce7679cde29f0..5c09da4d5c276 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -31,15 +31,15 @@ import org.opensearch.rule.DeleteRuleRequest; import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.DuplicateRuleChecker; import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; -import org.opensearch.rule.UpdatedRuleBuilder; +import org.opensearch.rule.RuleUtils; import org.opensearch.rule.UpdateRuleRequest; import org.opensearch.rule.UpdateRuleResponse; +import org.opensearch.rule.UpdatedRuleBuilder; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule; import org.opensearch.search.SearchHit; @@ -70,6 +70,7 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService private final int maxRulesPerPage; private final RuleEntityParser parser; private final RuleQueryMapper queryBuilder; + private final UpdatedRuleBuilder updatedRuleBuilder; private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); private static final Map indexSettings = Map.of("index.number_of_shards", 1, "index.auto_expand_replicas", "0-all"); @@ -82,6 +83,7 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService * @param maxRulesPerPage - The maximum number of rules that can be returned in a single get request. * @param parser * @param queryBuilder + * @param updatedRuleBuilder */ public IndexStoredRulePersistenceService( String indexName, @@ -89,7 +91,8 @@ public IndexStoredRulePersistenceService( ClusterService clusterService, int maxRulesPerPage, RuleEntityParser parser, - RuleQueryMapper queryBuilder + RuleQueryMapper queryBuilder, + UpdatedRuleBuilder updatedRuleBuilder ) { this.indexName = indexName; this.client = client; @@ -97,6 +100,7 @@ public IndexStoredRulePersistenceService( this.maxRulesPerPage = maxRulesPerPage; this.parser = parser; this.queryBuilder = queryBuilder; + this.updatedRuleBuilder = updatedRuleBuilder; } /** @@ -255,7 +259,7 @@ public void onResponse(GetRuleResponse getRuleResponse) { listener.onFailure(new ResourceNotFoundException("Rule with ID " + ruleId + " not found.")); return; } - Rule updatedRule = new UpdatedRuleBuilder(getRuleResponse.getRules().get(ruleId), request).build(); + Rule updatedRule = updatedRuleBuilder.apply(getRuleResponse.getRules().get(ruleId), request); validateNoDuplicateRule( updatedRule, ActionListener.wrap(unused -> persistUpdatedRule(ruleId, updatedRule, listener), listener::onFailure) @@ -273,6 +277,7 @@ public void onFailure(Exception e) { /** * indexName getter */ + public String getIndexName() { return indexName; } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedDuplicateRuleChecker.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedDuplicateRuleChecker.java deleted file mode 100644 index 7eb5457eab8fe..0000000000000 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedDuplicateRuleChecker.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule.storage; - -import org.opensearch.common.annotation.ExperimentalApi; -import org.opensearch.rule.DuplicateRuleChecker; -import org.opensearch.rule.autotagging.Attribute; -import org.opensearch.rule.autotagging.Rule; - -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -/** - * This class is used to check rule duplication for indexed based rules. - */ -@ExperimentalApi -public class IndexBasedDuplicateRuleChecker implements DuplicateRuleChecker { - - /** - * Default constructor - */ - public IndexBasedDuplicateRuleChecker() {} - - /** - * Checks if a duplicate rule exists based on the attribute map. - * A rule is considered a duplicate when the attribute value already exists in the index, and the number of - * attributes in the new rule is equal to the number of attributes in an existing rule. - * - * For example, if an existing rule has: - * attribute1 = ['a'] and attribute2 = ['c'] - * And we are creating a new rule with: - * attribute1 = ['a'] - * Then it's not a duplicate because the existing rule has attribute2 and is more granular - * - * @param rule The rule to be validated against ruleMap. - * @param ruleMap This map entries are Rules that contain the attribute values from rule, meaning they - * have a partial or complete overlap with the new rule being created. - */ - @Override - public Optional getDuplicateRuleId(Rule rule, Map ruleMap) { - Map> attributeMapToValidate = rule.getAttributeMap(); - for (Map.Entry entry : ruleMap.entrySet()) { - String ruleId = entry.getKey(); - Rule currRule = entry.getValue(); - // Compare the size of the attribute maps to ensure we only check for duplicates with the same number of attributes. - if (attributeMapToValidate.size() == currRule.getAttributeMap().size()) { - return Optional.of(ruleId); - } - } - return Optional.empty(); - } -} diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java index 5cb9e9f059cf6..c1ea54ce1fd30 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java @@ -10,30 +10,30 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.UpdateRuleRequest; -import org.opensearch.rule.autotagging.Attribute; -import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import static org.opensearch.rule.action.GetRuleRequestTests._ID_ONE; import static org.opensearch.rule.action.GetRuleRequestTests.ATTRIBUTE_MAP; -import static org.opensearch.rule.action.GetRuleRequestTests.FEATURE_VALUE_ONE; import static org.opensearch.rule.action.GetRuleRequestTests.DESCRIPTION_ONE; import static org.opensearch.rule.action.GetRuleRequestTests.DESCRIPTION_TWO; +import static org.opensearch.rule.action.GetRuleRequestTests.FEATURE_VALUE_ONE; +import static org.opensearch.rule.action.GetRuleRequestTests._ID_ONE; public class UpdateRuleRequestTests extends OpenSearchTestCase { /** * Test case to verify the serialization and deserialization of UpdateRuleRequest */ public void testSerialization() throws IOException { - UpdateRuleRequest request = new UpdateRuleRequest(_ID_ONE, DESCRIPTION_TWO, ATTRIBUTE_MAP, FEATURE_VALUE_ONE, RuleTestUtils.MockRuleFeatureType.INSTANCE); + UpdateRuleRequest request = new UpdateRuleRequest( + _ID_ONE, + DESCRIPTION_TWO, + ATTRIBUTE_MAP, + FEATURE_VALUE_ONE, + RuleTestUtils.MockRuleFeatureType.INSTANCE + ); assertEquals(_ID_ONE, request.get_id()); assertNull(request.validate()); assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, request.getFeatureType()); @@ -65,7 +65,13 @@ public void testSerializationWithNull() throws IOException { } public void testValidate() { - UpdateRuleRequest request = new UpdateRuleRequest(_ID_ONE, "", ATTRIBUTE_MAP, FEATURE_VALUE_ONE, RuleTestUtils.MockRuleFeatureType.INSTANCE); + UpdateRuleRequest request = new UpdateRuleRequest( + _ID_ONE, + "", + ATTRIBUTE_MAP, + FEATURE_VALUE_ONE, + RuleTestUtils.MockRuleFeatureType.INSTANCE + ); assertNotNull(request.validate()); request = new UpdateRuleRequest(_ID_ONE, DESCRIPTION_ONE, ATTRIBUTE_MAP, "", RuleTestUtils.MockRuleFeatureType.INSTANCE); assertNotNull(request.validate()); diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java index 75cc323495490..235b81c84a205 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java @@ -13,20 +13,15 @@ import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.UpdateRuleResponse; -import org.opensearch.rule.autotagging.Attribute; -import org.opensearch.rule.autotagging.Rule; -import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import static org.opensearch.rule.action.GetRuleRequestTests._ID_ONE; +import static org.opensearch.rule.action.GetRuleRequestTests.assertEqualRule; +import static org.opensearch.rule.action.GetRuleRequestTests.ruleOne; import static org.mockito.Mockito.mock; -import static org.opensearch.rule.action.GetRuleRequestTests.*; public class UpdateRuleResponseTests extends OpenSearchTestCase { /** @@ -48,15 +43,15 @@ public void testToXContent() throws IOException { UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); - String expected = "{\n" + - " \"_id\" : \"id_1\",\n" + - " \"description\" : \"description_1\",\n" + - " \"mock_attribute_one\" : [\n" + - " \"mock_attribute_one\"\n" + - " ],\n" + - " \"mock_feature_type\" : \"feature_value_one\",\n" + - " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + - "}"; + String expected = "{\n" + + " \"_id\" : \"id_1\",\n" + + " \"description\" : \"description_1\",\n" + + " \"mock_attribute_one\" : [\n" + + " \"mock_attribute_one\"\n" + + " ],\n" + + " \"mock_feature_type\" : \"feature_value_one\",\n" + + " \"updated_at\" : \"2024-01-26T08:58:57.558Z\"\n" + + "}"; assertEquals(expected, actual); } } diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index eb054ea8124e5..27df5124d5a8b 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -10,27 +10,16 @@ import org.apache.lucene.search.TotalHits; import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.DocWriteResponse; -import org.opensearch.action.delete.DeleteRequest; -import org.opensearch.action.index.IndexRequest; -import org.opensearch.action.index.IndexResponse; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; -import org.opensearch.action.support.clustermanager.AcknowledgedResponse; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.Metadata; import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.action.ActionFuture; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesArray; -import org.opensearch.core.index.shard.ShardId; -import org.opensearch.index.engine.DocumentMissingException; import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.CreateRuleRequest; -import org.opensearch.rule.CreateRuleResponse; -import org.opensearch.rule.DeleteRuleRequest; import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; @@ -44,33 +33,17 @@ import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.client.Client; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import org.mockito.ArgumentCaptor; import static org.opensearch.rule.XContentRuleParserTests.VALID_JSON; -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; -import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.MockRuleFeatureType; import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -78,208 +51,98 @@ @SuppressWarnings("unchecked") public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { - private static final int MAX_VALUES_PER_PAGE = 50; + public static final int MAX_VALUES_PER_PAGE = 50; - private Client client; - private ClusterService clusterService; - private RuleQueryMapper ruleQueryMapper; - private RuleEntityParser ruleEntityParser; - private SearchRequestBuilder searchRequestBuilder; - private RulePersistenceService rulePersistenceService; - private QueryBuilder queryBuilder; - private Rule rule; - - public void setUp() throws Exception { - super.setUp(); - searchRequestBuilder = mock(SearchRequestBuilder.class); - client = setUpMockClient(searchRequestBuilder); - - rule = mock(Rule.class); - - clusterService = mock(ClusterService.class); - ClusterState clusterState = mock(ClusterState.class); - Metadata metadata = mock(Metadata.class); - when(clusterService.state()).thenReturn(clusterState); - when(clusterState.metadata()).thenReturn(metadata); - when(metadata.hasIndex(TEST_INDEX_NAME)).thenReturn(true); + public void testGetRuleByIdSuccess() { + GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); + when(getRuleRequest.getId()).thenReturn(_ID_ONE); + when(getRuleRequest.getAttributeFilters()).thenReturn(new HashMap<>()); + QueryBuilder queryBuilder = mock(QueryBuilder.class); + RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); + RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); + ClusterService clusterService = mock(ClusterService.class); + Rule mockRule = mock(Rule.class); - ruleQueryMapper = mock(RuleQueryMapper.class); - ruleEntityParser = mock(RuleEntityParser.class); - queryBuilder = mock(QueryBuilder.class); + when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); + when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); when(queryBuilder.filter(any())).thenReturn(queryBuilder); - when(ruleQueryMapper.from(any(GetRuleRequest.class))).thenReturn(queryBuilder); - when(ruleEntityParser.parse(anyString())).thenReturn(rule); - - rulePersistenceService = new IndexStoredRulePersistenceService( - TEST_INDEX_NAME, - client, - clusterService, - MAX_VALUES_PER_PAGE, - ruleEntityParser, - ruleQueryMapper - ); - } - - public void testCreateRuleOnExistingIndex() throws Exception { - CreateRuleRequest createRuleRequest = mock(CreateRuleRequest.class); - when(createRuleRequest.getRule()).thenReturn(rule); - when(rule.toXContent(any(), any())).thenAnswer(invocation -> invocation.getArgument(0)); - - SearchResponse searchResponse = mock(SearchResponse.class); - when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); - when(searchRequestBuilder.get()).thenReturn(searchResponse); - IndexResponse indexResponse = mock(IndexResponse.class); - when(indexResponse.getId()).thenReturn(_ID_ONE); - ActionFuture future = mock(ActionFuture.class); - when(future.get()).thenReturn(indexResponse); - when(client.index(any(IndexRequest.class))).thenReturn(future); - - ActionListener listener = mock(ActionListener.class); - rulePersistenceService.createRule(createRuleRequest, listener); - - ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(CreateRuleResponse.class); - verify(listener).onResponse(responseCaptor.capture()); - assertNotNull(responseCaptor.getValue().getRule()); - } - - public void testConcurrentCreateDuplicateRules() throws InterruptedException { - ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); - int threadCount = 10; - CountDownLatch latch = new CountDownLatch(threadCount); - Set storedAttributeMaps = ConcurrentHashMap.newKeySet(); - - CreateRuleRequest createRuleRequest = mock(CreateRuleRequest.class); - when(rule.getAttributeMap()).thenReturn(ATTRIBUTE_MAP); - when(rule.getFeatureType()).thenReturn(MockRuleFeatureType.INSTANCE); - when(createRuleRequest.getRule()).thenReturn(rule); + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + Client client = setUpMockClient(searchRequestBuilder); RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( TEST_INDEX_NAME, client, clusterService, MAX_VALUES_PER_PAGE, - ruleEntityParser, - ruleQueryMapper - ) { - @Override - public void createRule(CreateRuleRequest request, ActionListener listener) { - singleThreadExecutor.execute(() -> { - Rule rule = request.getRule(); - validateNoDuplicateRule(rule, new ActionListener() { - @Override - public void onResponse(Void unused) { - synchronized (storedAttributeMaps) { - storedAttributeMaps.add(MOCK_RULE_ATTRIBUTE_ONE.getName()); - } - listener.onResponse(new CreateRuleResponse("fake-id", rule)); - latch.countDown(); - } - - @Override - public void onFailure(Exception e) { - listener.onFailure(e); - latch.countDown(); - } - }); - }); - } - - public void validateNoDuplicateRule(Rule rule, ActionListener listener) { - synchronized (storedAttributeMaps) { - if (storedAttributeMaps.contains(MOCK_RULE_ATTRIBUTE_ONE.getName())) { - listener.onFailure(new IllegalArgumentException("Duplicate rule exists with attribute map")); - } else { - listener.onResponse(null); - } - } - } - }; - - class TestListener implements ActionListener { - final AtomicInteger successCount = new AtomicInteger(); - final AtomicInteger failureCount = new AtomicInteger(); - final List failures = Collections.synchronizedList(new ArrayList<>()); - - @Override - public void onResponse(CreateRuleResponse response) { - successCount.incrementAndGet(); - } - - @Override - public void onFailure(Exception e) { - failureCount.incrementAndGet(); - failures.add(e); - } - } - TestListener testListener = new TestListener(); - - for (int i = 0; i < threadCount; i++) { - new Thread(() -> rulePersistenceService.createRule(createRuleRequest, testListener)).start(); - } - boolean completed = latch.await(10, TimeUnit.SECONDS); - singleThreadExecutor.shutdown(); - assertTrue("All create calls should complete", completed); - assertEquals(1, testListener.successCount.get()); - assertEquals(threadCount - 1, testListener.failureCount.get()); - for (Exception e : testListener.failures) { - assertTrue(e instanceof IllegalArgumentException); - assertTrue(e.getMessage().contains("Duplicate rule")); - } - } - - public void testCreateDuplicateRule() { - CreateRuleRequest createRuleRequest = mock(CreateRuleRequest.class); - when(createRuleRequest.getRule()).thenReturn(rule); - when(rule.getAttributeMap()).thenReturn(Map.of(MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_ONE))); - when(rule.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + mockRuleEntityParser, + mockRuleQueryMapper, + null + ); SearchResponse searchResponse = mock(SearchResponse.class); - SearchHit hit = new SearchHit(1); - hit.sourceRef(new BytesArray(VALID_JSON)); - SearchHits searchHits = new SearchHits(new SearchHit[] { hit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); when(searchResponse.getHits()).thenReturn(searchHits); - when(searchRequestBuilder.get()).thenReturn(searchResponse); + SearchHit hit = searchHits.getHits()[0]; + hit.sourceRef(new BytesArray(VALID_JSON)); - ActionListener listener = mock(ActionListener.class); - when(ruleEntityParser.parse(any(String.class))).thenReturn(rule); - rulePersistenceService.createRule(createRuleRequest, listener); - ArgumentCaptor failureCaptor = ArgumentCaptor.forClass(Exception.class); - verify(listener).onFailure(failureCaptor.capture()); - } + ActionListener listener = mock(ActionListener.class); - public void testGetRuleByIdSuccess() { - GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); - when(getRuleRequest.getId()).thenReturn(_ID_ONE); - when(getRuleRequest.getAttributeFilters()).thenReturn(new HashMap<>()); - when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + doAnswer((invocation) -> { + ActionListener actionListener = invocation.getArgument(0); + actionListener.onResponse(searchResponse); + return null; + }).when(searchRequestBuilder).execute(any(ActionListener.class)); - SearchResponse searchResponse = mock(SearchResponse.class); - SearchHit searchHit = new SearchHit(1); - searchHit.sourceRef(new BytesArray(VALID_JSON)); - SearchHits searchHits = new SearchHits(new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); - when(searchResponse.getHits()).thenReturn(searchHits); - when(searchRequestBuilder.get()).thenReturn(searchResponse); + when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + rulePersistenceService.getRule(getRuleRequest, listener); - ActionListener listener = mock(ActionListener.class); ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); - rulePersistenceService.getRule(getRuleRequest, listener); verify(listener).onResponse(responseCaptor.capture()); GetRuleResponse response = responseCaptor.getValue(); - assertEquals(1, response.getRules().size()); + assertEquals(response.getRules().size(), 1); } public void testGetRuleByIdNotFound() { GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); when(getRuleRequest.getId()).thenReturn(_ID_ONE); - when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + QueryBuilder queryBuilder = mock(QueryBuilder.class); + RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); + ClusterService clusterService = mock(ClusterService.class); + RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); + Rule mockRule = mock(Rule.class); + + when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); + when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); + when(queryBuilder.filter(any())).thenReturn(queryBuilder); + + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + Client client = setUpMockClient(searchRequestBuilder); + + RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( + TEST_INDEX_NAME, + client, + clusterService, + MAX_VALUES_PER_PAGE, + mockRuleEntityParser, + mockRuleQueryMapper, + null + ); SearchResponse searchResponse = mock(SearchResponse.class); - when(searchRequestBuilder.get()).thenReturn(searchResponse); when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); + ActionListener listener = mock(ActionListener.class); + doAnswer(invocationOnMock -> { + ActionListener actionListener = invocationOnMock.getArgument(0); + actionListener.onResponse(searchResponse); + return null; + }).when(searchRequestBuilder).execute(any(ActionListener.class)); + + when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); rulePersistenceService.getRule(getRuleRequest, listener); + ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); verify(listener).onFailure(exceptionCaptor.capture()); Exception exception = exceptionCaptor.getValue(); @@ -305,55 +168,4 @@ private Client setUpMockClient(SearchRequestBuilder searchRequestBuilder) { return client; } - - public void testDeleteRule_successful() { - String ruleId = "test-rule-id"; - DeleteRuleRequest request = new DeleteRuleRequest(ruleId, RuleTestUtils.MockRuleFeatureType.INSTANCE); - ThreadPool threadPool = mock(ThreadPool.class); - when(client.threadPool()).thenReturn(threadPool); - when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); - - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(DeleteRequest.class); - ArgumentCaptor> listenerCaptor = ArgumentCaptor.forClass( - ActionListener.class - ); - - ActionListener listener = mock(ActionListener.class); - - rulePersistenceService.deleteRule(request, listener); - - verify(client).delete(requestCaptor.capture(), listenerCaptor.capture()); - assertEquals(ruleId, requestCaptor.getValue().id()); - - org.opensearch.action.delete.DeleteResponse deleteResponse = mock(org.opensearch.action.delete.DeleteResponse.class); - when(deleteResponse.getResult()).thenReturn(DocWriteResponse.Result.DELETED); - - listenerCaptor.getValue().onResponse(deleteResponse); - - verify(listener).onResponse(argThat(AcknowledgedResponse::isAcknowledged)); - } - - public void testDeleteRule_notFound() { - String ruleId = "missing-rule-id"; - DeleteRuleRequest request = new DeleteRuleRequest(ruleId, RuleTestUtils.MockRuleFeatureType.INSTANCE); - ThreadPool threadPool = mock(ThreadPool.class); - when(client.threadPool()).thenReturn(threadPool); - when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); - - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(DeleteRequest.class); - ArgumentCaptor> listenerCaptor = ArgumentCaptor.forClass( - ActionListener.class - ); - - ActionListener listener = mock(ActionListener.class); - - rulePersistenceService.deleteRule(request, listener); - - verify(client).delete(requestCaptor.capture(), listenerCaptor.capture()); - assertEquals(ruleId, requestCaptor.getValue().id()); - - listenerCaptor.getValue().onFailure(new DocumentMissingException(new ShardId(TEST_INDEX_NAME, "_na_", 0), ruleId)); - - verify(listener).onFailure(any(ResourceNotFoundException.class)); - } } 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 27ccad1cf5f36..b199a3ab7809a 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 @@ -61,7 +61,10 @@ import org.opensearch.rule.spi.RuleFrameworkExtension; import org.opensearch.rule.storage.AttributeValueStoreFactory; import org.opensearch.rule.storage.DefaultAttributeValueStore; -import org.opensearch.rule.storage.IndexBasedDuplicateRuleChecker; +import org.opensearch.rule.RuleUtils; +import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.service.IndexStoredRulePersistenceService; +import org.opensearch.rule.spi.RuleFrameworkExtension; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.storage.XContentRuleParser; import org.opensearch.script.ScriptService; @@ -92,7 +95,6 @@ public class WorkloadManagementPlugin extends Plugin implements ActionPlugin, Sy private static FeatureType featureType; private static RulePersistenceService rulePersistenceService; private static RuleRoutingService ruleRoutingService; - private AutoTaggingActionFilter autoTaggingActionFilter; /** @@ -127,7 +129,8 @@ public Collection createComponents( clusterService, MAX_RULES_PER_PAGE, parser, - new IndexBasedRuleQueryMapper() + new IndexBasedRuleQueryMapper(), + (existingRule, request) -> RuleUtils.composeUpdatedRule(existingRule, request, featureType) ); ruleRoutingService = new WorkloadGroupRuleRoutingService(client, clusterService); From dba912ebe9a86e815d4b45d108f779abbd14aea8 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Wed, 7 May 2025 20:20:48 -0700 Subject: [PATCH 09/11] fix UTs Signed-off-by: Ruirui Zhang Signed-off-by: Kaushal Kumar --- .../rule/RuleFrameworkPluginTests.java | 12 +- .../plugin/wlm/WorkloadManagementPlugin.java | 15 +- .../wlm/rule/WorkloadGroupFeatureType.java | 16 +- .../WorkloadGroupFeatureValueValidator.java | 14 +- .../rule/WorkloadGroupFeatureTypeTests.java | 168 +++++++++++++++--- 5 files changed, 193 insertions(+), 32 deletions(-) diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java index 4e11d12f9facb..72b205f74261d 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java @@ -16,7 +16,9 @@ import org.opensearch.plugins.ActionPlugin; import org.opensearch.rest.RestHandler; import org.opensearch.rule.action.GetRuleAction; +import org.opensearch.rule.action.UpdateRuleAction; import org.opensearch.rule.rest.RestGetRuleAction; +import org.opensearch.rule.rest.RestUpdateRuleAction; import org.opensearch.test.OpenSearchTestCase; import java.util.List; @@ -28,13 +30,14 @@ public class RuleFrameworkPluginTests extends OpenSearchTestCase { public void testGetActions() { List> handlers = plugin.getActions(); - assertEquals(3, handlers.size()); + assertEquals(4, handlers.size()); assertEquals(GetRuleAction.INSTANCE.name(), handlers.get(0).getAction().name()); + assertEquals(UpdateRuleAction.INSTANCE.name(), handlers.get(1).getAction().name()); } public void testGetRestHandlers() { Settings settings = Settings.EMPTY; - RestHandler handler = plugin.getRestHandlers( + List handlers = plugin.getRestHandlers( settings, mock(org.opensearch.rest.RestController.class), null, @@ -42,8 +45,9 @@ public void testGetRestHandlers() { null, mock(IndexNameExpressionResolver.class), () -> mock(DiscoveryNodes.class) - ).get(0); + ); - assertTrue(handler instanceof RestGetRuleAction); + assertTrue(handlers.get(0) instanceof RestGetRuleAction); + assertTrue(handlers.get(1) instanceof RestUpdateRuleAction); } } 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 b199a3ab7809a..8c4f042f27e6c 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 @@ -63,6 +63,7 @@ import org.opensearch.rule.storage.DefaultAttributeValueStore; import org.opensearch.rule.RuleUtils; import org.opensearch.rule.autotagging.FeatureType; +import org.opensearch.rule.autotagging.FeatureValueValidator; import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.rule.spi.RuleFrameworkExtension; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; @@ -123,6 +124,7 @@ public Collection createComponents( DefaultAttributeValueStore::new ); InMemoryRuleProcessingService ruleProcessingService = new InMemoryRuleProcessingService(attributeValueStoreFactory); + rulePersistenceService = new IndexStoredRulePersistenceService( rulePersistenceService = new IndexStoredRulePersistenceService( INDEX_NAME, client, @@ -210,12 +212,15 @@ public Supplier getRulePersistenceServiceSupplier() { } @Override - public Supplier getRuleRoutingServiceSupplier() { - return () -> ruleRoutingService; + public FeatureType getFeatureType() { + return FeatureTypeHolder.featureType; } - @Override - public Supplier getFeatureTypeSupplier() { - return () -> featureType; + static class RulePersistenceServiceHolder { + private static RulePersistenceService rulePersistenceService; + } + + static class FeatureTypeHolder { + private static FeatureType featureType; } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java index fc9dfa3136277..f934ae15cda27 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java @@ -31,15 +31,29 @@ public class WorkloadGroupFeatureType implements FeatureType { RuleAttribute.INDEX_PATTERN ); private final FeatureValueValidator featureValueValidator; + private static WorkloadGroupFeatureType instance; /** * constructor for WorkloadGroupFeatureType * @param featureValueValidator */ - public WorkloadGroupFeatureType(FeatureValueValidator featureValueValidator) { + private WorkloadGroupFeatureType(FeatureValueValidator featureValueValidator) { this.featureValueValidator = featureValueValidator; } + public static void initializeFeatureValueValidator(FeatureValueValidator validator) { + if (instance == null) { + instance = new WorkloadGroupFeatureType(validator); + } + } + + public static WorkloadGroupFeatureType getInstance() { + if (instance == null) { + throw new IllegalStateException("FeatureValueValidator is not initialized. Call initializeFeatureValueValidator() first."); + } + return instance; + } + @Override public String getName() { return NAME; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureValueValidator.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureValueValidator.java index 0ea7621943615..1b673b656f9bb 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureValueValidator.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureValueValidator.java @@ -20,16 +20,28 @@ */ public class WorkloadGroupFeatureValueValidator implements FeatureValueValidator { private final ClusterService clusterService; + private static volatile WorkloadGroupFeatureValueValidator instance; private final Logger logger = LogManager.getLogger(WorkloadGroupFeatureValueValidator.class); /** * constructor for WorkloadGroupFeatureValueValidator * @param clusterService */ - public WorkloadGroupFeatureValueValidator(ClusterService clusterService) { + private WorkloadGroupFeatureValueValidator(ClusterService clusterService) { this.clusterService = clusterService; } + public static WorkloadGroupFeatureValueValidator getInstance(ClusterService clusterService) { + if (instance == null) { + synchronized (WorkloadGroupFeatureValueValidator.class) { + if (instance == null) { + instance = new WorkloadGroupFeatureValueValidator(clusterService); + } + } + } + return instance; + } + @Override public void validate(String featureValue) { if (!clusterService.state().metadata().workloadGroups().containsKey(featureValue)) { diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java index a55e345fd56da..27df5124d5a8b 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java @@ -6,40 +6,166 @@ * compatible open source license. */ -package org.opensearch.plugin.wlm.rule; +package org.opensearch.rule.service; +import org.apache.lucene.search.TotalHits; +import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.search.SearchRequestBuilder; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.cluster.ClusterState; +import org.opensearch.cluster.metadata.Metadata; import org.opensearch.cluster.service.ClusterService; -import org.opensearch.rule.RuleAttribute; -import org.opensearch.rule.autotagging.Attribute; -import org.opensearch.rule.autotagging.AutoTaggingRegistry; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.bytes.BytesArray; +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.GetRuleRequest; +import org.opensearch.rule.GetRuleResponse; +import org.opensearch.rule.RuleEntityParser; +import org.opensearch.rule.RulePersistenceService; +import org.opensearch.rule.RuleQueryMapper; +import org.opensearch.rule.autotagging.Rule; +import org.opensearch.rule.utils.RuleTestUtils; +import org.opensearch.search.SearchHit; +import org.opensearch.search.SearchHits; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.client.Client; -import java.util.Map; +import java.util.HashMap; +import org.mockito.ArgumentCaptor; + +import static org.opensearch.rule.XContentRuleParserTests.VALID_JSON; +import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -public class WorkloadGroupFeatureTypeTests extends OpenSearchTestCase { - WorkloadGroupFeatureType featureType = new WorkloadGroupFeatureType(new WorkloadGroupFeatureValueValidator(mock(ClusterService.class))); +@SuppressWarnings("unchecked") +public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { - public void testGetName_returnsCorrectName() { - assertEquals("workload_group", featureType.getName()); - } + public static final int MAX_VALUES_PER_PAGE = 50; - public void testMaxNumberOfValuesPerAttribute() { - assertEquals(10, featureType.getMaxNumberOfValuesPerAttribute()); - } + public void testGetRuleByIdSuccess() { + GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); + when(getRuleRequest.getId()).thenReturn(_ID_ONE); + when(getRuleRequest.getAttributeFilters()).thenReturn(new HashMap<>()); + QueryBuilder queryBuilder = mock(QueryBuilder.class); + RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); + RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); + ClusterService clusterService = mock(ClusterService.class); + Rule mockRule = mock(Rule.class); + + when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); + when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); + when(queryBuilder.filter(any())).thenReturn(queryBuilder); + + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + Client client = setUpMockClient(searchRequestBuilder); + + RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( + TEST_INDEX_NAME, + client, + clusterService, + MAX_VALUES_PER_PAGE, + mockRuleEntityParser, + mockRuleQueryMapper, + null + ); - public void testMaxCharLengthPerAttributeValue() { - assertEquals(100, featureType.getMaxCharLengthPerAttributeValue()); + SearchResponse searchResponse = mock(SearchResponse.class); + SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + when(searchResponse.getHits()).thenReturn(searchHits); + SearchHit hit = searchHits.getHits()[0]; + hit.sourceRef(new BytesArray(VALID_JSON)); + + ActionListener listener = mock(ActionListener.class); + + doAnswer((invocation) -> { + ActionListener actionListener = invocation.getArgument(0); + actionListener.onResponse(searchResponse); + return null; + }).when(searchRequestBuilder).execute(any(ActionListener.class)); + + when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + rulePersistenceService.getRule(getRuleRequest, listener); + + ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); + verify(listener).onResponse(responseCaptor.capture()); + GetRuleResponse response = responseCaptor.getValue(); + assertEquals(response.getRules().size(), 1); } - public void testGetAllowedAttributesRegistry_containsIndexPattern() { - Map allowedAttributes = featureType.getAllowedAttributesRegistry(); - assertTrue(allowedAttributes.containsKey("index_pattern")); - assertEquals(RuleAttribute.INDEX_PATTERN, allowedAttributes.get("index_pattern")); + public void testGetRuleByIdNotFound() { + GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); + when(getRuleRequest.getId()).thenReturn(_ID_ONE); + QueryBuilder queryBuilder = mock(QueryBuilder.class); + RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); + ClusterService clusterService = mock(ClusterService.class); + RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); + Rule mockRule = mock(Rule.class); + + when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); + when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); + when(queryBuilder.filter(any())).thenReturn(queryBuilder); + + SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); + Client client = setUpMockClient(searchRequestBuilder); + + RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( + TEST_INDEX_NAME, + client, + clusterService, + MAX_VALUES_PER_PAGE, + mockRuleEntityParser, + mockRuleQueryMapper, + null + ); + + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); + + ActionListener listener = mock(ActionListener.class); + + doAnswer(invocationOnMock -> { + ActionListener actionListener = invocationOnMock.getArgument(0); + actionListener.onResponse(searchResponse); + return null; + }).when(searchRequestBuilder).execute(any(ActionListener.class)); + + when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + rulePersistenceService.getRule(getRuleRequest, listener); + + ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); + verify(listener).onFailure(exceptionCaptor.capture()); + Exception exception = exceptionCaptor.getValue(); + assertTrue(exception instanceof ResourceNotFoundException); } - public void testRegisterFeatureType() { - AutoTaggingRegistry.registerFeatureType(featureType); + private Client setUpMockClient(SearchRequestBuilder searchRequestBuilder) { + Client client = mock(Client.class); + ClusterService clusterService = mock(ClusterService.class); + ClusterState clusterState = mock(ClusterState.class); + Metadata metadata = mock(Metadata.class); + ThreadPool threadPool = mock(ThreadPool.class); + + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + when(client.threadPool()).thenReturn(threadPool); + when(threadPool.getThreadContext()).thenReturn(threadContext); + when(clusterService.state()).thenReturn(clusterState); + when(clusterState.metadata()).thenReturn(metadata); + + when(client.prepareSearch(TEST_INDEX_NAME)).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setQuery(any(QueryBuilder.class))).thenReturn(searchRequestBuilder); + when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); + + return client; } } From 805cefc9ea155c43cd1eeceb5ff2fb32b142b8fe Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Thu, 5 Jun 2025 13:20:21 -0700 Subject: [PATCH 10/11] update to fit the new framework Signed-off-by: Ruirui Zhang --- .../opensearch/rule/CreateRuleResponse.java | 5 +- .../org/opensearch/rule/GetRuleResponse.java | 4 +- .../opensearch/rule/RuleRoutingService.java | 7 + .../java/org/opensearch/rule/RuleUtils.java | 21 + .../opensearch/rule/UpdateRuleRequest.java | 2 +- .../opensearch/rule/UpdateRuleResponse.java | 5 +- .../opensearch/rule/UpdatedRuleBuilder.java | 71 --- .../org/opensearch/rule/autotagging/Rule.java | 8 +- .../rule/autotagging/RuleValidator.java | 7 + .../IndexStoredRulePersistenceService.java | 32 +- .../org/opensearch/rule/RuleUtilsTests.java | 2 +- .../rule/action/CreateRuleResponseTests.java | 2 +- .../rule/action/GetRuleResponseTests.java | 22 +- .../rule/action/UpdateRuleRequestTests.java | 10 +- .../rule/action/UpdateRuleResponseTests.java | 8 +- .../rule/autotagging/RuleTests.java | 24 +- .../rule/autotagging/RuleValidatorTests.java | 9 +- ...ndexStoredRulePersistenceServiceTests.java | 411 +++++++++++++++--- .../rule/action/TransportGetRuleAction.java | 15 +- .../action/TransportUpdateRuleAction.java | 71 ++- .../rule/rest/RestCreateRuleAction.java | 1 - .../rule/rest/RestDeleteRuleAction.java | 6 +- .../InMemoryRuleProcessingServiceTests.java | 1 - .../rule/RuleFrameworkPluginTests.java | 8 +- .../action/TransportGetRuleActionTests.java | 9 +- .../plugin/wlm/WorkloadManagementPlugin.java | 21 +- .../wlm/rule/WorkloadGroupFeatureType.java | 16 +- .../WorkloadGroupFeatureValueValidator.java | 14 +- .../rule/WorkloadGroupRuleRoutingService.java | 65 ++- .../rule/WorkloadGroupFeatureTypeTests.java | 168 +------ 30 files changed, 597 insertions(+), 448 deletions(-) diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleResponse.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleResponse.java index f040372b69335..14c57f2fb0bd4 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleResponse.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleResponse.java @@ -17,9 +17,6 @@ import org.opensearch.rule.autotagging.Rule; import java.io.IOException; -import java.util.Map; - -import static org.opensearch.rule.autotagging.Rule._ID_STRING; /** * Response for the create API for Rule @@ -64,7 +61,7 @@ public void writeTo(StreamOutput out) throws IOException { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return rule.toXContent(builder, new MapParams(Map.of(_ID_STRING, _id))); + return rule.toXContent(builder, params); } /** diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java index 2ce79850084db..e0f22e7c075ff 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java @@ -20,8 +20,6 @@ import java.io.IOException; import java.util.Map; -import static org.opensearch.rule.autotagging.Rule._ID_STRING; - /** * Response for the get API for Rule. * Example response: @@ -74,7 +72,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject(); builder.startArray("rules"); for (Map.Entry entry : rules.entrySet()) { - entry.getValue().toXContent(builder, new MapParams(Map.of(_ID_STRING, entry.getKey()))); + entry.getValue().toXContent(builder, params); } builder.endArray(); if (searchAfter != null && !searchAfter.isEmpty()) { diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleRoutingService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleRoutingService.java index e0d08f371a2aa..a84a5c717e756 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleRoutingService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleRoutingService.java @@ -22,4 +22,11 @@ public interface RuleRoutingService { * @param listener listener to handle the final response */ void handleCreateRuleRequest(CreateRuleRequest request, ActionListener listener); + + /** + * Handles a update rule request by routing it to the appropriate node. + * @param request the update rule request + * @param listener listener to handle the final response + */ + void handleUpdateRuleRequest(UpdateRuleRequest request, ActionListener listener); } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java index 40f56289df8e5..4d5bbb618b4e0 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java @@ -13,11 +13,13 @@ import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule; +import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.UUID; /** * Utility class for operations related to {@link Rule} objects. @@ -31,6 +33,24 @@ public class RuleUtils { */ public RuleUtils() {} + /** + * Computes a UUID-based hash string for a rule based on its key attributes. + * @param description the rule's description + * @param featureType the rule's feature type + * @param attributeMap the rule's attribute map (will use its toString representation) + * @param featureValue the rule's feature value + */ + public static String computeRuleHash( + String description, + FeatureType featureType, + Map> attributeMap, + String featureValue + ) { + String combined = description + "|" + featureType.getName() + "|" + attributeMap.toString() + "|" + featureValue; + UUID uuid = UUID.nameUUIDFromBytes(combined.getBytes(StandardCharsets.UTF_8)); + return uuid.toString(); + } + /** * Checks if a duplicate rule exists and returns its id. * Two rules are considered to be duplicate when meeting all the criteria below @@ -79,6 +99,7 @@ public static Rule composeUpdatedRule(Rule originalRule, UpdateRuleRequest reque Map> requestMap = request.getAttributeMap(); String requestLabel = request.getFeatureValue(); return new Rule( + originalRule.getId(), requestDescription == null ? originalRule.getDescription() : requestDescription, requestMap == null || requestMap.isEmpty() ? originalRule.getAttributeMap() : requestMap, featureType, diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java index 8172687586090..d03dc135d3028 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java @@ -79,7 +79,7 @@ public UpdateRuleRequest(StreamInput in) throws IOException { @Override public ActionRequestValidationException validate() { - RuleValidator validator = new RuleValidator(description, attributeMap, featureValue, null, featureType); + RuleValidator validator = new RuleValidator(_id, description, attributeMap, featureValue, null, featureType); List errors = validator.validateUpdatingRuleParams(); if (!errors.isEmpty()) { ActionRequestValidationException validationException = new ActionRequestValidationException(); diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java index e867e25ce13ab..ee35fa60b95f7 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java @@ -18,9 +18,6 @@ import org.opensearch.rule.autotagging.Rule; import java.io.IOException; -import java.util.Map; - -import static org.opensearch.rule.autotagging.Rule._ID_STRING; /** * Response for the update API for Rule @@ -65,7 +62,7 @@ public void writeTo(StreamOutput out) throws IOException { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return rule.toXContent(builder, new MapParams(Map.of(_ID_STRING, _id))); + return rule.toXContent(builder, params); } /** diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java index fd729fa3e05c6..ae686f8f13ab2 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java @@ -9,16 +9,6 @@ package org.opensearch.rule; import org.opensearch.common.annotation.ExperimentalApi; -<<<<<<< HEAD -import org.opensearch.rule.autotagging.Attribute; -import org.opensearch.rule.autotagging.Rule; - -import java.util.Collections; -import java.util.Map; -import java.util.Optional; -import org.opensearch.rule.autotagging.FeatureType; -======= ->>>>>>> 0dfab231d13 (change the structure to update a rule to make testing easier) import org.opensearch.rule.autotagging.Rule; /** @@ -26,72 +16,11 @@ * @opensearch.experimental */ @ExperimentalApi -@FunctionalInterface public interface UpdatedRuleBuilder { /** * Applies updates to an existing rule based on the provided update request. * @param existingRule the rule to update * @param request the update request containing new values */ -<<<<<<< HEAD - public UpdatedRuleBuilder(Rule originalRule, UpdateRuleRequest updateRuleRequest) { - this.originalRule = originalRule; - this.request = updateRuleRequest; - } - - /** - * Checks if a duplicate rule exists and returns its id. - * Two rules are considered to be duplicate when meeting all the criteria below - * 1. They have the same feature type - * 2. They have the exact same attributes - * 3. For each attribute, the sets of values must intersect — i.e., at least one common value must exist - * between the current rule and the one being checked. - * - * @param rule The rule to be validated against ruleMap. - * @param ruleMap This map contains existing rules to be checked - */ - public static Optional getDuplicateRuleId(Rule rule, Map ruleMap) { - Map> targetAttributeMap = rule.getAttributeMap(); - for (Map.Entry entry : ruleMap.entrySet()) { - Rule currRule = entry.getValue(); - Map> existingAttributeMap = currRule.getAttributeMap(); - - if (rule.getFeatureType() != currRule.getFeatureType() || targetAttributeMap.size() != existingAttributeMap.size()) { - continue; - } - boolean allAttributesIntersect = true; - for (Attribute attribute : targetAttributeMap.keySet()) { - Set targetAttributeValues = targetAttributeMap.get(attribute); - Set existingAttributeValues = existingAttributeMap.get(attribute); - if (existingAttributeValues == null || Collections.disjoint(targetAttributeValues, existingAttributeValues)) { - allAttributesIntersect = false; - break; - } - } - if (allAttributesIntersect) { - return Optional.of(entry.getKey()); - } - } - return Optional.empty(); - } - - /** - * Creates an updated {@link Rule} object by applying non-null fields from the given {@link UpdateRuleRequest} - * to the original rule. Fields not provided in the request will retain their values from the original rule. - */ - public Rule build() { - String requestDescription = request.getDescription(); - Map> requestMap = request.getAttributeMap(); - String requestLabel = request.getFeatureValue(); - return new Rule( - requestDescription == null ? originalRule.getDescription() : requestDescription, - requestMap == null || requestMap.isEmpty() ? originalRule.getAttributeMap() : requestMap, - originalRule.getFeatureType(), - requestLabel == null ? originalRule.getFeatureValue() : requestLabel, - Instant.now().toString() - ); - } -======= Rule apply(Rule existingRule, UpdateRuleRequest request); ->>>>>>> 0dfab231d13 (change the structure to update a rule to make testing easier) } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java index 79c8782202cf8..4791b07979c1d 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java @@ -15,6 +15,7 @@ import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.core.xcontent.XContentParseException; import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.rule.RuleUtils; import java.io.IOException; import java.util.HashMap; @@ -81,7 +82,7 @@ public Rule( this.attributeMap = attributeMap; this.featureValue = featureValue; this.updatedAt = updatedAt; - this.ruleValidator = new RuleValidator(description, attributeMap, featureValue, updatedAt, featureType); + this.ruleValidator = new RuleValidator(id, description, attributeMap, featureValue, updatedAt, featureType); this.ruleValidator.validate(); } @@ -97,7 +98,7 @@ public Rule(StreamInput in) throws IOException { attributeMap = in.readMap(i -> Attribute.from(i, featureType), i -> new HashSet<>(i.readStringList())); featureValue = in.readString(); updatedAt = in.readString(); - this.ruleValidator = new RuleValidator(description, attributeMap, featureValue, updatedAt, featureType); + this.ruleValidator = new RuleValidator(id, description, attributeMap, featureValue, updatedAt, featureType); this.ruleValidator.validate(); } @@ -173,7 +174,7 @@ public Map> getAttributeMap() { @Override public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException { builder.startObject(); - builder.field(_ID_STRING, id); + builder.field("id", id); builder.field(DESCRIPTION_STRING, description); for (Map.Entry> entry : attributeMap.entrySet()) { builder.array(entry.getKey().getName(), entry.getValue().toArray(new String[0])); @@ -350,6 +351,7 @@ public Builder updatedAt(String updatedAt) { * @return */ public Rule build() { + id = RuleUtils.computeRuleHash(description, featureType, attributeMap, featureValue); return new Rule(id, description, attributeMap, featureType, featureValue, updatedAt); } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java index e7d0f817b4b17..fb464046c67f5 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java @@ -26,6 +26,7 @@ * @opensearch.experimental */ public class RuleValidator { + private final String id; private final String description; private final Map> attributeMap; private final String featureValue; @@ -38,6 +39,7 @@ public class RuleValidator { /** * deafult constructor + * @param id * @param description * @param attributeMap * @param featureValue @@ -45,12 +47,14 @@ public class RuleValidator { * @param featureType */ public RuleValidator( + String id, String description, Map> attributeMap, String featureValue, String updatedAt, FeatureType featureType ) { + this.id = id; this.description = description; this.attributeMap = attributeMap; this.featureValue = featureValue; @@ -101,6 +105,9 @@ public List validateUpdatingRuleParams() { private List validateStringFields() { List errors = new ArrayList<>(); + if (isNullOrEmpty(id)) { + errors.add("Rule id can't be null or empty"); + } if (isNullOrEmpty(description)) { errors.add("Rule description can't be null or empty"); } else if (description.length() > MAX_DESCRIPTION_LENGTH) { diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index 5c09da4d5c276..fe56ac63b1fca 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -29,8 +29,6 @@ import org.opensearch.rule.CreateRuleRequest; import org.opensearch.rule.CreateRuleResponse; import org.opensearch.rule.DeleteRuleRequest; - -import org.opensearch.index.query.QueryBuilder; import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; @@ -46,7 +44,6 @@ import org.opensearch.search.sort.SortOrder; import org.opensearch.transport.client.Client; -import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -72,7 +69,6 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService private final RuleQueryMapper queryBuilder; private final UpdatedRuleBuilder updatedRuleBuilder; private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); - private static final Map indexSettings = Map.of("index.number_of_shards", 1, "index.auto_expand_replicas", "0-all"); /** * Constructs an instance of {@link IndexStoredRulePersistenceService} with the specified parameters. @@ -153,9 +149,8 @@ public void onFailure(Exception e) { */ private void persistRule(Rule rule, ActionListener listener) { try { - IndexRequest indexRequest = new IndexRequest(indexName).source( - rule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) - ); + IndexRequest indexRequest = new IndexRequest(indexName).id(rule.getId()) + .source(rule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS)); IndexResponse indexResponse = client.index(indexRequest).get(); listener.onResponse(new CreateRuleResponse(indexResponse.getId(), rule)); } catch (Exception e) { @@ -216,7 +211,7 @@ private static boolean hasNoResults(String id, ActionListener l */ void handleGetRuleResponse(List hits, ActionListener listener) { Map ruleMap = hits.stream().collect(Collectors.toMap(SearchHit::getId, hit -> parser.parse(hit.getSourceAsString()))); - String nextSearchAfter = hits.isEmpty() ? null : hits.get(hits.size() - 1).getId(); + String nextSearchAfter = hits.isEmpty() || hits.size() < maxRulesPerPage ? null : hits.get(hits.size() - 1).getId(); listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter)); } @@ -274,14 +269,6 @@ public void onFailure(Exception e) { } } - /** - * indexName getter - */ - - public String getIndexName() { - return indexName; - } - /** * Persist the updated rule in index * @param ruleId - the rule id to update @@ -289,18 +276,13 @@ public String getIndexName() { * @param listener - ActionListener for UpdateRuleResponse */ private void persistUpdatedRule(String ruleId, Rule updatedRule, ActionListener listener) { - try (ThreadContext.StoredContext context = stashContext()) { + try { UpdateRequest updateRequest = new UpdateRequest(indexName, ruleId).doc( updatedRule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) ); - client.update( - updateRequest, - ActionListener.wrap(updateResponse -> { listener.onResponse(new UpdateRuleResponse(ruleId, updatedRule)); }, e -> { - logger.error("Failed to update Rule object due to error: {}", e.getMessage()); - listener.onFailure(e); - }) - ); - } catch (IOException e) { + client.update(updateRequest).get(); + listener.onResponse(new UpdateRuleResponse(ruleId, updatedRule)); + } catch (Exception e) { logger.error("Error updating rule in index: {}", indexName); listener.onFailure(new RuntimeException("Failed to update rule to index.")); } diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleUtilsTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleUtilsTests.java index 2780f329925c9..6b0d26528f8b8 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleUtilsTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleUtilsTests.java @@ -17,7 +17,6 @@ import java.util.Optional; import java.util.Set; -import static org.opensearch.rule.action.GetRuleResponseTests.ruleOne; import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_TWO; import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; @@ -25,6 +24,7 @@ import static org.opensearch.rule.utils.RuleTestUtils.TIMESTAMP_ONE; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; import static org.opensearch.rule.utils.RuleTestUtils._ID_TWO; +import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; import static org.opensearch.rule.utils.RuleTestUtils.ruleTwo; public class RuleUtilsTests extends OpenSearchTestCase { diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleResponseTests.java index dc445dad2e82c..050e1f7ff963b 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleResponseTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleResponseTests.java @@ -20,9 +20,9 @@ import java.io.IOException; import java.util.Map; -import static org.opensearch.rule.action.GetRuleResponseTests.ruleOne; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRules; +import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; import static org.mockito.Mockito.mock; public class CreateRuleResponseTests extends OpenSearchTestCase { diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java index 5515d12e4701f..d6bd0baf562ca 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java @@ -14,41 +14,21 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.rule.GetRuleResponse; -import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.Rule; -import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; import java.util.HashMap; import java.util.Map; -import java.util.Set; import static org.opensearch.rule.utils.RuleTestUtils.SEARCH_AFTER; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRules; import static org.opensearch.rule.utils.RuleTestUtils.ruleMap; +import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; import static org.mockito.Mockito.mock; public class GetRuleResponseTests extends OpenSearchTestCase { - public static final String FEATURE_VALUE_ONE = "feature_value_one"; - public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; - public static final String DESCRIPTION_ONE = "description_1"; - public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; - static final Map> ATTRIBUTE_MAP = Map.of( - RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, - Set.of(ATTRIBUTE_VALUE_ONE) - ); - - public static final Rule ruleOne = Rule.builder() - .id(_ID_ONE) - .description(DESCRIPTION_ONE) - .featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_ONE) - .attributeMap(ATTRIBUTE_MAP) - .updatedAt(TIMESTAMP_ONE) - .build(); - /** * Test case to verify the serialization and deserialization of GetRuleResponse */ diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java index c1ea54ce1fd30..9d2418f0f5dca 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java @@ -16,11 +16,11 @@ import java.io.IOException; -import static org.opensearch.rule.action.GetRuleRequestTests.ATTRIBUTE_MAP; -import static org.opensearch.rule.action.GetRuleRequestTests.DESCRIPTION_ONE; -import static org.opensearch.rule.action.GetRuleRequestTests.DESCRIPTION_TWO; -import static org.opensearch.rule.action.GetRuleRequestTests.FEATURE_VALUE_ONE; -import static org.opensearch.rule.action.GetRuleRequestTests._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_TWO; +import static org.opensearch.rule.utils.RuleTestUtils.FEATURE_VALUE_ONE; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; public class UpdateRuleRequestTests extends OpenSearchTestCase { /** diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java index 235b81c84a205..ce3dfda25189c 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java @@ -18,9 +18,9 @@ import java.io.IOException; -import static org.opensearch.rule.action.GetRuleRequestTests._ID_ONE; -import static org.opensearch.rule.action.GetRuleRequestTests.assertEqualRule; -import static org.opensearch.rule.action.GetRuleRequestTests.ruleOne; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRule; +import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; import static org.mockito.Mockito.mock; public class UpdateRuleResponseTests extends OpenSearchTestCase { @@ -44,7 +44,7 @@ public void testToXContent() throws IOException { XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" - + " \"_id\" : \"id_1\",\n" + + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + " \"description\" : \"description_1\",\n" + " \"mock_attribute_one\" : [\n" + " \"mock_attribute_one\"\n" diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleTests.java index c0f3a96020a4c..13c6b93fac631 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleTests.java @@ -13,6 +13,7 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.rule.RuleUtils; import org.opensearch.test.AbstractSerializingTestCase; import java.io.IOException; @@ -20,7 +21,6 @@ import java.util.Map; import java.util.Set; -import static org.opensearch.rule.autotagging.Rule._ID_STRING; import static org.opensearch.rule.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_1; import static org.opensearch.rule.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_2; @@ -32,12 +32,7 @@ public class RuleTests extends AbstractSerializingTestCase { public static final String _ID = "test_id"; public static final String FEATURE_VALUE = "feature_value"; public static final TestFeatureType FEATURE_TYPE = TestFeatureType.INSTANCE; - public static final Map> ATTRIBUTE_MAP = Map.of( - TEST_ATTRIBUTE_1, - Set.of("value1"), - TEST_ATTRIBUTE_2, - Set.of("value2") - ); + public static final Map> ATTRIBUTE_MAP = Map.of(TEST_ATTRIBUTE_1, Set.of("value1")); public static final String UPDATED_AT = "2025-02-24T07:42:10.123456Z"; public static final String INVALID_ATTRIBUTE = "invalid_attribute"; public static final String INVALID_FEATURE = "invalid_feature"; @@ -47,7 +42,8 @@ protected Rule createTestInstance() { String description = randomAlphaOfLength(10); String featureValue = randomAlphaOfLength(5); String updatedAt = Instant.now().toString(); - return new Rule("test_id", description, ATTRIBUTE_MAP, FEATURE_TYPE, featureValue, updatedAt); + String id = RuleUtils.computeRuleHash(description, FEATURE_TYPE, ATTRIBUTE_MAP, featureValue); + return new Rule(id, description, ATTRIBUTE_MAP, FEATURE_TYPE, featureValue, updatedAt); } @Override @@ -122,8 +118,9 @@ static Rule buildRule( String updatedAt, String description ) { + String id = RuleUtils.computeRuleHash(description, featureType, attributeListMap, featureValue); return Rule.builder() - .id(_ID) + .id(id) .featureValue(featureValue) .featureType(featureType) .description(description) @@ -146,13 +143,14 @@ public void testValidRule() { public void testToXContent() throws IOException { String updatedAt = Instant.now().toString(); - Rule rule = buildRule(FEATURE_VALUE, FEATURE_TYPE, Map.of(TEST_ATTRIBUTE_1, Set.of("value1")), updatedAt, DESCRIPTION); + Map> map = Map.of(TEST_ATTRIBUTE_1, Set.of("value1")); + Rule rule = buildRule(FEATURE_VALUE, FEATURE_TYPE, map, updatedAt, DESCRIPTION); XContentBuilder builder = JsonXContent.contentBuilder(); - rule.toXContent(builder, new ToXContent.MapParams(Map.of(_ID_STRING, _ID))); + rule.toXContent(builder, ToXContent.EMPTY_PARAMS); assertEquals( - "{\"_id\":\"" - + _ID + "{\"id\":\"" + + RuleUtils.computeRuleHash(DESCRIPTION, FEATURE_TYPE, map, FEATURE_VALUE) + "\",\"description\":\"description\",\"test_attr1\":[\"value1\"],\"test_feature_type\":\"feature_value\",\"updated_at\":\"" + updatedAt + "\"}", diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java index b24f9daa034c6..1b17ede64cca0 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/autotagging/RuleValidatorTests.java @@ -22,11 +22,12 @@ import static org.opensearch.rule.autotagging.RuleTests.FEATURE_VALUE; import static org.opensearch.rule.autotagging.RuleTests.TestAttribute.TEST_ATTRIBUTE_1; import static org.opensearch.rule.autotagging.RuleTests.UPDATED_AT; +import static org.opensearch.rule.autotagging.RuleTests._ID; public class RuleValidatorTests extends OpenSearchTestCase { public void testValidRule() { - RuleValidator validator = new RuleValidator(DESCRIPTION, ATTRIBUTE_MAP, FEATURE_VALUE, UPDATED_AT, FEATURE_TYPE); + RuleValidator validator = new RuleValidator(_ID, DESCRIPTION, ATTRIBUTE_MAP, FEATURE_VALUE, UPDATED_AT, FEATURE_TYPE); try { validator.validate(); } catch (Exception e) { @@ -41,7 +42,7 @@ public static void validateRule( String updatedAt, String description ) { - RuleValidator validator = new RuleValidator(description, attributeMap, featureValue, updatedAt, featureType); + RuleValidator validator = new RuleValidator(_ID, description, attributeMap, featureValue, updatedAt, featureType); validator.validate(); } @@ -113,8 +114,8 @@ public void testInvalidLabel() { } public void testEqualRuleValidators() { - RuleValidator validator = new RuleValidator(DESCRIPTION, ATTRIBUTE_MAP, FEATURE_VALUE, UPDATED_AT, FEATURE_TYPE); - RuleValidator otherValidator = new RuleValidator(DESCRIPTION, ATTRIBUTE_MAP, FEATURE_VALUE, UPDATED_AT, FEATURE_TYPE); + RuleValidator validator = new RuleValidator(_ID, DESCRIPTION, ATTRIBUTE_MAP, FEATURE_VALUE, UPDATED_AT, FEATURE_TYPE); + RuleValidator otherValidator = new RuleValidator(_ID, DESCRIPTION, ATTRIBUTE_MAP, FEATURE_VALUE, UPDATED_AT, FEATURE_TYPE); assertEquals(validator, otherValidator); } } diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index 27df5124d5a8b..17ab9ae73de60 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -10,21 +10,37 @@ import org.apache.lucene.search.TotalHits; import org.opensearch.ResourceNotFoundException; +import org.opensearch.action.DocWriteResponse; +import org.opensearch.action.delete.DeleteRequest; +import org.opensearch.action.index.IndexRequest; +import org.opensearch.action.index.IndexResponse; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; +import org.opensearch.action.support.clustermanager.AcknowledgedResponse; +import org.opensearch.action.update.UpdateRequest; +import org.opensearch.action.update.UpdateResponse; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.Metadata; import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.action.ActionFuture; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesArray; +import org.opensearch.core.index.shard.ShardId; +import org.opensearch.index.engine.DocumentMissingException; import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.CreateRuleRequest; +import org.opensearch.rule.CreateRuleResponse; +import org.opensearch.rule.DeleteRuleRequest; import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; +import org.opensearch.rule.UpdateRuleRequest; +import org.opensearch.rule.UpdateRuleResponse; +import org.opensearch.rule.UpdatedRuleBuilder; import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.search.SearchHit; @@ -33,17 +49,35 @@ import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.client.Client; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.mockito.ArgumentCaptor; import static org.opensearch.rule.XContentRuleParserTests.VALID_JSON; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE; import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; +import static org.opensearch.rule.utils.RuleTestUtils.ruleTwo; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -51,98 +85,209 @@ @SuppressWarnings("unchecked") public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { - public static final int MAX_VALUES_PER_PAGE = 50; + private static final int MAX_VALUES_PER_PAGE = 50; - public void testGetRuleByIdSuccess() { - GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); - when(getRuleRequest.getId()).thenReturn(_ID_ONE); - when(getRuleRequest.getAttributeFilters()).thenReturn(new HashMap<>()); - QueryBuilder queryBuilder = mock(QueryBuilder.class); - RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); - RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); - ClusterService clusterService = mock(ClusterService.class); - Rule mockRule = mock(Rule.class); + private Client client; + private ClusterService clusterService; + private RuleQueryMapper ruleQueryMapper; + private RuleEntityParser ruleEntityParser; + private UpdatedRuleBuilder updatedRuleBuilder; + private SearchRequestBuilder searchRequestBuilder; + private RulePersistenceService rulePersistenceService; + private QueryBuilder queryBuilder; + private Rule rule; - when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); - when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); + public void setUp() throws Exception { + super.setUp(); + searchRequestBuilder = mock(SearchRequestBuilder.class); + client = setUpMockClient(searchRequestBuilder); + rule = mock(Rule.class); + clusterService = mock(ClusterService.class); + ClusterState clusterState = mock(ClusterState.class); + Metadata metadata = mock(Metadata.class); + when(clusterService.state()).thenReturn(clusterState); + when(clusterState.metadata()).thenReturn(metadata); + when(metadata.hasIndex(TEST_INDEX_NAME)).thenReturn(true); + ruleQueryMapper = mock(RuleQueryMapper.class); + ruleEntityParser = mock(RuleEntityParser.class); + queryBuilder = mock(QueryBuilder.class); when(queryBuilder.filter(any())).thenReturn(queryBuilder); + when(ruleQueryMapper.from(any(GetRuleRequest.class))).thenReturn(queryBuilder); + when(ruleEntityParser.parse(anyString())).thenReturn(rule); + updatedRuleBuilder = mock(UpdatedRuleBuilder.class); - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - Client client = setUpMockClient(searchRequestBuilder); - - RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( + rulePersistenceService = new IndexStoredRulePersistenceService( TEST_INDEX_NAME, client, clusterService, MAX_VALUES_PER_PAGE, - mockRuleEntityParser, - mockRuleQueryMapper, - null + ruleEntityParser, + ruleQueryMapper, + updatedRuleBuilder ); + } - SearchResponse searchResponse = mock(SearchResponse.class); - SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); - when(searchResponse.getHits()).thenReturn(searchHits); - SearchHit hit = searchHits.getHits()[0]; - hit.sourceRef(new BytesArray(VALID_JSON)); + public void testCreateRuleOnExistingIndex() throws Exception { + CreateRuleRequest createRuleRequest = mock(CreateRuleRequest.class); + when(createRuleRequest.getRule()).thenReturn(rule); + when(rule.toXContent(any(), any())).thenAnswer(invocation -> invocation.getArgument(0)); - ActionListener listener = mock(ActionListener.class); + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); + when(searchRequestBuilder.get()).thenReturn(searchResponse); - doAnswer((invocation) -> { - ActionListener actionListener = invocation.getArgument(0); - actionListener.onResponse(searchResponse); - return null; - }).when(searchRequestBuilder).execute(any(ActionListener.class)); + IndexResponse indexResponse = mock(IndexResponse.class); + when(indexResponse.getId()).thenReturn(_ID_ONE); + ActionFuture future = mock(ActionFuture.class); + when(future.get()).thenReturn(indexResponse); + when(client.index(any(IndexRequest.class))).thenReturn(future); - when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); - rulePersistenceService.getRule(getRuleRequest, listener); + ActionListener listener = mock(ActionListener.class); + rulePersistenceService.createRule(createRuleRequest, listener); - ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); + ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(CreateRuleResponse.class); verify(listener).onResponse(responseCaptor.capture()); - GetRuleResponse response = responseCaptor.getValue(); - assertEquals(response.getRules().size(), 1); + assertNotNull(responseCaptor.getValue().getRule()); } - public void testGetRuleByIdNotFound() { - GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); - when(getRuleRequest.getId()).thenReturn(_ID_ONE); - QueryBuilder queryBuilder = mock(QueryBuilder.class); - RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); - ClusterService clusterService = mock(ClusterService.class); - RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); - Rule mockRule = mock(Rule.class); + public void testConcurrentCreateDuplicateRules() throws InterruptedException { + ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); + int threadCount = 10; + CountDownLatch latch = new CountDownLatch(threadCount); + Set storedAttributeMaps = ConcurrentHashMap.newKeySet(); - when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); - when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); - when(queryBuilder.filter(any())).thenReturn(queryBuilder); - - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - Client client = setUpMockClient(searchRequestBuilder); + CreateRuleRequest createRuleRequest = mock(CreateRuleRequest.class); + when(rule.getAttributeMap()).thenReturn(ATTRIBUTE_MAP); + when(rule.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + when(createRuleRequest.getRule()).thenReturn(rule); RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( TEST_INDEX_NAME, client, clusterService, MAX_VALUES_PER_PAGE, - mockRuleEntityParser, - mockRuleQueryMapper, - null - ); + ruleEntityParser, + ruleQueryMapper, + updatedRuleBuilder + ) { + @Override + public void createRule(CreateRuleRequest request, ActionListener listener) { + singleThreadExecutor.execute(() -> { + Rule rule = request.getRule(); + validateNoDuplicateRule(rule, new ActionListener() { + @Override + public void onResponse(Void unused) { + synchronized (storedAttributeMaps) { + storedAttributeMaps.add(MOCK_RULE_ATTRIBUTE_ONE.getName()); + } + listener.onResponse(new CreateRuleResponse("fake-id", rule)); + latch.countDown(); + } - SearchResponse searchResponse = mock(SearchResponse.class); - when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + latch.countDown(); + } + }); + }); + } - ActionListener listener = mock(ActionListener.class); + public void validateNoDuplicateRule(Rule rule, ActionListener listener) { + synchronized (storedAttributeMaps) { + if (storedAttributeMaps.contains(MOCK_RULE_ATTRIBUTE_ONE.getName())) { + listener.onFailure(new IllegalArgumentException("Duplicate rule exists with attribute map")); + } else { + listener.onResponse(null); + } + } + } + }; + + class TestListener implements ActionListener { + final AtomicInteger successCount = new AtomicInteger(); + final AtomicInteger failureCount = new AtomicInteger(); + final List failures = Collections.synchronizedList(new ArrayList<>()); + + @Override + public void onResponse(CreateRuleResponse response) { + successCount.incrementAndGet(); + } + + @Override + public void onFailure(Exception e) { + failureCount.incrementAndGet(); + failures.add(e); + } + } + TestListener testListener = new TestListener(); + + for (int i = 0; i < threadCount; i++) { + new Thread(() -> rulePersistenceService.createRule(createRuleRequest, testListener)).start(); + } + boolean completed = latch.await(10, TimeUnit.SECONDS); + singleThreadExecutor.shutdown(); + assertTrue("All create calls should complete", completed); + assertEquals(1, testListener.successCount.get()); + assertEquals(threadCount - 1, testListener.failureCount.get()); + for (Exception e : testListener.failures) { + assertTrue(e instanceof IllegalArgumentException); + assertTrue(e.getMessage().contains("Duplicate rule")); + } + } + + public void testCreateDuplicateRule() { + CreateRuleRequest createRuleRequest = mock(CreateRuleRequest.class); + when(createRuleRequest.getRule()).thenReturn(rule); + when(rule.getAttributeMap()).thenReturn(Map.of(MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_ONE))); + when(rule.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); - doAnswer(invocationOnMock -> { - ActionListener actionListener = invocationOnMock.getArgument(0); - actionListener.onResponse(searchResponse); - return null; - }).when(searchRequestBuilder).execute(any(ActionListener.class)); + SearchResponse searchResponse = mock(SearchResponse.class); + SearchHit hit = new SearchHit(1); + hit.sourceRef(new BytesArray(VALID_JSON)); + SearchHits searchHits = new SearchHits(new SearchHit[] { hit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + when(searchResponse.getHits()).thenReturn(searchHits); + when(searchRequestBuilder.get()).thenReturn(searchResponse); + + ActionListener listener = mock(ActionListener.class); + when(ruleEntityParser.parse(any(String.class))).thenReturn(rule); + rulePersistenceService.createRule(createRuleRequest, listener); + ArgumentCaptor failureCaptor = ArgumentCaptor.forClass(Exception.class); + verify(listener).onFailure(failureCaptor.capture()); + } + public void testGetRuleByIdSuccess() { + GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); + when(getRuleRequest.getId()).thenReturn(_ID_ONE); + when(getRuleRequest.getAttributeFilters()).thenReturn(new HashMap<>()); when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + + SearchResponse searchResponse = mock(SearchResponse.class); + SearchHit searchHit = new SearchHit(1); + searchHit.sourceRef(new BytesArray(VALID_JSON)); + SearchHits searchHits = new SearchHits(new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + when(searchResponse.getHits()).thenReturn(searchHits); + when(searchRequestBuilder.get()).thenReturn(searchResponse); + + ActionListener listener = mock(ActionListener.class); + ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); rulePersistenceService.getRule(getRuleRequest, listener); + verify(listener).onResponse(responseCaptor.capture()); + GetRuleResponse response = responseCaptor.getValue(); + assertEquals(1, response.getRules().size()); + } + public void testGetRuleByIdNotFound() { + GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); + when(getRuleRequest.getId()).thenReturn(_ID_ONE); + when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchRequestBuilder.get()).thenReturn(searchResponse); + when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); + ActionListener listener = mock(ActionListener.class); + + rulePersistenceService.getRule(getRuleRequest, listener); ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); verify(listener).onFailure(exceptionCaptor.capture()); Exception exception = exceptionCaptor.getValue(); @@ -168,4 +313,146 @@ private Client setUpMockClient(SearchRequestBuilder searchRequestBuilder) { return client; } + + public void testDeleteRule_successful() { + String ruleId = "test-rule-id"; + DeleteRuleRequest request = new DeleteRuleRequest(ruleId, RuleTestUtils.MockRuleFeatureType.INSTANCE); + ThreadPool threadPool = mock(ThreadPool.class); + when(client.threadPool()).thenReturn(threadPool); + when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); + + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(DeleteRequest.class); + ArgumentCaptor> listenerCaptor = ArgumentCaptor.forClass( + ActionListener.class + ); + + ActionListener listener = mock(ActionListener.class); + + rulePersistenceService.deleteRule(request, listener); + + verify(client).delete(requestCaptor.capture(), listenerCaptor.capture()); + assertEquals(ruleId, requestCaptor.getValue().id()); + + org.opensearch.action.delete.DeleteResponse deleteResponse = mock(org.opensearch.action.delete.DeleteResponse.class); + when(deleteResponse.getResult()).thenReturn(DocWriteResponse.Result.DELETED); + + listenerCaptor.getValue().onResponse(deleteResponse); + + verify(listener).onResponse(argThat(AcknowledgedResponse::isAcknowledged)); + } + + public void testDeleteRule_notFound() { + String ruleId = "missing-rule-id"; + DeleteRuleRequest request = new DeleteRuleRequest(ruleId, RuleTestUtils.MockRuleFeatureType.INSTANCE); + ThreadPool threadPool = mock(ThreadPool.class); + when(client.threadPool()).thenReturn(threadPool); + when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); + + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(DeleteRequest.class); + ArgumentCaptor> listenerCaptor = ArgumentCaptor.forClass( + ActionListener.class + ); + + ActionListener listener = mock(ActionListener.class); + + rulePersistenceService.deleteRule(request, listener); + + verify(client).delete(requestCaptor.capture(), listenerCaptor.capture()); + assertEquals(ruleId, requestCaptor.getValue().id()); + + listenerCaptor.getValue().onFailure(new DocumentMissingException(new ShardId(TEST_INDEX_NAME, "_na_", 0), ruleId)); + + verify(listener).onFailure(any(ResourceNotFoundException.class)); + } + + public void testUpdateRule_SuccessfulUpdate() throws Exception { + UpdateRuleRequest request = mock(UpdateRuleRequest.class); + when(request.get_id()).thenReturn(_ID_ONE); + when(updatedRuleBuilder.apply(ruleOne, request)).thenReturn(ruleTwo); + + SearchHit searchHit = new SearchHit(1, _ID_ONE, null, null); + searchHit.sourceRef(new BytesArray(VALID_JSON)); + SearchHits searchHits = new SearchHits(new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(searchHits); + when(searchRequestBuilder.get()).thenReturn(searchResponse); + when(ruleEntityParser.parse(anyString())).thenReturn(ruleOne); + + UpdateResponse updateResponse = mock(UpdateResponse.class); + ActionFuture future = mock(ActionFuture.class); + when(future.get()).thenReturn(updateResponse); + when(client.update(any(UpdateRequest.class))).thenReturn(future); + + AtomicBoolean onResponseCalled = new AtomicBoolean(false); + rulePersistenceService.updateRule(request, new ActionListener<>() { + @Override + public void onResponse(UpdateRuleResponse updateRuleResponse) { + assertEquals(_ID_ONE, updateRuleResponse.get_id()); + assertEquals(ruleTwo, updateRuleResponse.getRule()); + onResponseCalled.set(true); + } + + @Override + public void onFailure(Exception e) { + fail(); + } + }); + + assertTrue(onResponseCalled.get()); + } + + public void testUpdateRule_RuleNotFound() { + UpdateRuleRequest request = mock(UpdateRuleRequest.class); + when(request.get_id()).thenReturn(_ID_ONE); + + SearchHits emptyHits = new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f); + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(emptyHits); + when(searchRequestBuilder.get()).thenReturn(searchResponse); + + AtomicReference failure = new AtomicReference<>(); + rulePersistenceService.updateRule(request, new ActionListener<>() { + @Override + public void onResponse(UpdateRuleResponse updateRuleResponse) { + fail(); + } + + @Override + public void onFailure(Exception e) { + failure.set(e); + } + }); + + assertTrue(failure.get() instanceof ResourceNotFoundException); + assertTrue(failure.get().getMessage().contains(_ID_ONE)); + } + + public void testUpdateRule_ParseFailure() { + UpdateRuleRequest request = mock(UpdateRuleRequest.class); + when(request.get_id()).thenReturn(_ID_ONE); + + SearchHit searchHit = new SearchHit(1, _ID_ONE, null, null); + searchHit.sourceRef(new BytesArray(VALID_JSON)); + SearchHits searchHits = new SearchHits(new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(searchHits); + when(searchRequestBuilder.get()).thenReturn(searchResponse); + when(ruleEntityParser.parse(anyString())).thenThrow(new RuntimeException("Invalid JSON")); + + AtomicReference failure = new AtomicReference<>(); + rulePersistenceService.updateRule(request, new ActionListener<>() { + @Override + public void onResponse(UpdateRuleResponse updateRuleResponse) { + fail(); + } + + @Override + public void onFailure(Exception e) { + failure.set(e); + } + }); + + assertNotNull(failure.get()); + assertTrue(failure.get().getMessage().contains("Invalid JSON")); + } } diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java index 7a7d7258af216..29115a38060d9 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java @@ -17,6 +17,7 @@ import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.tasks.Task; +import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; /** @@ -26,28 +27,34 @@ public class TransportGetRuleAction extends HandledTransportAction { private final RulePersistenceServiceRegistry rulePersistenceServiceRegistry; + private final ThreadPool threadPool; /** * Constructor for TransportGetRuleAction * @param transportService - a {@link TransportService} object + * @param threadPool - a {@link ThreadPool} object * @param actionFilters - a {@link ActionFilters} object * @param rulePersistenceServiceRegistry - a {@link RulePersistenceServiceRegistry} object */ @Inject public TransportGetRuleAction( TransportService transportService, + ThreadPool threadPool, ActionFilters actionFilters, RulePersistenceServiceRegistry rulePersistenceServiceRegistry ) { super(GetRuleAction.NAME, transportService, actionFilters, GetRuleRequest::new); + this.threadPool = threadPool; this.rulePersistenceServiceRegistry = rulePersistenceServiceRegistry; } @Override protected void doExecute(Task task, GetRuleRequest request, ActionListener listener) { - final RulePersistenceService rulePersistenceService = rulePersistenceServiceRegistry.getRulePersistenceService( - request.getFeatureType() - ); - rulePersistenceService.getRule(request, listener); + threadPool.executor(ThreadPool.Names.GET).execute(() -> { + final RulePersistenceService rulePersistenceService = rulePersistenceServiceRegistry.getRulePersistenceService( + request.getFeatureType() + ); + rulePersistenceService.getRule(request, listener); + }); } } diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java index 7cdc01e294f5d..427e639fdd19b 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java @@ -9,45 +9,98 @@ package org.opensearch.rule.action; import org.opensearch.action.support.ActionFilters; -import org.opensearch.action.support.HandledTransportAction; +import org.opensearch.action.support.TransportAction; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; +import org.opensearch.rule.RuleRoutingServiceRegistry; import org.opensearch.rule.UpdateRuleRequest; import org.opensearch.rule.UpdateRuleResponse; import org.opensearch.tasks.Task; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportChannel; +import org.opensearch.transport.TransportException; +import org.opensearch.transport.TransportRequestHandler; import org.opensearch.transport.TransportService; +import java.io.IOException; + +import static org.opensearch.rule.RuleFrameworkPlugin.RULE_THREAD_POOL_NAME; + /** * Transport action to update Rules * @opensearch.experimental */ -public class TransportUpdateRuleAction extends HandledTransportAction { - +public class TransportUpdateRuleAction extends TransportAction { + private final ThreadPool threadPool; + private final RuleRoutingServiceRegistry ruleRoutingServiceRegistry; private final RulePersistenceServiceRegistry rulePersistenceServiceRegistry; /** * Constructor for TransportUpdateRuleAction * @param transportService - a {@link TransportService} object + * @param threadPool - a {@link ThreadPool} object * @param actionFilters - a {@link ActionFilters} object * @param rulePersistenceServiceRegistry - a {@link RulePersistenceServiceRegistry} object + * @param ruleRoutingServiceRegistry - a {@link RuleRoutingServiceRegistry} object */ @Inject public TransportUpdateRuleAction( TransportService transportService, + ThreadPool threadPool, ActionFilters actionFilters, - RulePersistenceServiceRegistry rulePersistenceServiceRegistry + RulePersistenceServiceRegistry rulePersistenceServiceRegistry, + RuleRoutingServiceRegistry ruleRoutingServiceRegistry ) { - super(UpdateRuleAction.NAME, transportService, actionFilters, UpdateRuleRequest::new); + super(UpdateRuleAction.NAME, actionFilters, transportService.getTaskManager()); this.rulePersistenceServiceRegistry = rulePersistenceServiceRegistry; + this.ruleRoutingServiceRegistry = ruleRoutingServiceRegistry; + this.threadPool = threadPool; + + transportService.registerRequestHandler( + UpdateRuleAction.NAME, + ThreadPool.Names.SAME, + UpdateRuleRequest::new, + new TransportRequestHandler() { + @Override + public void messageReceived(UpdateRuleRequest request, TransportChannel channel, Task task) { + executeLocally(request, ActionListener.wrap(response -> { + try { + channel.sendResponse(response); + } catch (IOException e) { + logger.error("Failed to send UpdateRuleResponse to transport channel", e); + throw new TransportException("Fail to send", e); + } + }, exception -> { + try { + channel.sendResponse(exception); + } catch (IOException e) { + logger.error("Failed to send exception response to transport channel", e); + throw new TransportException("Fail to send", e); + } + })); + } + } + ); } @Override protected void doExecute(Task task, UpdateRuleRequest request, ActionListener listener) { - final RulePersistenceService rulePersistenceService = rulePersistenceServiceRegistry.getRulePersistenceService( - request.getFeatureType() - ); - rulePersistenceService.updateRule(request, listener); + ruleRoutingServiceRegistry.getRuleRoutingService(request.getFeatureType()).handleUpdateRuleRequest(request, listener); + } + + /** + * Executes the update rule operation locally on the dedicated rule thread pool. + * @param request the UpdateRuleRequest + * @param listener listener to handle response or failure + */ + private void executeLocally(UpdateRuleRequest request, ActionListener listener) { + threadPool.executor(RULE_THREAD_POOL_NAME).execute(() -> { + final RulePersistenceService rulePersistenceService = rulePersistenceServiceRegistry.getRulePersistenceService( + request.getFeatureType() + ); + rulePersistenceService.updateRule(request, listener); + }); } } diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestCreateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestCreateRuleAction.java index 7a5f45e95a0ba..4a8254924db2e 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestCreateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestCreateRuleAction.java @@ -58,7 +58,6 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli try (XContentParser parser = request.contentParser()) { Builder builder = Builder.fromXContent(parser, featureType); CreateRuleRequest createRuleRequest = new CreateRuleRequest(builder.updatedAt(Instant.now().toString()).build()); - return channel -> client.execute(CreateRuleAction.INSTANCE, createRuleRequest, createRuleResponse(channel)); } } diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestDeleteRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestDeleteRuleAction.java index bdf25963faf9f..fffd344c46e8b 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestDeleteRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestDeleteRuleAction.java @@ -26,6 +26,8 @@ import java.util.List; import static org.opensearch.rest.RestRequest.Method.DELETE; +import static org.opensearch.rule.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.rest.RestGetRuleAction.FEATURE_TYPE; /** * Rest action to delete a Rule @@ -50,8 +52,8 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - final String ruleId = request.param("ruleId"); - FeatureType featureType = FeatureType.from(request.param("featureType")); + final String ruleId = request.param(_ID_STRING); + FeatureType featureType = FeatureType.from(request.param(FEATURE_TYPE)); DeleteRuleRequest deleteRuleRequest = new DeleteRuleRequest(ruleId, featureType); return channel -> client.execute(DeleteRuleAction.INSTANCE, deleteRuleRequest, deleteRuleResponse(channel)); } diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java index 21882753210c6..67e015ad01254 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/InMemoryRuleProcessingServiceTests.java @@ -12,7 +12,6 @@ import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.AutoTaggingRegistry; import org.opensearch.rule.autotagging.FeatureType; -import org.opensearch.rule.autotagging.FeatureValueValidator; import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.storage.AttributeValueStoreFactory; import org.opensearch.rule.storage.DefaultAttributeValueStore; diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java index 72b205f74261d..ff5f907ce352c 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/RuleFrameworkPluginTests.java @@ -16,7 +16,8 @@ import org.opensearch.plugins.ActionPlugin; import org.opensearch.rest.RestHandler; import org.opensearch.rule.action.GetRuleAction; -import org.opensearch.rule.action.UpdateRuleAction; +import org.opensearch.rule.rest.RestCreateRuleAction; +import org.opensearch.rule.rest.RestDeleteRuleAction; import org.opensearch.rule.rest.RestGetRuleAction; import org.opensearch.rule.rest.RestUpdateRuleAction; import org.opensearch.test.OpenSearchTestCase; @@ -32,7 +33,6 @@ public void testGetActions() { List> handlers = plugin.getActions(); assertEquals(4, handlers.size()); assertEquals(GetRuleAction.INSTANCE.name(), handlers.get(0).getAction().name()); - assertEquals(UpdateRuleAction.INSTANCE.name(), handlers.get(1).getAction().name()); } public void testGetRestHandlers() { @@ -48,6 +48,8 @@ public void testGetRestHandlers() { ); assertTrue(handlers.get(0) instanceof RestGetRuleAction); - assertTrue(handlers.get(1) instanceof RestUpdateRuleAction); + assertTrue(handlers.get(1) instanceof RestDeleteRuleAction); + assertTrue(handlers.get(2) instanceof RestCreateRuleAction); + assertTrue(handlers.get(3) instanceof RestUpdateRuleAction); } } diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java index 369af17ed581f..cf69cf858f162 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java @@ -13,8 +13,12 @@ import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; @@ -35,7 +39,10 @@ public void testExecute() { when(rulePersistenceServiceRegistry.getRulePersistenceService(any())).thenReturn(rulePersistenceService); doNothing().when(rulePersistenceService).getRule(any(), any()); - sut = new TransportGetRuleAction(transportService, actionFilters, rulePersistenceServiceRegistry); + ThreadPool threadPool = mock(ThreadPool.class); + ExecutorService mockExecutor = Executors.newSingleThreadExecutor(); + when(threadPool.executor(any())).thenReturn(mockExecutor); + sut = new TransportGetRuleAction(transportService, threadPool, actionFilters, rulePersistenceServiceRegistry); sut.doExecute(null, getRuleRequest, null); verify(rulePersistenceService, times(1)).getRule(any(), any()); } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/WorkloadManagementPlugin.java index 8c4f042f27e6c..e7b11fa1d8f30 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 @@ -56,16 +56,12 @@ import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleRoutingService; +import org.opensearch.rule.RuleUtils; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.rule.spi.RuleFrameworkExtension; import org.opensearch.rule.storage.AttributeValueStoreFactory; import org.opensearch.rule.storage.DefaultAttributeValueStore; -import org.opensearch.rule.RuleUtils; -import org.opensearch.rule.autotagging.FeatureType; -import org.opensearch.rule.autotagging.FeatureValueValidator; -import org.opensearch.rule.service.IndexStoredRulePersistenceService; -import org.opensearch.rule.spi.RuleFrameworkExtension; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.storage.XContentRuleParser; import org.opensearch.script.ScriptService; @@ -124,7 +120,6 @@ public Collection createComponents( DefaultAttributeValueStore::new ); InMemoryRuleProcessingService ruleProcessingService = new InMemoryRuleProcessingService(attributeValueStoreFactory); - rulePersistenceService = new IndexStoredRulePersistenceService( rulePersistenceService = new IndexStoredRulePersistenceService( INDEX_NAME, client, @@ -134,7 +129,6 @@ public Collection createComponents( new IndexBasedRuleQueryMapper(), (existingRule, request) -> RuleUtils.composeUpdatedRule(existingRule, request, featureType) ); - ruleRoutingService = new WorkloadGroupRuleRoutingService(client, clusterService); RefreshBasedSyncMechanism refreshMechanism = new RefreshBasedSyncMechanism( @@ -212,15 +206,12 @@ public Supplier getRulePersistenceServiceSupplier() { } @Override - public FeatureType getFeatureType() { - return FeatureTypeHolder.featureType; + public Supplier getRuleRoutingServiceSupplier() { + return () -> ruleRoutingService; } - static class RulePersistenceServiceHolder { - private static RulePersistenceService rulePersistenceService; - } - - static class FeatureTypeHolder { - private static FeatureType featureType; + @Override + public Supplier getFeatureTypeSupplier() { + return () -> featureType; } } diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java index f934ae15cda27..fc9dfa3136277 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureType.java @@ -31,29 +31,15 @@ public class WorkloadGroupFeatureType implements FeatureType { RuleAttribute.INDEX_PATTERN ); private final FeatureValueValidator featureValueValidator; - private static WorkloadGroupFeatureType instance; /** * constructor for WorkloadGroupFeatureType * @param featureValueValidator */ - private WorkloadGroupFeatureType(FeatureValueValidator featureValueValidator) { + public WorkloadGroupFeatureType(FeatureValueValidator featureValueValidator) { this.featureValueValidator = featureValueValidator; } - public static void initializeFeatureValueValidator(FeatureValueValidator validator) { - if (instance == null) { - instance = new WorkloadGroupFeatureType(validator); - } - } - - public static WorkloadGroupFeatureType getInstance() { - if (instance == null) { - throw new IllegalStateException("FeatureValueValidator is not initialized. Call initializeFeatureValueValidator() first."); - } - return instance; - } - @Override public String getName() { return NAME; diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureValueValidator.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureValueValidator.java index 1b673b656f9bb..0ea7621943615 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureValueValidator.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureValueValidator.java @@ -20,28 +20,16 @@ */ public class WorkloadGroupFeatureValueValidator implements FeatureValueValidator { private final ClusterService clusterService; - private static volatile WorkloadGroupFeatureValueValidator instance; private final Logger logger = LogManager.getLogger(WorkloadGroupFeatureValueValidator.class); /** * constructor for WorkloadGroupFeatureValueValidator * @param clusterService */ - private WorkloadGroupFeatureValueValidator(ClusterService clusterService) { + public WorkloadGroupFeatureValueValidator(ClusterService clusterService) { this.clusterService = clusterService; } - public static WorkloadGroupFeatureValueValidator getInstance(ClusterService clusterService) { - if (instance == null) { - synchronized (WorkloadGroupFeatureValueValidator.class) { - if (instance == null) { - instance = new WorkloadGroupFeatureValueValidator(clusterService); - } - } - } - return instance; - } - @Override public void validate(String featureValue) { if (!clusterService.state().metadata().workloadGroups().containsKey(featureValue)) { diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupRuleRoutingService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupRuleRoutingService.java index a70482eb40186..3436f8e852ef3 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupRuleRoutingService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupRuleRoutingService.java @@ -12,7 +12,9 @@ import org.apache.logging.log4j.Logger; import org.opensearch.ExceptionsHelper; import org.opensearch.ResourceAlreadyExistsException; +import org.opensearch.ResourceNotFoundException; import org.opensearch.action.ActionListenerResponseHandler; +import org.opensearch.action.ActionRequest; import org.opensearch.action.admin.indices.create.CreateIndexRequest; import org.opensearch.action.admin.indices.create.CreateIndexResponse; import org.opensearch.cluster.ClusterState; @@ -22,11 +24,16 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; +import org.opensearch.core.action.ActionResponse; +import org.opensearch.core.common.io.stream.Writeable; import org.opensearch.plugin.wlm.WorkloadManagementPlugin; import org.opensearch.rule.CreateRuleRequest; import org.opensearch.rule.CreateRuleResponse; import org.opensearch.rule.RuleRoutingService; +import org.opensearch.rule.UpdateRuleRequest; +import org.opensearch.rule.UpdateRuleResponse; import org.opensearch.rule.action.CreateRuleAction; +import org.opensearch.rule.action.UpdateRuleAction; import org.opensearch.transport.TransportService; import org.opensearch.transport.client.Client; @@ -67,8 +74,8 @@ public void handleCreateRuleRequest(CreateRuleRequest request, ActionListener() { @@ -78,7 +85,7 @@ public void onResponse(CreateIndexResponse response) { logger.error("Failed to create index " + indexName); listener.onFailure(new IllegalStateException(indexName + " index creation not acknowledged")); } else { - routeRequest(request, listener, indexName); + routeRequest(CreateRuleAction.NAME, indexName, request, CreateRuleResponse::new, listener); } } @@ -86,7 +93,7 @@ public void onResponse(CreateIndexResponse response) { public void onFailure(Exception e) { Throwable cause = ExceptionsHelper.unwrapCause(e); if (cause instanceof ResourceAlreadyExistsException) { - routeRequest(request, listener, indexName); + routeRequest(CreateRuleAction.NAME, indexName, request, CreateRuleResponse::new, listener); } else { logger.error("Failed to create index {}: {}", indexName, e.getMessage()); listener.onFailure(e); @@ -96,6 +103,19 @@ public void onFailure(Exception e) { } } + @Override + public void handleUpdateRuleRequest(UpdateRuleRequest request, ActionListener listener) { + String indexName = WorkloadManagementPlugin.INDEX_NAME; + try (ThreadContext.StoredContext ctx = client.threadPool().getThreadContext().stashContext()) { + if (!hasIndex(indexName)) { + logger.error("Index {} not found", indexName); + listener.onFailure(new ResourceNotFoundException("Index " + indexName + "does not exist.")); + } else { + routeRequest(UpdateRuleAction.NAME, indexName, request, UpdateRuleResponse::new, listener); + } + } + } + /** * Creates the backing index if it does not exist, then runs the given success callback. * @param indexName the name of the index to create @@ -107,24 +127,31 @@ private void createIndex(String indexName, ActionListener l } /** - * Routes the CreateRuleRequest to the primary shard node for the given index. + * Routes the request to the primary shard node for the given index. * Executes locally if the current node is the primary. - * @param request the CreateRuleRequest - * @param listener listener to handle response or failure - * @param indexName the index name used to find the primary shard node + * @param actionName + * @param indexName + * @param request + * @param responseReader + * @param listener */ - private void routeRequest(CreateRuleRequest request, ActionListener listener, String indexName) { - Optional optionalPrimaryNode = getPrimaryShardNode(indexName); - if (optionalPrimaryNode.isEmpty()) { + private void routeRequest( + String actionName, + String indexName, + Request request, + Writeable.Reader responseReader, + ActionListener listener + ) { + Optional primaryNodeOpt = getPrimaryShardNode(indexName); + if (primaryNodeOpt.isEmpty()) { listener.onFailure(new IllegalStateException("Primary node for index [" + indexName + "] not found")); return; } - DiscoveryNode primaryNode = optionalPrimaryNode.get(); transportService.sendRequest( - primaryNode, - CreateRuleAction.NAME, + primaryNodeOpt.get(), + actionName, request, - new ActionListenerResponseHandler<>(listener, CreateRuleResponse::new) + new ActionListenerResponseHandler<>(listener, responseReader) ); } @@ -140,4 +167,12 @@ private Optional getPrimaryShardNode(String indexName) { .filter(ShardRouting::assignedToNode) .map(shard -> state.nodes().get(shard.currentNodeId())); } + + /** + * Checks whether the index is present + * @param indexName - the index name to check + */ + private boolean hasIndex(String indexName) { + return clusterService.state().metadata().hasIndex(indexName); + } } diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java index 27df5124d5a8b..a55e345fd56da 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/WorkloadGroupFeatureTypeTests.java @@ -6,166 +6,40 @@ * compatible open source license. */ -package org.opensearch.rule.service; +package org.opensearch.plugin.wlm.rule; -import org.apache.lucene.search.TotalHits; -import org.opensearch.ResourceNotFoundException; -import org.opensearch.action.search.SearchRequestBuilder; -import org.opensearch.action.search.SearchResponse; -import org.opensearch.cluster.ClusterState; -import org.opensearch.cluster.metadata.Metadata; import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.common.bytes.BytesArray; -import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.GetRuleRequest; -import org.opensearch.rule.GetRuleResponse; -import org.opensearch.rule.RuleEntityParser; -import org.opensearch.rule.RulePersistenceService; -import org.opensearch.rule.RuleQueryMapper; -import org.opensearch.rule.autotagging.Rule; -import org.opensearch.rule.utils.RuleTestUtils; -import org.opensearch.search.SearchHit; -import org.opensearch.search.SearchHits; +import org.opensearch.rule.RuleAttribute; +import org.opensearch.rule.autotagging.Attribute; +import org.opensearch.rule.autotagging.AutoTaggingRegistry; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.client.Client; -import java.util.HashMap; +import java.util.Map; -import org.mockito.ArgumentCaptor; - -import static org.opensearch.rule.XContentRuleParserTests.VALID_JSON; -import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@SuppressWarnings("unchecked") -public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { - - public static final int MAX_VALUES_PER_PAGE = 50; - - public void testGetRuleByIdSuccess() { - GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); - when(getRuleRequest.getId()).thenReturn(_ID_ONE); - when(getRuleRequest.getAttributeFilters()).thenReturn(new HashMap<>()); - QueryBuilder queryBuilder = mock(QueryBuilder.class); - RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); - RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); - ClusterService clusterService = mock(ClusterService.class); - Rule mockRule = mock(Rule.class); - - when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); - when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); - when(queryBuilder.filter(any())).thenReturn(queryBuilder); - - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - Client client = setUpMockClient(searchRequestBuilder); - RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( - TEST_INDEX_NAME, - client, - clusterService, - MAX_VALUES_PER_PAGE, - mockRuleEntityParser, - mockRuleQueryMapper, - null - ); +public class WorkloadGroupFeatureTypeTests extends OpenSearchTestCase { + WorkloadGroupFeatureType featureType = new WorkloadGroupFeatureType(new WorkloadGroupFeatureValueValidator(mock(ClusterService.class))); - SearchResponse searchResponse = mock(SearchResponse.class); - SearchHits searchHits = new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); - when(searchResponse.getHits()).thenReturn(searchHits); - SearchHit hit = searchHits.getHits()[0]; - hit.sourceRef(new BytesArray(VALID_JSON)); - - ActionListener listener = mock(ActionListener.class); - - doAnswer((invocation) -> { - ActionListener actionListener = invocation.getArgument(0); - actionListener.onResponse(searchResponse); - return null; - }).when(searchRequestBuilder).execute(any(ActionListener.class)); - - when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); - rulePersistenceService.getRule(getRuleRequest, listener); - - ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(GetRuleResponse.class); - verify(listener).onResponse(responseCaptor.capture()); - GetRuleResponse response = responseCaptor.getValue(); - assertEquals(response.getRules().size(), 1); + public void testGetName_returnsCorrectName() { + assertEquals("workload_group", featureType.getName()); } - public void testGetRuleByIdNotFound() { - GetRuleRequest getRuleRequest = mock(GetRuleRequest.class); - when(getRuleRequest.getId()).thenReturn(_ID_ONE); - QueryBuilder queryBuilder = mock(QueryBuilder.class); - RuleQueryMapper mockRuleQueryMapper = mock(RuleQueryMapper.class); - ClusterService clusterService = mock(ClusterService.class); - RuleEntityParser mockRuleEntityParser = mock(RuleEntityParser.class); - Rule mockRule = mock(Rule.class); - - when(mockRuleEntityParser.parse(anyString())).thenReturn(mockRule); - when(mockRuleQueryMapper.from(getRuleRequest)).thenReturn(queryBuilder); - when(queryBuilder.filter(any())).thenReturn(queryBuilder); - - SearchRequestBuilder searchRequestBuilder = mock(SearchRequestBuilder.class); - Client client = setUpMockClient(searchRequestBuilder); - - RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( - TEST_INDEX_NAME, - client, - clusterService, - MAX_VALUES_PER_PAGE, - mockRuleEntityParser, - mockRuleQueryMapper, - null - ); - - SearchResponse searchResponse = mock(SearchResponse.class); - when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f)); - - ActionListener listener = mock(ActionListener.class); - - doAnswer(invocationOnMock -> { - ActionListener actionListener = invocationOnMock.getArgument(0); - actionListener.onResponse(searchResponse); - return null; - }).when(searchRequestBuilder).execute(any(ActionListener.class)); - - when(getRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); - rulePersistenceService.getRule(getRuleRequest, listener); - - ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); - verify(listener).onFailure(exceptionCaptor.capture()); - Exception exception = exceptionCaptor.getValue(); - assertTrue(exception instanceof ResourceNotFoundException); + public void testMaxNumberOfValuesPerAttribute() { + assertEquals(10, featureType.getMaxNumberOfValuesPerAttribute()); } - private Client setUpMockClient(SearchRequestBuilder searchRequestBuilder) { - Client client = mock(Client.class); - ClusterService clusterService = mock(ClusterService.class); - ClusterState clusterState = mock(ClusterState.class); - Metadata metadata = mock(Metadata.class); - ThreadPool threadPool = mock(ThreadPool.class); - - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - when(client.threadPool()).thenReturn(threadPool); - when(threadPool.getThreadContext()).thenReturn(threadContext); - when(clusterService.state()).thenReturn(clusterState); - when(clusterState.metadata()).thenReturn(metadata); + public void testMaxCharLengthPerAttributeValue() { + assertEquals(100, featureType.getMaxCharLengthPerAttributeValue()); + } - when(client.prepareSearch(TEST_INDEX_NAME)).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setQuery(any(QueryBuilder.class))).thenReturn(searchRequestBuilder); - when(searchRequestBuilder.setSize(anyInt())).thenReturn(searchRequestBuilder); + public void testGetAllowedAttributesRegistry_containsIndexPattern() { + Map allowedAttributes = featureType.getAllowedAttributesRegistry(); + assertTrue(allowedAttributes.containsKey("index_pattern")); + assertEquals(RuleAttribute.INDEX_PATTERN, allowedAttributes.get("index_pattern")); + } - return client; + public void testRegisterFeatureType() { + AutoTaggingRegistry.registerFeatureType(featureType); } } From 4fea47c4b9d7ef8f55d92e88a1bd1ef4d78015f1 Mon Sep 17 00:00:00 2001 From: Ruirui Zhang Date: Mon, 9 Jun 2025 15:36:10 -0700 Subject: [PATCH 11/11] modify based on comments Signed-off-by: Ruirui Zhang --- .../rule/RulePersistenceService.java | 7 + .../org/opensearch/rule/RuleQueryMapper.java | 1 + .../opensearch/rule/RuleRoutingService.java | 4 + .../java/org/opensearch/rule/RuleUtils.java | 11 +- .../opensearch/rule/UpdatedRuleBuilder.java | 26 ---- .../rule/{ => action}/CreateRuleRequest.java | 2 +- .../rule/{ => action}/CreateRuleResponse.java | 11 +- .../rule/{ => action}/DeleteRuleRequest.java | 4 +- .../rule/{ => action}/GetRuleRequest.java | 4 +- .../rule/{ => action}/GetRuleResponse.java | 20 +-- .../rule/{ => action}/UpdateRuleRequest.java | 27 ++-- .../rule/{ => action}/UpdateRuleResponse.java | 21 +-- .../opensearch/rule/action/package-info.java | 12 ++ .../org/opensearch/rule/autotagging/Rule.java | 21 ++- .../rule/autotagging/RuleValidator.java | 40 ++--- .../IndexStoredRulePersistenceService.java | 44 +++--- .../storage/IndexBasedRuleQueryMapper.java | 6 +- .../rule/IndexStoredRuleUtilsTests.java | 3 +- .../org/opensearch/rule/RuleUtilsTests.java | 36 ++++- .../rule/XContentRuleParserTests.java | 5 +- .../rule/action/CreateRuleRequestTests.java | 1 - .../rule/action/CreateRuleResponseTests.java | 13 +- .../rule/action/DeleteRuleRequestTests.java | 1 - .../rule/action/GetRuleRequestTests.java | 70 +-------- .../rule/action/GetRuleResponseTests.java | 36 ++--- .../rule/action/UpdateRuleRequestTests.java | 11 +- .../rule/action/UpdateRuleResponseTests.java | 8 +- ...ndexStoredRulePersistenceServiceTests.java | 147 ++++++++++++------ .../opensearch/rule/utils/RuleTestUtils.java | 19 ++- .../rule/action/CreateRuleAction.java | 1 - .../opensearch/rule/action/GetRuleAction.java | 1 - .../action/TransportCreateRuleAction.java | 2 - .../action/TransportDeleteRuleAction.java | 1 - .../rule/action/TransportGetRuleAction.java | 2 - .../action/TransportUpdateRuleAction.java | 2 - .../rule/action/UpdateRuleAction.java | 1 - .../rule/rest/RestCreateRuleAction.java | 6 +- .../rule/rest/RestDeleteRuleAction.java | 8 +- .../rule/rest/RestGetRuleAction.java | 20 +-- .../rule/rest/RestUpdateRuleAction.java | 11 +- .../TransportCreateRuleActionTests.java | 2 - .../TransportDeleteRuleActionTests.java | 1 - .../action/TransportGetRuleActionTests.java | 2 +- .../rule/rest/RestDeleteRuleActionTests.java | 4 +- .../rule/rest/RestGetRuleActionTests.java | 2 +- .../rule/rest/RestUpdateRuleActionTests.java | 25 +++ .../plugin/wlm/WorkloadManagementPlugin.java | 4 +- .../rule/WorkloadGroupRuleRoutingService.java | 10 +- .../rule/sync/RefreshBasedSyncMechanism.java | 6 +- .../sync/RefreshBasedSyncMechanismTests.java | 22 +-- 50 files changed, 355 insertions(+), 389 deletions(-) delete mode 100644 modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java rename modules/autotagging-commons/common/src/main/java/org/opensearch/rule/{ => action}/CreateRuleRequest.java (98%) rename modules/autotagging-commons/common/src/main/java/org/opensearch/rule/{ => action}/CreateRuleResponse.java (86%) rename modules/autotagging-commons/common/src/main/java/org/opensearch/rule/{ => action}/DeleteRuleRequest.java (97%) rename modules/autotagging-commons/common/src/main/java/org/opensearch/rule/{ => action}/GetRuleRequest.java (96%) rename modules/autotagging-commons/common/src/main/java/org/opensearch/rule/{ => action}/GetRuleResponse.java (80%) rename modules/autotagging-commons/common/src/main/java/org/opensearch/rule/{ => action}/UpdateRuleRequest.java (81%) rename modules/autotagging-commons/common/src/main/java/org/opensearch/rule/{ => action}/UpdateRuleResponse.java (81%) create mode 100644 modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/package-info.java create mode 100644 modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestUpdateRuleActionTests.java diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java index d956a1e9602dd..da0396fc57d27 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RulePersistenceService.java @@ -10,6 +10,13 @@ import org.opensearch.action.support.clustermanager.AcknowledgedResponse; import org.opensearch.core.action.ActionListener; +import org.opensearch.rule.action.CreateRuleRequest; +import org.opensearch.rule.action.CreateRuleResponse; +import org.opensearch.rule.action.DeleteRuleRequest; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; /** * Interface for a service that handles rule persistence CRUD operations. diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleQueryMapper.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleQueryMapper.java index 62dce30d04109..f0ee052790b4b 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleQueryMapper.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleQueryMapper.java @@ -9,6 +9,7 @@ package org.opensearch.rule; import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.rule.action.GetRuleRequest; /** * This interface is responsible for creating query objects which storage layer can use diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleRoutingService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleRoutingService.java index a84a5c717e756..f3e0e6febf428 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleRoutingService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleRoutingService.java @@ -9,6 +9,10 @@ package org.opensearch.rule; import org.opensearch.core.action.ActionListener; +import org.opensearch.rule.action.CreateRuleRequest; +import org.opensearch.rule.action.CreateRuleResponse; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; /** * Interface that handles rule routing logic diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java index 4d5bbb618b4e0..cbf7eb8ce6ec7 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/RuleUtils.java @@ -9,6 +9,7 @@ package org.opensearch.rule; import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.rule.action.UpdateRuleRequest; import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule; @@ -16,6 +17,7 @@ import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -60,12 +62,11 @@ public static String computeRuleHash( * between the current rule and the one being checked. * * @param rule The rule to be validated against ruleMap. - * @param ruleMap This map contains existing rules to be checked + * @param ruleList This list contains existing rules to be checked */ - public static Optional getDuplicateRuleId(Rule rule, Map ruleMap) { + public static Optional getDuplicateRuleId(Rule rule, List ruleList) { Map> targetAttributeMap = rule.getAttributeMap(); - for (Map.Entry entry : ruleMap.entrySet()) { - Rule currRule = entry.getValue(); + for (Rule currRule : ruleList) { Map> existingAttributeMap = currRule.getAttributeMap(); if (rule.getFeatureType() != currRule.getFeatureType() || targetAttributeMap.size() != existingAttributeMap.size()) { @@ -81,7 +82,7 @@ public static Optional getDuplicateRuleId(Rule rule, Map r } } if (allAttributesIntersect) { - return Optional.of(entry.getKey()); + return Optional.of(currRule.getId()); } } return Optional.empty(); diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java deleted file mode 100644 index ae686f8f13ab2..0000000000000 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdatedRuleBuilder.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rule; - -import org.opensearch.common.annotation.ExperimentalApi; -import org.opensearch.rule.autotagging.Rule; - -/** - * A functional interface for updating an existing {@link Rule} using an {@link UpdateRuleRequest}. - * @opensearch.experimental - */ -@ExperimentalApi -public interface UpdatedRuleBuilder { - /** - * Applies updates to an existing rule based on the provided update request. - * @param existingRule the rule to update - * @param request the update request containing new values - */ - Rule apply(Rule existingRule, UpdateRuleRequest request); -} diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleRequest.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/CreateRuleRequest.java similarity index 98% rename from modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleRequest.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/CreateRuleRequest.java index 7963357b893d9..aaf05e698a506 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleRequest.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/CreateRuleRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule; +package org.opensearch.rule.action; import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleResponse.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java similarity index 86% rename from modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleResponse.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java index 14c57f2fb0bd4..60001038bdadc 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/CreateRuleResponse.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/CreateRuleResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule; +package org.opensearch.rule.action; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.StreamInput; @@ -22,7 +22,7 @@ * Response for the create API for Rule * Example response: * { - * "_id":"wi6VApYBoX5wstmtU_8l", + * "id":"wi6VApYBoX5wstmtU_8l", * "description":"description1", * "index_pattern":["log*", "uvent*"], * "workload_group":"poOiU851RwyLYvV5lbvv5w", @@ -31,16 +31,13 @@ * @opensearch.experimental */ public class CreateRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final String _id; private final Rule rule; /** * contructor for CreateRuleResponse - * @param id - the id for the rule created * @param rule - the rule created */ - public CreateRuleResponse(String id, final Rule rule) { - this._id = id; + public CreateRuleResponse(final Rule rule) { this.rule = rule; } @@ -49,13 +46,11 @@ public CreateRuleResponse(String id, final Rule rule) { * @param in - The {@link StreamInput} instance to read from. */ public CreateRuleResponse(StreamInput in) throws IOException { - _id = in.readString(); rule = new Rule(in); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeString(_id); rule.writeTo(out); } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DeleteRuleRequest.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/DeleteRuleRequest.java similarity index 97% rename from modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DeleteRuleRequest.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/DeleteRuleRequest.java index b60755f051be0..de36e3646f5cd 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/DeleteRuleRequest.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/DeleteRuleRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule; +package org.opensearch.rule.action; import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; @@ -80,7 +80,7 @@ public String getRuleId() { * * @return The feature type. */ - public FeatureType getFeatureType() { + FeatureType getFeatureType() { return featureType; } } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleRequest.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/GetRuleRequest.java similarity index 96% rename from modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleRequest.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/GetRuleRequest.java index 630a329688b2b..e6da349b046c7 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleRequest.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/GetRuleRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule; +package org.opensearch.rule.action; import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; @@ -67,7 +67,7 @@ public GetRuleRequest(StreamInput in) throws IOException { @Override public ActionRequestValidationException validate() { if (RuleValidator.isEmpty(id)) { - throw new IllegalArgumentException(Rule._ID_STRING + " cannot be empty."); + throw new IllegalArgumentException(Rule.ID_STRING + " cannot be empty."); } if (RuleValidator.isEmpty(searchAfter)) { throw new IllegalArgumentException("search_after cannot be empty."); diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/GetRuleResponse.java similarity index 80% rename from modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/GetRuleResponse.java index e0f22e7c075ff..8928c0fa0d082 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/GetRuleResponse.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/GetRuleResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule; +package org.opensearch.rule.action; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.action.ActionResponse; @@ -18,7 +18,7 @@ import org.opensearch.rule.autotagging.Rule; import java.io.IOException; -import java.util.Map; +import java.util.List; /** * Response for the get API for Rule. @@ -26,7 +26,7 @@ * { * "rules": [ * { - * "_id": "z1MJApUB0zgMcDmz-UQq", + * "id": "z1MJApUB0zgMcDmz-UQq", * "description": "Rule for tagging workload_group_id to index123" * "index_pattern": ["index123"], * "workload_group": "workload_group_id", @@ -40,7 +40,7 @@ */ @ExperimentalApi public class GetRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final Map rules; + private final List rules; private final String searchAfter; /** @@ -48,7 +48,7 @@ public class GetRuleResponse extends ActionResponse implements ToXContent, ToXCo * @param rules - Rules get from the request * @param searchAfter - The sort value used for pagination. */ - public GetRuleResponse(final Map rules, String searchAfter) { + public GetRuleResponse(final List rules, String searchAfter) { this.rules = rules; this.searchAfter = searchAfter; } @@ -58,12 +58,12 @@ public GetRuleResponse(final Map rules, String searchAfter) { * @param in - The {@link StreamInput} instance to read from. */ public GetRuleResponse(StreamInput in) throws IOException { - this(in.readMap(StreamInput::readString, Rule::new), in.readOptionalString()); + this(in.readList(Rule::new), in.readOptionalString()); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeMap(rules, StreamOutput::writeString, (outStream, rule) -> rule.writeTo(outStream)); + out.writeList(rules); out.writeOptionalString(searchAfter); } @@ -71,8 +71,8 @@ public void writeTo(StreamOutput out) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); builder.startArray("rules"); - for (Map.Entry entry : rules.entrySet()) { - entry.getValue().toXContent(builder, params); + for (Rule rule : rules) { + rule.toXContent(builder, params); } builder.endArray(); if (searchAfter != null && !searchAfter.isEmpty()) { @@ -85,7 +85,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws /** * rules getter */ - public Map getRules() { + public List getRules() { return rules; } } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java similarity index 81% rename from modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java index d03dc135d3028..824102c40da6a 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleRequest.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/UpdateRuleRequest.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule; +package org.opensearch.rule.action; import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; @@ -15,11 +15,9 @@ import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.FeatureType; -import org.opensearch.rule.autotagging.RuleValidator; import java.io.IOException; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; @@ -36,7 +34,7 @@ */ @ExperimentalApi public class UpdateRuleRequest extends ActionRequest { - private final String _id; + private final String id; private final String description; private final Map> attributeMap; private final String featureValue; @@ -44,20 +42,20 @@ public class UpdateRuleRequest extends ActionRequest { /** * constructor for UpdateRuleRequest - * @param _id - the rule id to update + * @param id - the rule id to update * @param description - the description to update * @param attributeMap - the attribute values to update * @param featureValue - the feature value to update * @param featureType - the feature type for the rule */ public UpdateRuleRequest( - String _id, + String id, String description, Map> attributeMap, String featureValue, FeatureType featureType ) { - this._id = _id; + this.id = id; this.description = description; this.attributeMap = attributeMap; this.featureValue = featureValue; @@ -70,7 +68,7 @@ public UpdateRuleRequest( */ public UpdateRuleRequest(StreamInput in) throws IOException { super(in); - _id = in.readString(); + id = in.readString(); description = in.readOptionalString(); featureType = FeatureType.from(in); attributeMap = in.readMap(i -> Attribute.from(i, featureType), i -> new HashSet<>(i.readStringList())); @@ -79,20 +77,13 @@ public UpdateRuleRequest(StreamInput in) throws IOException { @Override public ActionRequestValidationException validate() { - RuleValidator validator = new RuleValidator(_id, description, attributeMap, featureValue, null, featureType); - List errors = validator.validateUpdatingRuleParams(); - if (!errors.isEmpty()) { - ActionRequestValidationException validationException = new ActionRequestValidationException(); - validationException.addValidationErrors(errors); - return validationException; - } return null; } @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); - out.writeString(_id); + out.writeString(id); out.writeOptionalString(description); featureType.writeTo(out); out.writeMap(attributeMap, (o, a) -> a.writeTo(o), StreamOutput::writeStringCollection); @@ -102,8 +93,8 @@ public void writeTo(StreamOutput out) throws IOException { /** * id getter */ - public String get_id() { - return _id; + public String getId() { + return id; } /** diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java similarity index 81% rename from modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java rename to modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java index ee35fa60b95f7..8ba8109db7546 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/UpdateRuleResponse.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/UpdateRuleResponse.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rule; +package org.opensearch.rule.action; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.core.action.ActionResponse; @@ -23,7 +23,7 @@ * Response for the update API for Rule * Example response: * { - * _id": "z1MJApUB0zgMcDmz-UQq", + * id": "z1MJApUB0zgMcDmz-UQq", * "description": "Rule for tagging workload_group_id to index123" * "index_pattern": ["index123"], * "workload_group": "workload_group_id", @@ -33,16 +33,13 @@ */ @ExperimentalApi public class UpdateRuleResponse extends ActionResponse implements ToXContent, ToXContentObject { - private final String _id; private final Rule rule; /** * constructor for UpdateRuleResponse - * @param _id - rule id updated * @param rule - the updated rule */ - public UpdateRuleResponse(String _id, final Rule rule) { - this._id = _id; + public UpdateRuleResponse(final Rule rule) { this.rule = rule; } @@ -51,12 +48,11 @@ public UpdateRuleResponse(String _id, final Rule rule) { * @param in - The {@link StreamInput} instance to read from. */ public UpdateRuleResponse(StreamInput in) throws IOException { - this(in.readString(), new Rule(in)); + this(new Rule(in)); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeString(_id); rule.writeTo(out); } @@ -65,17 +61,10 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return rule.toXContent(builder, params); } - /** - * id getter - */ - public String get_id() { - return _id; - } - /** * rule getter */ - public Rule getRule() { + Rule getRule() { return rule; } } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/package-info.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/package-info.java new file mode 100644 index 0000000000000..5da0779401d77 --- /dev/null +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/action/package-info.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** + * This package contains action classes for rule lifecycle + */ +package org.opensearch.rule.action; diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java index 4791b07979c1d..ae1cebdda99d5 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/Rule.java @@ -30,7 +30,7 @@ * 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==", + * "id": "fwehf8302582mglfio349==", * "description": "Assign Query Group for Index Logs123" * "index_pattern": ["logs123"], * "workload_group": "dev_workload_group_id", @@ -49,7 +49,7 @@ public class Rule implements Writeable, ToXContentObject { /** * id field */ - public static final String _ID_STRING = "_id"; + public static final String ID_STRING = "id"; /** * description field */ @@ -174,7 +174,7 @@ public Map> getAttributeMap() { @Override public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException { builder.startObject(); - builder.field("id", id); + builder.field(ID_STRING, id); builder.field(DESCRIPTION_STRING, description); for (Map.Entry> entry : attributeMap.entrySet()) { builder.array(entry.getKey().getName(), entry.getValue().toArray(new String[0])); @@ -248,7 +248,7 @@ public static Builder fromXContent(XContentParser parser, FeatureType featureTyp if (token == XContentParser.Token.FIELD_NAME) { fieldName = parser.currentName(); } else if (token.isValue()) { - if (fieldName.equals(_ID_STRING)) { + if (fieldName.equals(ID_STRING)) { builder.id(parser.text()); } else if (fieldName.equals(DESCRIPTION_STRING)) { builder.description(parser.text()); @@ -296,6 +296,18 @@ public Builder id(String id) { return this; } + /** + * sets the id based on description, featureType, attributeMap, and featureValue + * @return + */ + public Builder id() { + if (description == null || featureType == null || attributeMap == null || featureValue == null) { + throw new IllegalStateException("Cannot compute ID: required fields are missing."); + } + this.id = RuleUtils.computeRuleHash(description, featureType, attributeMap, featureValue); + return this; + } + /** * sets the description * @param description @@ -351,7 +363,6 @@ public Builder updatedAt(String updatedAt) { * @return */ public Rule build() { - id = RuleUtils.computeRuleHash(description, featureType, attributeMap, featureValue); return new Rule(id, description, attributeMap, featureType, featureValue, updatedAt); } diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java index fb464046c67f5..dd4eafaceab35 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/autotagging/RuleValidator.java @@ -78,31 +78,6 @@ public void validate() { } } - /** - * validates the updated rule object fields - */ - public List validateUpdatingRuleParams() { - List errorMessages = new ArrayList<>(); - if (isEmpty(description)) { - errorMessages.add("Rule description can't be empty"); - } - if (isEmpty(featureValue)) { - errorMessages.add("Rule featureValue can't be empty"); - } - FeatureValueValidator featureValueValidator = featureType.getFeatureValueValidator(); - if (featureValue != null && !featureValue.isEmpty() && featureValueValidator != null) { - try { - featureValueValidator.validate(featureValue); - } catch (Exception e) { - errorMessages.add(e.getMessage()); - } - } - if (attributeMap != null && !attributeMap.isEmpty()) { - errorMessages.addAll(validateAttributeMap()); - } - return errorMessages; - } - private List validateStringFields() { List errors = new ArrayList<>(); if (isNullOrEmpty(id)) { @@ -161,14 +136,14 @@ private List validateAttributeMap() { Set attributeValues = entry.getValue(); errors.addAll(validateAttributeExistence(attribute)); errors.addAll(validateMaxAttributeValues(attribute, attributeValues)); - errors.addAll(validateAttributeValuesLength(attributeValues)); + errors.addAll(validateAttributeValuesList(attributeValues)); } } return errors; } private List validateAttributeExistence(Attribute attribute) { - if (featureType.getAttributeFromName(attribute.getName()) == null) { + if (!featureType.isValidAttribute(attribute)) { return List.of(attribute.getName() + " is not a valid attribute within the " + featureType.getName() + " feature."); } return new ArrayList<>(); @@ -196,14 +171,19 @@ private List validateMaxAttributeValues(Attribute attribute, Set return errors; } - private List validateAttributeValuesLength(Set attributeValues) { + private List validateAttributeValuesList(Set attributeValues) { int maxValueLength = featureType.getMaxCharLengthPerAttributeValue(); + List errors = new ArrayList<>(); for (String attributeValue : attributeValues) { if (attributeValue.isEmpty() || attributeValue.length() > maxValueLength) { - return List.of("Attribute value [" + attributeValue + "] is invalid (empty or exceeds " + maxValueLength + " characters)"); + errors.add("Attribute value [" + attributeValue + "] is invalid (empty or exceeds " + maxValueLength + " characters)"); + } + int asteriskCount = (int) attributeValue.chars().filter(c -> c == '*').count(); + if (asteriskCount > 1 || (asteriskCount == 1 && !attributeValue.endsWith("*"))) { + errors.add("Attribute value [" + attributeValue + "] is invalid (only one '*' is allowed and it must appear at the end)"); } } - return new ArrayList<>(); + return errors; } @Override diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java index fe56ac63b1fca..d7a6f396bed74 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/service/IndexStoredRulePersistenceService.java @@ -14,7 +14,6 @@ import org.opensearch.action.DocWriteResponse; import org.opensearch.action.delete.DeleteRequest; import org.opensearch.action.index.IndexRequest; -import org.opensearch.action.index.IndexResponse; import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; @@ -26,18 +25,17 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.index.engine.DocumentMissingException; import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.CreateRuleRequest; -import org.opensearch.rule.CreateRuleResponse; -import org.opensearch.rule.DeleteRuleRequest; -import org.opensearch.rule.GetRuleRequest; -import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; import org.opensearch.rule.RuleUtils; -import org.opensearch.rule.UpdateRuleRequest; -import org.opensearch.rule.UpdateRuleResponse; -import org.opensearch.rule.UpdatedRuleBuilder; +import org.opensearch.rule.action.CreateRuleRequest; +import org.opensearch.rule.action.CreateRuleResponse; +import org.opensearch.rule.action.DeleteRuleRequest; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule; import org.opensearch.search.SearchHit; @@ -47,11 +45,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; - -import static org.opensearch.rule.autotagging.Rule._ID_STRING; /** * This class encapsulates the logic to manage the lifecycle of rules at index level @@ -67,7 +61,6 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService private final int maxRulesPerPage; private final RuleEntityParser parser; private final RuleQueryMapper queryBuilder; - private final UpdatedRuleBuilder updatedRuleBuilder; private static final Logger logger = LogManager.getLogger(IndexStoredRulePersistenceService.class); /** @@ -79,7 +72,6 @@ public class IndexStoredRulePersistenceService implements RulePersistenceService * @param maxRulesPerPage - The maximum number of rules that can be returned in a single get request. * @param parser * @param queryBuilder - * @param updatedRuleBuilder */ public IndexStoredRulePersistenceService( String indexName, @@ -87,8 +79,7 @@ public IndexStoredRulePersistenceService( ClusterService clusterService, int maxRulesPerPage, RuleEntityParser parser, - RuleQueryMapper queryBuilder, - UpdatedRuleBuilder updatedRuleBuilder + RuleQueryMapper queryBuilder ) { this.indexName = indexName; this.client = client; @@ -96,7 +87,6 @@ public IndexStoredRulePersistenceService( this.maxRulesPerPage = maxRulesPerPage; this.parser = parser; this.queryBuilder = queryBuilder; - this.updatedRuleBuilder = updatedRuleBuilder; } /** @@ -151,8 +141,8 @@ private void persistRule(Rule rule, ActionListener listener) try { IndexRequest indexRequest = new IndexRequest(indexName).id(rule.getId()) .source(rule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS)); - IndexResponse indexResponse = client.index(indexRequest).get(); - listener.onResponse(new CreateRuleResponse(indexResponse.getId(), rule)); + client.index(indexRequest).get(); + listener.onResponse(new CreateRuleResponse(rule)); } catch (Exception e) { logger.error("Error saving rule to index: {}", indexName); listener.onFailure(new RuntimeException("Failed to save rule to index.")); @@ -182,7 +172,7 @@ private void getRuleFromIndex(String id, QueryBuilder queryBuilder, String searc try { SearchRequestBuilder searchRequest = client.prepareSearch(indexName).setQuery(queryBuilder).setSize(maxRulesPerPage); if (searchAfter != null) { - searchRequest.addSort(_ID_STRING, SortOrder.ASC).searchAfter(new Object[] { searchAfter }); + searchRequest.addSort("_id", SortOrder.ASC).searchAfter(new Object[] { searchAfter }); } SearchResponse searchResponse = searchRequest.get(); @@ -210,9 +200,9 @@ private static boolean hasNoResults(String id, ActionListener l * @param listener - ActionListener for GetRuleResponse */ void handleGetRuleResponse(List hits, ActionListener listener) { - Map ruleMap = hits.stream().collect(Collectors.toMap(SearchHit::getId, hit -> parser.parse(hit.getSourceAsString()))); + List ruleList = hits.stream().map(hit -> parser.parse(hit.getSourceAsString())).toList(); String nextSearchAfter = hits.isEmpty() || hits.size() < maxRulesPerPage ? null : hits.get(hits.size() - 1).getId(); - listener.onResponse(new GetRuleResponse(ruleMap, nextSearchAfter)); + listener.onResponse(new GetRuleResponse(ruleList, nextSearchAfter)); } @Override @@ -243,7 +233,7 @@ public void deleteRule(DeleteRuleRequest request, ActionListener listener) { - String ruleId = request.get_id(); + String ruleId = request.getId(); FeatureType featureType = request.getFeatureType(); try (ThreadContext.StoredContext context = stashContext()) { QueryBuilder query = queryBuilder.from(new GetRuleRequest(ruleId, new HashMap<>(), null, featureType)); @@ -254,7 +244,9 @@ public void onResponse(GetRuleResponse getRuleResponse) { listener.onFailure(new ResourceNotFoundException("Rule with ID " + ruleId + " not found.")); return; } - Rule updatedRule = updatedRuleBuilder.apply(getRuleResponse.getRules().get(ruleId), request); + List ruleList = getRuleResponse.getRules(); + assert ruleList.size() == 1; + Rule updatedRule = RuleUtils.composeUpdatedRule(ruleList.get(0), request, featureType); validateNoDuplicateRule( updatedRule, ActionListener.wrap(unused -> persistUpdatedRule(ruleId, updatedRule, listener), listener::onFailure) @@ -281,7 +273,7 @@ private void persistUpdatedRule(String ruleId, Rule updatedRule, ActionListener< updatedRule.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) ); client.update(updateRequest).get(); - listener.onResponse(new UpdateRuleResponse(ruleId, updatedRule)); + listener.onResponse(new UpdateRuleResponse(updatedRule)); } catch (Exception e) { logger.error("Error updating rule in index: {}", indexName); listener.onFailure(new RuntimeException("Failed to update rule to index.")); diff --git a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java index 96b77e0b4b643..11b0ad5e564fb 100644 --- a/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java +++ b/modules/autotagging-commons/common/src/main/java/org/opensearch/rule/storage/IndexBasedRuleQueryMapper.java @@ -12,15 +12,13 @@ import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilder; import org.opensearch.index.query.QueryBuilders; -import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.RuleQueryMapper; +import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.autotagging.Attribute; import java.util.Map; import java.util.Set; -import static org.opensearch.rule.autotagging.Rule._ID_STRING; - /** * This class is used to build opensearch index based query object */ @@ -40,7 +38,7 @@ public QueryBuilder from(GetRuleRequest request) { boolQuery.filter(QueryBuilders.existsQuery(request.getFeatureType().getName())); if (id != null) { - return boolQuery.must(QueryBuilders.termQuery(_ID_STRING, id)); + return boolQuery.must(QueryBuilders.termQuery("_id", id)); } for (Map.Entry> entry : attributeFilters.entrySet()) { Attribute attribute = entry.getKey(); diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java index 46aaf6770b17c..555ab59b71250 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/IndexStoredRuleUtilsTests.java @@ -10,6 +10,7 @@ import org.opensearch.index.query.BoolQueryBuilder; import org.opensearch.index.query.QueryBuilder; +import org.opensearch.rule.action.GetRuleRequest; import org.opensearch.rule.storage.IndexBasedRuleQueryMapper; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; @@ -41,7 +42,7 @@ public void testBuildGetRuleQuery_WithAttributes() { ); assertNotNull(queryBuilder); BoolQueryBuilder query = (BoolQueryBuilder) queryBuilder; - assertTrue(query.must().size() == 1); + assertEquals(1, query.must().size()); assertTrue(query.toString().contains(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE.getName())); assertTrue(query.toString().contains(RuleTestUtils.ATTRIBUTE_VALUE_ONE)); } diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleUtilsTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleUtilsTests.java index 6b0d26528f8b8..5c330be57f008 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleUtilsTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/RuleUtilsTests.java @@ -8,11 +8,13 @@ package org.opensearch.rule; +import org.opensearch.rule.action.UpdateRuleRequest; import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.autotagging.RuleTests; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -20,28 +22,31 @@ import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_TWO; import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_TWO; import static org.opensearch.rule.utils.RuleTestUtils.FEATURE_VALUE_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.FEATURE_VALUE_TWO; +import static org.opensearch.rule.utils.RuleTestUtils.MockRuleAttributes; import static org.opensearch.rule.utils.RuleTestUtils.TIMESTAMP_ONE; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.utils.RuleTestUtils._ID_TWO; import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; import static org.opensearch.rule.utils.RuleTestUtils.ruleTwo; public class RuleUtilsTests extends OpenSearchTestCase { public void testDuplicateRuleFound() { - Optional result = RuleUtils.getDuplicateRuleId(ruleOne, Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo)); + Optional result = RuleUtils.getDuplicateRuleId(ruleOne, List.of(ruleOne, ruleTwo)); assertTrue(result.isPresent()); assertEquals(_ID_ONE, result.get()); } public void testNoAttributeIntersection() { - Optional result = RuleUtils.getDuplicateRuleId(ruleOne, Map.of(_ID_TWO, ruleTwo)); + Optional result = RuleUtils.getDuplicateRuleId(ruleOne, List.of(ruleTwo)); assertTrue(result.isEmpty()); } public void testAttributeSizeMismatch() { Rule testRule = Rule.builder() + .id(_ID_ONE) .description(DESCRIPTION_ONE) .featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE) .featureValue(FEATURE_VALUE_ONE) @@ -55,12 +60,13 @@ public void testAttributeSizeMismatch() { ) .updatedAt(TIMESTAMP_ONE) .build(); - Optional result = RuleUtils.getDuplicateRuleId(ruleOne, Map.of(_ID_TWO, testRule)); + Optional result = RuleUtils.getDuplicateRuleId(ruleOne, List.of(testRule)); assertTrue(result.isEmpty()); } public void testPartialAttributeValueIntersection() { Rule ruleWithPartialOverlap = Rule.builder() + .id(_ID_ONE) .description(DESCRIPTION_ONE) .featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE) .featureValue(FEATURE_VALUE_ONE) @@ -68,13 +74,14 @@ public void testPartialAttributeValueIntersection() { .updatedAt(TIMESTAMP_ONE) .build(); - Optional result = RuleUtils.getDuplicateRuleId(ruleWithPartialOverlap, Map.of(_ID_ONE, ruleOne)); + Optional result = RuleUtils.getDuplicateRuleId(ruleWithPartialOverlap, List.of(ruleOne)); assertTrue(result.isPresent()); assertEquals(_ID_ONE, result.get()); } public void testDifferentFeatureTypes() { Rule differentFeatureTypeRule = Rule.builder() + .id(_ID_ONE) .description(DESCRIPTION_ONE) .featureType(RuleTests.TestFeatureType.INSTANCE) .featureValue(FEATURE_VALUE_ONE) @@ -82,7 +89,24 @@ public void testDifferentFeatureTypes() { .updatedAt(TIMESTAMP_ONE) .build(); - Optional result = RuleUtils.getDuplicateRuleId(differentFeatureTypeRule, Map.of(_ID_ONE, ruleOne)); + Optional result = RuleUtils.getDuplicateRuleId(differentFeatureTypeRule, List.of(ruleOne)); assertTrue(result.isEmpty()); } + + public void testComposeUpdateAllFields() { + UpdateRuleRequest request = new UpdateRuleRequest( + _ID_ONE, + DESCRIPTION_TWO, + Map.of(MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, Set.of(ATTRIBUTE_VALUE_TWO)), + FEATURE_VALUE_TWO, + RuleTestUtils.MockRuleFeatureType.INSTANCE + ); + + Rule updatedRule = RuleUtils.composeUpdatedRule(ruleOne, request, RuleTestUtils.MockRuleFeatureType.INSTANCE); + + assertEquals(_ID_ONE, updatedRule.getId()); + assertEquals(DESCRIPTION_TWO, updatedRule.getDescription()); + assertEquals(FEATURE_VALUE_TWO, updatedRule.getFeatureValue()); + assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, updatedRule.getFeatureType()); + } } diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java index 67b7cb8f54c53..b4bb1c5232927 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/XContentRuleParserTests.java @@ -17,15 +17,18 @@ import java.time.Instant; import java.util.Locale; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; + public class XContentRuleParserTests extends OpenSearchTestCase { public static final String VALID_JSON = String.format(Locale.ROOT, """ { + "id": "%s", "description": "%s", "mock_feature_type": "feature value", "mock_attribute_one": ["attribute_value_one", "attribute_value_two"], "updated_at": "%s" } - """, RuleTestUtils.DESCRIPTION_ONE, Instant.now().toString()); + """, _ID_ONE, RuleTestUtils.DESCRIPTION_ONE, Instant.now().toString()); private static final String INVALID_JSON = """ { diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleRequestTests.java index 7804714c37dcc..4ebdf296cf1c0 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleRequestTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleRequestTests.java @@ -10,7 +10,6 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.CreateRuleRequest; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleResponseTests.java index 050e1f7ff963b..eb813c9b12ca3 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleResponseTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/CreateRuleResponseTests.java @@ -13,15 +13,12 @@ import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.rule.CreateRuleResponse; import org.opensearch.rule.autotagging.Rule; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; -import java.util.Map; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRules; +import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRule; import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; import static org.mockito.Mockito.mock; @@ -31,14 +28,14 @@ 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); + CreateRuleResponse response = new CreateRuleResponse(ruleOne); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); CreateRuleResponse otherResponse = new CreateRuleResponse(streamInput); Rule responseRule = response.getRule(); Rule otherResponseRule = otherResponse.getRule(); - assertEqualRules(Map.of(_ID_ONE, responseRule), Map.of(_ID_ONE, otherResponseRule), false); + assertEqualRule(responseRule, otherResponseRule, false); } /** @@ -46,10 +43,10 @@ public void testSerialization() throws IOException { */ public void testToXContentCreateRule() throws IOException { XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - CreateRuleResponse response = new CreateRuleResponse(_ID_ONE, ruleOne); + CreateRuleResponse response = new CreateRuleResponse(ruleOne); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" - + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + + " \"id\" : \"e9f35a73-ece2-3fa7-857e-7c1af877fc75\",\n" + " \"description\" : \"description_1\",\n" + " \"mock_attribute_one\" : [\n" + " \"mock_attribute_one\"\n" diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/DeleteRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/DeleteRuleRequestTests.java index 55213a245b5ad..bddaaad1f0927 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/DeleteRuleRequestTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/DeleteRuleRequestTests.java @@ -10,7 +10,6 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.DeleteRuleRequest; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java index f8321a38765fb..7a17c26f4818f 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleRequestTests.java @@ -10,16 +10,15 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.GetRuleRequest; -import org.opensearch.rule.autotagging.Attribute; -import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; import java.util.HashMap; -import java.util.Map; -import java.util.Set; + +import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; +import static org.opensearch.rule.utils.RuleTestUtils.SEARCH_AFTER; +import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; public class GetRuleRequestTests extends OpenSearchTestCase { /** @@ -64,65 +63,4 @@ public void testValidate() { request = new GetRuleRequest(_ID_ONE, ATTRIBUTE_MAP, "", RuleTestUtils.MockRuleFeatureType.INSTANCE); assertThrows(IllegalArgumentException.class, request::validate); } - - public static final String _ID_ONE = "id_1"; - public static final String SEARCH_AFTER = "search_after"; - public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; - public static final String FEATURE_VALUE_ONE = "feature_value_one"; - public static final String FEATURE_VALUE_TWO = "feature_value_two"; - public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; - public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two"; - public static final String DESCRIPTION_ONE = "description_1"; - public static final String DESCRIPTION_TWO = "description_2"; - public static final String TIMESTAMP_ONE = "2024-01-26T08:58:57.558Z"; - public static final String TIMESTAMP_TWO = "2023-01-26T08:58:57.558Z"; - public static final Map> ATTRIBUTE_MAP = Map.of( - RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE, - Set.of(ATTRIBUTE_VALUE_ONE) - ); - - public static final Rule ruleOne = Rule.builder() - .id(_ID_ONE) - .description(DESCRIPTION_ONE) - .featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_ONE) - .attributeMap(ATTRIBUTE_MAP) - .updatedAt(TIMESTAMP_ONE) - .build(); - - public static final Rule ruleTwo = Rule.builder() - .id(_ID_TWO) - .description(DESCRIPTION_TWO) - .featureType(RuleTestUtils.MockRuleFeatureType.INSTANCE) - .featureValue(FEATURE_VALUE_TWO) - .attributeMap(Map.of(RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_TWO, Set.of(ATTRIBUTE_VALUE_TWO))) - .updatedAt(TIMESTAMP_TWO) - .build(); - - public static Map ruleMap() { - return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); - } - - public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { - assertEquals(mapOne.size(), mapTwo.size()); - for (Map.Entry entry : mapOne.entrySet()) { - String id = entry.getKey(); - assertTrue(mapTwo.containsKey(id)); - Rule one = mapOne.get(id); - Rule two = mapTwo.get(id); - assertEqualRule(one, two, ruleUpdated); - } - } - - public static void assertEqualRule(Rule one, Rule two, boolean ruleUpdated) { - if (ruleUpdated) { - assertEquals(one.getDescription(), two.getDescription()); - assertEquals(one.getFeatureType(), two.getFeatureType()); - assertEquals(one.getFeatureValue(), two.getFeatureValue()); - assertEquals(one.getAttributeMap(), two.getAttributeMap()); - assertEquals(one.getAttributeMap(), two.getAttributeMap()); - } else { - assertEquals(one, two); - } - } } diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java index d6bd0baf562ca..10817d8b9e899 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/GetRuleResponseTests.java @@ -13,19 +13,17 @@ import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.autotagging.Rule; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import static org.opensearch.rule.utils.RuleTestUtils.SEARCH_AFTER; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRules; -import static org.opensearch.rule.utils.RuleTestUtils.ruleMap; import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; +import static org.opensearch.rule.utils.RuleTestUtils.ruleTwo; import static org.mockito.Mockito.mock; public class GetRuleResponseTests extends OpenSearchTestCase { @@ -33,10 +31,10 @@ public class GetRuleResponseTests extends OpenSearchTestCase { * Test case to verify the serialization and deserialization of GetRuleResponse */ public void testSerializationSingleRule() throws IOException { - Map map = new HashMap<>(); - map.put(_ID_ONE, ruleOne); - GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), null); - assertEquals(response.getRules(), map); + List list = new ArrayList<>(); + list.add(ruleOne); + GetRuleResponse response = new GetRuleResponse(list, null); + assertEquals(response.getRules(), list); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); @@ -50,8 +48,10 @@ public void testSerializationSingleRule() throws IOException { * Test case to verify the serialization and deserialization of GetRuleResponse when the result contains multiple rules */ public void testSerializationMultipleRule() throws IOException { - GetRuleResponse response = new GetRuleResponse(ruleMap(), SEARCH_AFTER); - assertEquals(response.getRules(), ruleMap()); + List list = new ArrayList<>(); + list.add(ruleOne); + list.add(ruleTwo); + GetRuleResponse response = new GetRuleResponse(list, SEARCH_AFTER); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); @@ -66,9 +66,9 @@ public void testSerializationMultipleRule() throws IOException { * Test case to verify the serialization and deserialization of GetRuleResponse when the result is empty */ public void testSerializationNull() throws IOException { - Map map = new HashMap<>(); - GetRuleResponse response = new GetRuleResponse(map, SEARCH_AFTER); - assertEquals(response.getRules(), map); + List list = new ArrayList<>(); + GetRuleResponse response = new GetRuleResponse(list, SEARCH_AFTER); + assertEquals(response.getRules(), list); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); @@ -82,15 +82,13 @@ public void testSerializationNull() throws IOException { * Test case to verify the toXContent of GetRuleResponse */ public void testToXContentGetSingleRule() throws IOException { - Map map = new HashMap<>(); - map.put(_ID_ONE, ruleOne); - GetRuleResponse response = new GetRuleResponse(Map.of(_ID_ONE, ruleOne), SEARCH_AFTER); + GetRuleResponse response = new GetRuleResponse(List.of(ruleOne), SEARCH_AFTER); XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" + " \"rules\" : [\n" + " {\n" - + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + + " \"id\" : \"e9f35a73-ece2-3fa7-857e-7c1af877fc75\",\n" + " \"description\" : \"description_1\",\n" + " \"mock_attribute_one\" : [\n" + " \"mock_attribute_one\"\n" @@ -111,7 +109,7 @@ public void testToXContentGetSingleRule() throws IOException { */ public void testToXContentGetZeroRule() throws IOException { XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); - GetRuleResponse otherResponse = new GetRuleResponse(new HashMap<>(), null); + GetRuleResponse otherResponse = new GetRuleResponse(new ArrayList<>(), null); String actual = otherResponse.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" + " \"rules\" : [ ]\n" + "}"; assertEquals(expected, actual); diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java index 9d2418f0f5dca..8cb851fd308d7 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleRequestTests.java @@ -10,7 +10,6 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.rule.UpdateRuleRequest; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.test.OpenSearchTestCase; @@ -34,14 +33,14 @@ public void testSerialization() throws IOException { FEATURE_VALUE_ONE, RuleTestUtils.MockRuleFeatureType.INSTANCE ); - assertEquals(_ID_ONE, request.get_id()); + assertEquals(_ID_ONE, request.getId()); assertNull(request.validate()); assertEquals(RuleTestUtils.MockRuleFeatureType.INSTANCE, request.getFeatureType()); BytesStreamOutput out = new BytesStreamOutput(); request.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); UpdateRuleRequest otherRequest = new UpdateRuleRequest(streamInput); - assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getId(), otherRequest.getId()); assertEquals(request.getAttributeMap(), otherRequest.getAttributeMap()); assertEquals(request.getDescription(), otherRequest.getDescription()); assertEquals(request.getFeatureValue(), otherRequest.getFeatureValue()); @@ -58,7 +57,7 @@ public void testSerializationWithNull() throws IOException { request.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); UpdateRuleRequest otherRequest = new UpdateRuleRequest(streamInput); - assertEquals(request.get_id(), otherRequest.get_id()); + assertEquals(request.getId(), otherRequest.getId()); assertEquals(request.getAttributeMap(), otherRequest.getAttributeMap()); assertEquals(request.getDescription(), otherRequest.getDescription()); assertEquals(request.getFeatureValue(), otherRequest.getFeatureValue()); @@ -72,8 +71,8 @@ public void testValidate() { FEATURE_VALUE_ONE, RuleTestUtils.MockRuleFeatureType.INSTANCE ); - assertNotNull(request.validate()); + assertNull(request.validate()); request = new UpdateRuleRequest(_ID_ONE, DESCRIPTION_ONE, ATTRIBUTE_MAP, "", RuleTestUtils.MockRuleFeatureType.INSTANCE); - assertNotNull(request.validate()); + assertNull(request.validate()); } } diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java index ce3dfda25189c..4825b28a7c728 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/action/UpdateRuleResponseTests.java @@ -13,12 +13,10 @@ import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.rule.UpdateRuleResponse; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; -import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; import static org.opensearch.rule.utils.RuleTestUtils.assertEqualRule; import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; import static org.mockito.Mockito.mock; @@ -28,7 +26,7 @@ public class UpdateRuleResponseTests extends OpenSearchTestCase { * Test case to verify the serialization and deserialization of UpdateRuleResponse */ public void testSerialization() throws IOException { - UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); + UpdateRuleResponse response = new UpdateRuleResponse(ruleOne); BytesStreamOutput out = new BytesStreamOutput(); response.writeTo(out); StreamInput streamInput = out.bytes().streamInput(); @@ -40,11 +38,11 @@ public void testSerialization() throws IOException { * Test case to verify the toXContent of GetRuleResponse */ public void testToXContent() throws IOException { - UpdateRuleResponse response = new UpdateRuleResponse(_ID_ONE, ruleOne); + UpdateRuleResponse response = new UpdateRuleResponse(ruleOne); XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint(); String actual = response.toXContent(builder, mock(ToXContent.Params.class)).toString(); String expected = "{\n" - + " \"_id\" : \"AgfUO5Ja9yfvhdONlYi3TQ==\",\n" + + " \"id\" : \"e9f35a73-ece2-3fa7-857e-7c1af877fc75\",\n" + " \"description\" : \"description_1\",\n" + " \"mock_attribute_one\" : [\n" + " \"mock_attribute_one\"\n" diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java index 17ab9ae73de60..e348d104cfe27 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/service/IndexStoredRulePersistenceServiceTests.java @@ -17,8 +17,6 @@ import org.opensearch.action.search.SearchRequestBuilder; import org.opensearch.action.search.SearchResponse; import org.opensearch.action.support.clustermanager.AcknowledgedResponse; -import org.opensearch.action.update.UpdateRequest; -import org.opensearch.action.update.UpdateResponse; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.Metadata; import org.opensearch.cluster.service.ClusterService; @@ -30,17 +28,17 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.index.engine.DocumentMissingException; import org.opensearch.index.query.QueryBuilder; -import org.opensearch.rule.CreateRuleRequest; -import org.opensearch.rule.CreateRuleResponse; -import org.opensearch.rule.DeleteRuleRequest; -import org.opensearch.rule.GetRuleRequest; -import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleQueryMapper; -import org.opensearch.rule.UpdateRuleRequest; -import org.opensearch.rule.UpdateRuleResponse; -import org.opensearch.rule.UpdatedRuleBuilder; +import org.opensearch.rule.RuleUtils; +import org.opensearch.rule.action.CreateRuleRequest; +import org.opensearch.rule.action.CreateRuleResponse; +import org.opensearch.rule.action.DeleteRuleRequest; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; import org.opensearch.rule.autotagging.Rule; import org.opensearch.rule.utils.RuleTestUtils; import org.opensearch.search.SearchHit; @@ -60,7 +58,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -69,11 +66,12 @@ import static org.opensearch.rule.XContentRuleParserTests.VALID_JSON; import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_MAP; import static org.opensearch.rule.utils.RuleTestUtils.ATTRIBUTE_VALUE_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_ONE; +import static org.opensearch.rule.utils.RuleTestUtils.DESCRIPTION_TWO; +import static org.opensearch.rule.utils.RuleTestUtils.FEATURE_VALUE_ONE; import static org.opensearch.rule.utils.RuleTestUtils.MockRuleAttributes.MOCK_RULE_ATTRIBUTE_ONE; import static org.opensearch.rule.utils.RuleTestUtils.TEST_INDEX_NAME; import static org.opensearch.rule.utils.RuleTestUtils._ID_ONE; -import static org.opensearch.rule.utils.RuleTestUtils.ruleOne; -import static org.opensearch.rule.utils.RuleTestUtils.ruleTwo; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.any; @@ -86,12 +84,10 @@ public class IndexStoredRulePersistenceServiceTests extends OpenSearchTestCase { private static final int MAX_VALUES_PER_PAGE = 50; - private Client client; private ClusterService clusterService; private RuleQueryMapper ruleQueryMapper; private RuleEntityParser ruleEntityParser; - private UpdatedRuleBuilder updatedRuleBuilder; private SearchRequestBuilder searchRequestBuilder; private RulePersistenceService rulePersistenceService; private QueryBuilder queryBuilder; @@ -114,7 +110,6 @@ public void setUp() throws Exception { when(queryBuilder.filter(any())).thenReturn(queryBuilder); when(ruleQueryMapper.from(any(GetRuleRequest.class))).thenReturn(queryBuilder); when(ruleEntityParser.parse(anyString())).thenReturn(rule); - updatedRuleBuilder = mock(UpdatedRuleBuilder.class); rulePersistenceService = new IndexStoredRulePersistenceService( TEST_INDEX_NAME, @@ -122,8 +117,7 @@ public void setUp() throws Exception { clusterService, MAX_VALUES_PER_PAGE, ruleEntityParser, - ruleQueryMapper, - updatedRuleBuilder + ruleQueryMapper ); } @@ -167,8 +161,7 @@ public void testConcurrentCreateDuplicateRules() throws InterruptedException { clusterService, MAX_VALUES_PER_PAGE, ruleEntityParser, - ruleQueryMapper, - updatedRuleBuilder + ruleQueryMapper ) { @Override public void createRule(CreateRuleRequest request, ActionListener listener) { @@ -180,7 +173,7 @@ public void onResponse(Void unused) { synchronized (storedAttributeMaps) { storedAttributeMaps.add(MOCK_RULE_ATTRIBUTE_ONE.getName()); } - listener.onResponse(new CreateRuleResponse("fake-id", rule)); + listener.onResponse(new CreateRuleResponse(rule)); latch.countDown(); } @@ -365,45 +358,105 @@ public void testDeleteRule_notFound() { verify(listener).onFailure(any(ResourceNotFoundException.class)); } - public void testUpdateRule_SuccessfulUpdate() throws Exception { - UpdateRuleRequest request = mock(UpdateRuleRequest.class); - when(request.get_id()).thenReturn(_ID_ONE); - when(updatedRuleBuilder.apply(ruleOne, request)).thenReturn(ruleTwo); + public void testConcurrentUpdateDuplicateRules() throws InterruptedException { + int threadCount = 10; + CountDownLatch latch = new CountDownLatch(threadCount); + ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); + Set storedAttributeMaps = ConcurrentHashMap.newKeySet(); - SearchHit searchHit = new SearchHit(1, _ID_ONE, null, null); - searchHit.sourceRef(new BytesArray(VALID_JSON)); - SearchHits searchHits = new SearchHits(new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f); - SearchResponse searchResponse = mock(SearchResponse.class); - when(searchResponse.getHits()).thenReturn(searchHits); - when(searchRequestBuilder.get()).thenReturn(searchResponse); - when(ruleEntityParser.parse(anyString())).thenReturn(ruleOne); + UpdateRuleRequest updateRuleRequest = mock(UpdateRuleRequest.class); + when(updateRuleRequest.getFeatureValue()).thenReturn(FEATURE_VALUE_ONE); + when(updateRuleRequest.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + when(updateRuleRequest.getAttributeMap()).thenReturn(ATTRIBUTE_MAP); + when(updateRuleRequest.getDescription()).thenReturn(DESCRIPTION_TWO); - UpdateResponse updateResponse = mock(UpdateResponse.class); - ActionFuture future = mock(ActionFuture.class); - when(future.get()).thenReturn(updateResponse); - when(client.update(any(UpdateRequest.class))).thenReturn(future); + Rule originalRule = mock(Rule.class); + when(originalRule.getId()).thenReturn(_ID_ONE); + when(originalRule.getAttributeMap()).thenReturn(ATTRIBUTE_MAP); + when(originalRule.getFeatureType()).thenReturn(RuleTestUtils.MockRuleFeatureType.INSTANCE); + when(originalRule.getFeatureValue()).thenReturn(FEATURE_VALUE_ONE); + when(originalRule.getDescription()).thenReturn(DESCRIPTION_ONE); - AtomicBoolean onResponseCalled = new AtomicBoolean(false); - rulePersistenceService.updateRule(request, new ActionListener<>() { + RulePersistenceService rulePersistenceService = new IndexStoredRulePersistenceService( + TEST_INDEX_NAME, + client, + clusterService, + MAX_VALUES_PER_PAGE, + ruleEntityParser, + ruleQueryMapper + ) { @Override - public void onResponse(UpdateRuleResponse updateRuleResponse) { - assertEquals(_ID_ONE, updateRuleResponse.get_id()); - assertEquals(ruleTwo, updateRuleResponse.getRule()); - onResponseCalled.set(true); + public void updateRule(UpdateRuleRequest request, ActionListener listener) { + singleThreadExecutor.execute(() -> { + Rule updatedRule = RuleUtils.composeUpdatedRule(originalRule, request, request.getFeatureType()); + validateNoDuplicateRule(updatedRule, new ActionListener() { + @Override + public void onResponse(Void unused) { + listener.onResponse(new UpdateRuleResponse(updatedRule)); + latch.countDown(); + } + + @Override + public void onFailure(Exception e) { + listener.onFailure(e); + latch.countDown(); + } + }); + }); + } + + public void validateNoDuplicateRule(Rule rule, ActionListener listener) { + synchronized (storedAttributeMaps) { + String key = rule.getAttributeMap().toString(); + if (storedAttributeMaps.contains(key)) { + listener.onFailure(new IllegalArgumentException("Duplicate rule exists with attribute map")); + } else { + storedAttributeMaps.add(key); + listener.onResponse(null); + } + } + } + }; + + class TestListener implements ActionListener { + final AtomicInteger successCount = new AtomicInteger(); + final AtomicInteger failureCount = new AtomicInteger(); + final List failures = Collections.synchronizedList(new ArrayList<>()); + + @Override + public void onResponse(UpdateRuleResponse response) { + successCount.incrementAndGet(); } @Override public void onFailure(Exception e) { - fail(); + failureCount.incrementAndGet(); + failures.add(e); } - }); + } + + TestListener testListener = new TestListener(); + + for (int i = 0; i < threadCount; i++) { + new Thread(() -> rulePersistenceService.updateRule(updateRuleRequest, testListener)).start(); + } + + boolean completed = latch.await(10, TimeUnit.SECONDS); + singleThreadExecutor.shutdown(); + + assertTrue("All update calls should complete", completed); + assertEquals(1, testListener.successCount.get()); + assertEquals(threadCount - 1, testListener.failureCount.get()); - assertTrue(onResponseCalled.get()); + for (Exception e : testListener.failures) { + assertTrue(e instanceof IllegalArgumentException); + assertTrue(e.getMessage().contains("Duplicate rule")); + } } public void testUpdateRule_RuleNotFound() { UpdateRuleRequest request = mock(UpdateRuleRequest.class); - when(request.get_id()).thenReturn(_ID_ONE); + when(request.getId()).thenReturn(_ID_ONE); SearchHits emptyHits = new SearchHits(new SearchHit[] {}, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 1.0f); SearchResponse searchResponse = mock(SearchResponse.class); @@ -429,7 +482,7 @@ public void onFailure(Exception e) { public void testUpdateRule_ParseFailure() { UpdateRuleRequest request = mock(UpdateRuleRequest.class); - when(request.get_id()).thenReturn(_ID_ONE); + when(request.getId()).thenReturn(_ID_ONE); SearchHit searchHit = new SearchHit(1, _ID_ONE, null, null); searchHit.sourceRef(new BytesArray(VALID_JSON)); diff --git a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java index 1c10d327a863f..b0a93fa369147 100644 --- a/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java +++ b/modules/autotagging-commons/common/src/test/java/org/opensearch/rule/utils/RuleTestUtils.java @@ -13,14 +13,15 @@ import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule; +import java.util.Comparator; +import java.util.List; import java.util.Map; import java.util.Set; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; public class RuleTestUtils { - public static final String _ID_ONE = "AgfUO5Ja9yfvhdONlYi3TQ=="; + public static final String _ID_ONE = "e9f35a73-ece2-3fa7-857e-7c1af877fc75"; public static final String ATTRIBUTE_VALUE_ONE = "mock_attribute_one"; public static final String ATTRIBUTE_VALUE_TWO = "mock_attribute_two"; public static final String DESCRIPTION_ONE = "description_1"; @@ -29,7 +30,7 @@ public class RuleTestUtils { public static final String INVALID_ATTRIBUTE = "invalid_attribute"; public static final String SEARCH_AFTER = "search_after"; - public static final String _ID_TWO = "G5iIq84j7eK1qIAAAAIH53=1"; + public static final String _ID_TWO = "b55aa7e6-5aae-38e8-bf43-803599996ffe"; public static final String FEATURE_VALUE_ONE = "feature_value_one"; public static final String FEATURE_VALUE_TWO = "feature_value_two"; public static final String DESCRIPTION_TWO = "description_2"; @@ -63,14 +64,12 @@ public static Map ruleMap() { return Map.of(_ID_ONE, ruleOne, _ID_TWO, ruleTwo); } - public static void assertEqualRules(Map mapOne, Map mapTwo, boolean ruleUpdated) { + public static void assertEqualRules(List mapOne, List 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); + mapOne.sort(Comparator.comparing(Rule::getId)); + mapTwo.sort(Comparator.comparing(Rule::getId)); + for (int i = 0; i < mapOne.size(); i++) { + assertEqualRule(mapOne.get(i), mapTwo.get(i), ruleUpdated); } } diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleAction.java index fe7b424b31ca4..b61dd272366e0 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/CreateRuleAction.java @@ -9,7 +9,6 @@ package org.opensearch.rule.action; import org.opensearch.action.ActionType; -import org.opensearch.rule.CreateRuleResponse; /** * Action type for creating a Rule diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleAction.java index aa795d3aa4f72..49369e927aa01 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/GetRuleAction.java @@ -9,7 +9,6 @@ package org.opensearch.rule.action; import org.opensearch.action.ActionType; -import org.opensearch.rule.GetRuleResponse; /** * Action type for getting Rules diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportCreateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportCreateRuleAction.java index f808cf7427cbc..9a4bff59ed2a1 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportCreateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportCreateRuleAction.java @@ -12,8 +12,6 @@ import org.opensearch.action.support.TransportAction; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; -import org.opensearch.rule.CreateRuleRequest; -import org.opensearch.rule.CreateRuleResponse; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.rule.RuleRoutingServiceRegistry; diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportDeleteRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportDeleteRuleAction.java index 8bedffe0e89fc..34df52c28bba9 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportDeleteRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportDeleteRuleAction.java @@ -13,7 +13,6 @@ import org.opensearch.action.support.clustermanager.AcknowledgedResponse; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; -import org.opensearch.rule.DeleteRuleRequest; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.tasks.Task; diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java index 29115a38060d9..fdd73b3690d8e 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportGetRuleAction.java @@ -12,8 +12,6 @@ import org.opensearch.action.support.HandledTransportAction; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; -import org.opensearch.rule.GetRuleRequest; -import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.tasks.Task; diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java index 427e639fdd19b..d0f2043d1e196 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/TransportUpdateRuleAction.java @@ -15,8 +15,6 @@ import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.rule.RuleRoutingServiceRegistry; -import org.opensearch.rule.UpdateRuleRequest; -import org.opensearch.rule.UpdateRuleResponse; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportChannel; diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleAction.java index 5888e4e96b06f..8793b258e0a3d 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/action/UpdateRuleAction.java @@ -9,7 +9,6 @@ package org.opensearch.rule.action; import org.opensearch.action.ActionType; -import org.opensearch.rule.UpdateRuleResponse; /** * Action type for updating Rules diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestCreateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestCreateRuleAction.java index 4a8254924db2e..684691e97aac4 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestCreateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestCreateRuleAction.java @@ -18,9 +18,9 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.rule.CreateRuleRequest; -import org.opensearch.rule.CreateRuleResponse; import org.opensearch.rule.action.CreateRuleAction; +import org.opensearch.rule.action.CreateRuleRequest; +import org.opensearch.rule.action.CreateRuleResponse; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule.Builder; import org.opensearch.transport.client.node.NodeClient; @@ -57,7 +57,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli final FeatureType featureType = FeatureType.from(request.param(FEATURE_TYPE)); try (XContentParser parser = request.contentParser()) { Builder builder = Builder.fromXContent(parser, featureType); - CreateRuleRequest createRuleRequest = new CreateRuleRequest(builder.updatedAt(Instant.now().toString()).build()); + CreateRuleRequest createRuleRequest = new CreateRuleRequest(builder.updatedAt(Instant.now().toString()).id().build()); return channel -> client.execute(CreateRuleAction.INSTANCE, createRuleRequest, createRuleResponse(channel)); } } diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestDeleteRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestDeleteRuleAction.java index fffd344c46e8b..89ce2b9143f70 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestDeleteRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestDeleteRuleAction.java @@ -18,15 +18,15 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.rule.DeleteRuleRequest; import org.opensearch.rule.action.DeleteRuleAction; +import org.opensearch.rule.action.DeleteRuleRequest; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.transport.client.node.NodeClient; import java.util.List; import static org.opensearch.rest.RestRequest.Method.DELETE; -import static org.opensearch.rule.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.autotagging.Rule.ID_STRING; import static org.opensearch.rule.rest.RestGetRuleAction.FEATURE_TYPE; /** @@ -47,12 +47,12 @@ public String getName() { @Override public List routes() { - return List.of(new RestHandler.Route(DELETE, "_rules/{featureType}/{_id}")); + return List.of(new RestHandler.Route(DELETE, "_rules/{featureType}/{id}")); } @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - final String ruleId = request.param(_ID_STRING); + final String ruleId = request.param(ID_STRING); FeatureType featureType = FeatureType.from(request.param(FEATURE_TYPE)); DeleteRuleRequest deleteRuleRequest = new DeleteRuleRequest(ruleId, featureType); return channel -> client.execute(DeleteRuleAction.INSTANCE, deleteRuleRequest, deleteRuleResponse(channel)); diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java index f1bd56927c41f..49bdb750b70ee 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestGetRuleAction.java @@ -18,14 +18,13 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.rule.GetRuleRequest; -import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.action.GetRuleAction; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.transport.client.node.NodeClient; -import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -34,7 +33,7 @@ import java.util.Set; import static org.opensearch.rest.RestRequest.Method.GET; -import static org.opensearch.rule.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.autotagging.Rule.ID_STRING; /** * Rest action to get a Rule @@ -63,11 +62,11 @@ public String getName() { @Override public List routes() { - return List.of(new RestHandler.Route(GET, "_rules/{featureType}/"), new RestHandler.Route(GET, "_rules/{featureType}/{_id}")); + return List.of(new RestHandler.Route(GET, "_rules/{featureType}/"), new RestHandler.Route(GET, "_rules/{featureType}/{id}")); } @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { final Map> attributeFilters = new HashMap<>(); if (!request.hasParam(FEATURE_TYPE)) { @@ -75,11 +74,8 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli } final FeatureType featureType = FeatureType.from(request.param(FEATURE_TYPE)); - final List requestParams = request.params() - .keySet() - .stream() - .filter(key -> !key.equals(FEATURE_TYPE) && !key.equals(_ID_STRING) && !key.equals(SEARCH_AFTER_STRING)) - .toList(); + final Set excludedKeys = Set.of(FEATURE_TYPE, ID_STRING, SEARCH_AFTER_STRING, "pretty"); + final List requestParams = request.params().keySet().stream().filter(key -> !excludedKeys.contains(key)).toList(); for (String attributeName : requestParams) { Attribute attribute = featureType.getAttributeFromName(attributeName); @@ -89,7 +85,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli attributeFilters.put(attribute, parseAttributeValues(request.param(attributeName), attributeName, featureType)); } final GetRuleRequest getRuleRequest = new GetRuleRequest( - request.param(_ID_STRING), + request.param(ID_STRING), attributeFilters, request.param(SEARCH_AFTER_STRING), featureType diff --git a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java index c33430fa98a0a..98d24655323fe 100644 --- a/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java +++ b/modules/autotagging-commons/src/main/java/org/opensearch/rule/rest/RestUpdateRuleAction.java @@ -19,9 +19,9 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; -import org.opensearch.rule.UpdateRuleRequest; -import org.opensearch.rule.UpdateRuleResponse; import org.opensearch.rule.action.UpdateRuleAction; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule.Builder; import org.opensearch.transport.client.node.NodeClient; @@ -29,9 +29,8 @@ import java.io.IOException; import java.util.List; -import static org.opensearch.rest.RestRequest.Method.POST; import static org.opensearch.rest.RestRequest.Method.PUT; -import static org.opensearch.rule.autotagging.Rule._ID_STRING; +import static org.opensearch.rule.autotagging.Rule.ID_STRING; import static org.opensearch.rule.rest.RestGetRuleAction.FEATURE_TYPE; /** @@ -52,7 +51,7 @@ public String getName() { @Override public List routes() { - return List.of(new RestHandler.Route(PUT, "_rules/{featureType}/{_id}"), new RestHandler.Route(POST, "_rules/{featureType}/{_id}")); + return List.of(new RestHandler.Route(PUT, "_rules/{featureType}/{id}")); } @Override @@ -61,7 +60,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli try (XContentParser parser = request.contentParser()) { Builder builder = Builder.fromXContent(parser, featureType); UpdateRuleRequest updateRuleRequest = new UpdateRuleRequest( - request.param(_ID_STRING), + request.param(ID_STRING), builder.getDescription(), builder.getAttributeMap(), builder.getFeatureValue(), diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportCreateRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportCreateRuleActionTests.java index fa413044c5efc..072e2278bea14 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportCreateRuleActionTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportCreateRuleActionTests.java @@ -10,8 +10,6 @@ import org.opensearch.action.support.ActionFilters; import org.opensearch.core.action.ActionListener; -import org.opensearch.rule.CreateRuleRequest; -import org.opensearch.rule.CreateRuleResponse; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.rule.RuleRoutingService; import org.opensearch.rule.RuleRoutingServiceRegistry; diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportDeleteRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportDeleteRuleActionTests.java index c236362cc449e..d7dd1e4d26c85 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportDeleteRuleActionTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportDeleteRuleActionTests.java @@ -9,7 +9,6 @@ package org.opensearch.rule.action; import org.opensearch.action.support.ActionFilters; -import org.opensearch.rule.DeleteRuleRequest; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.test.OpenSearchTestCase; diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java index cf69cf858f162..009cabc18ccbd 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/action/TransportGetRuleActionTests.java @@ -9,7 +9,6 @@ package org.opensearch.rule.action; import org.opensearch.action.support.ActionFilters; -import org.opensearch.rule.GetRuleRequest; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RulePersistenceServiceRegistry; import org.opensearch.test.OpenSearchTestCase; @@ -45,5 +44,6 @@ public void testExecute() { sut = new TransportGetRuleAction(transportService, threadPool, actionFilters, rulePersistenceServiceRegistry); sut.doExecute(null, getRuleRequest, null); verify(rulePersistenceService, times(1)).getRule(any(), any()); + mockExecutor.shutdownNow(); } } diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestDeleteRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestDeleteRuleActionTests.java index 4cbaa7ca76420..2997af9e71807 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestDeleteRuleActionTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestDeleteRuleActionTests.java @@ -20,8 +20,6 @@ public void testGetName() { public void testRoutes() { var routes = action.routes(); assertEquals(1, routes.size()); - assertTrue( - routes.stream().anyMatch(r -> r.getMethod().name().equals("DELETE") && r.getPath().equals("_rules/{featureType}/{_id}")) - ); + assertTrue(routes.stream().anyMatch(r -> r.getMethod().name().equals("DELETE") && r.getPath().equals("_rules/{featureType}/{id}"))); } } diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestGetRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestGetRuleActionTests.java index 726924593e2b8..3c5e434c2735e 100644 --- a/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestGetRuleActionTests.java +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestGetRuleActionTests.java @@ -21,6 +21,6 @@ public void testRoutes() { var routes = action.routes(); assertEquals(2, routes.size()); assertTrue(routes.stream().anyMatch(r -> r.getPath().equals("_rules/{featureType}/"))); - assertTrue(routes.stream().anyMatch(r -> r.getPath().equals("_rules/{featureType}/{_id}"))); + assertTrue(routes.stream().anyMatch(r -> r.getPath().equals("_rules/{featureType}/{id}"))); } } diff --git a/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestUpdateRuleActionTests.java b/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestUpdateRuleActionTests.java new file mode 100644 index 0000000000000..2f1d4d8d9f61a --- /dev/null +++ b/modules/autotagging-commons/src/test/java/org/opensearch/rule/rest/RestUpdateRuleActionTests.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rule.rest; + +import org.opensearch.test.OpenSearchTestCase; + +public class RestUpdateRuleActionTests extends OpenSearchTestCase { + RestUpdateRuleAction action = new RestUpdateRuleAction();; + + public void testGetName() { + assertEquals("update_rule", action.getName()); + } + + public void testRoutes() { + var routes = action.routes(); + assertEquals(1, routes.size()); + assertTrue(routes.stream().anyMatch(r -> r.getPath().equals("_rules/{featureType}/{id}"))); + } +} 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 e7b11fa1d8f30..9135b12c9cfaf 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 @@ -56,7 +56,6 @@ import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; import org.opensearch.rule.RuleRoutingService; -import org.opensearch.rule.RuleUtils; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.service.IndexStoredRulePersistenceService; import org.opensearch.rule.spi.RuleFrameworkExtension; @@ -126,8 +125,7 @@ public Collection createComponents( clusterService, MAX_RULES_PER_PAGE, parser, - new IndexBasedRuleQueryMapper(), - (existingRule, request) -> RuleUtils.composeUpdatedRule(existingRule, request, featureType) + new IndexBasedRuleQueryMapper() ); ruleRoutingService = new WorkloadGroupRuleRoutingService(client, clusterService); diff --git a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupRuleRoutingService.java b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupRuleRoutingService.java index 3436f8e852ef3..300fe1fcd2b19 100644 --- a/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupRuleRoutingService.java +++ b/plugins/workload-management/src/main/java/org/opensearch/plugin/wlm/rule/WorkloadGroupRuleRoutingService.java @@ -27,13 +27,13 @@ import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.Writeable; import org.opensearch.plugin.wlm.WorkloadManagementPlugin; -import org.opensearch.rule.CreateRuleRequest; -import org.opensearch.rule.CreateRuleResponse; import org.opensearch.rule.RuleRoutingService; -import org.opensearch.rule.UpdateRuleRequest; -import org.opensearch.rule.UpdateRuleResponse; import org.opensearch.rule.action.CreateRuleAction; +import org.opensearch.rule.action.CreateRuleRequest; +import org.opensearch.rule.action.CreateRuleResponse; import org.opensearch.rule.action.UpdateRuleAction; +import org.opensearch.rule.action.UpdateRuleRequest; +import org.opensearch.rule.action.UpdateRuleResponse; import org.opensearch.transport.TransportService; import org.opensearch.transport.client.Client; @@ -109,7 +109,7 @@ public void handleUpdateRuleRequest(UpdateRuleRequest request, ActionListener() { @Override public void onResponse(GetRuleResponse response) { - final Set newRules = new HashSet<>(response.getRules().values()); + final Set newRules = new HashSet<>(response.getRules()); ruleEventClassifier.setPreviousRules(lastRunIndexedRules); ruleEventClassifier.getRuleEvents(newRules).forEach(RuleEvent::process); diff --git a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/sync/RefreshBasedSyncMechanismTests.java b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/sync/RefreshBasedSyncMechanismTests.java index b54f70ea9cf84..cca14c8778a87 100644 --- a/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/sync/RefreshBasedSyncMechanismTests.java +++ b/plugins/workload-management/src/test/java/org/opensearch/plugin/wlm/rule/sync/RefreshBasedSyncMechanismTests.java @@ -14,11 +14,11 @@ import org.opensearch.plugin.wlm.AutoTaggingActionFilterTests; import org.opensearch.plugin.wlm.WorkloadManagementPlugin; import org.opensearch.plugin.wlm.rule.sync.detect.RuleEventClassifier; -import org.opensearch.rule.GetRuleRequest; -import org.opensearch.rule.GetRuleResponse; import org.opensearch.rule.InMemoryRuleProcessingService; import org.opensearch.rule.RuleEntityParser; import org.opensearch.rule.RulePersistenceService; +import org.opensearch.rule.action.GetRuleRequest; +import org.opensearch.rule.action.GetRuleResponse; import org.opensearch.rule.autotagging.Attribute; import org.opensearch.rule.autotagging.FeatureType; import org.opensearch.rule.autotagging.Rule; @@ -33,12 +33,12 @@ import org.opensearch.wlm.WorkloadManagementSettings; import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import static org.opensearch.plugin.wlm.rule.sync.detect.RuleEventClassifierTests.getRandomRule; import static org.mockito.ArgumentMatchers.any; @@ -166,7 +166,7 @@ public void test_doRun_RefreshesRules() { .id("test_id") .build(); - when(getRuleResponse.getRules()).thenReturn(Map.of("test_id", rule)); + when(getRuleResponse.getRules()).thenReturn(List.of(rule)); doAnswer(invocation -> { ActionListener listener = invocation.getArgument(1); listener.onResponse(getRuleResponse); @@ -181,10 +181,10 @@ public void test_doRun_RefreshesRules() { @SuppressWarnings("unchecked") public void test_doRun_RefreshesRulesAndCheckInMemoryView() { GetRuleResponse getRuleResponse = mock(GetRuleResponse.class); - Map existingRules = new HashMap<>(); + List existingRules = new ArrayList<>(); for (int i = 0; i < 10; i++) { final String randomRuleId = randomAlphaOfLength(5); - existingRules.put(randomRuleId, getRandomRule(randomRuleId)); + existingRules.add(getRandomRule(randomRuleId)); } when(getRuleResponse.getRules()).thenReturn(existingRules); @@ -197,16 +197,16 @@ public void test_doRun_RefreshesRulesAndCheckInMemoryView() { // marks the first run of service sut.doRun(); - Set previousRules = new HashSet<>(existingRules.values()); + Set previousRules = new HashSet<>(existingRules); Set newRules = new HashSet<>(); int deletionEventCount = 10; // Mark some deletions - for (Map.Entry rule : existingRules.entrySet()) { + for (Rule rule : existingRules) { if (randomBoolean()) { deletionEventCount--; - newRules.add(rule.getValue()); + newRules.add(rule); } } @@ -224,7 +224,7 @@ public void test_doRun_RefreshesRulesAndCheckInMemoryView() { } } - when(getRuleResponse.getRules()).thenReturn(newRules.stream().collect(Collectors.toMap(Rule::getId, rule -> rule))); + when(getRuleResponse.getRules()).thenReturn(new ArrayList<>(newRules)); doAnswer(invocation -> { ActionListener listener = invocation.getArgument(1); listener.onResponse(getRuleResponse);