From dc3018d60a86c678135ef170ed5a9bc35538f944 Mon Sep 17 00:00:00 2001 From: jzonthemtn Date: Sat, 1 Jun 2024 09:12:03 -0400 Subject: [PATCH 1/8] #176 Sending queries to Data Prepper. --- README.md | 21 ++- build.gradle | 4 + docker-compose.yaml | 3 +- licenses/httpclient-4.5.14.jar.sha1 | 1 + licenses/httpclient-LICENSE.txt | 177 ++++++++++++++++++ licenses/httpclient-NOTICE.txt | 5 + licenses/httpcore-4.4.16.jar.sha1 | 1 + licenses/httpcore-LICENSE.txt | 177 ++++++++++++++++++ licenses/httpcore-NOTICE.txt | 5 + scripts/get-indexed-queries.sh | 5 + scripts/search.sh | 16 ++ .../org/opensearch/ubi/UbiActionFilter.java | 65 ++++++- .../java/org/opensearch/ubi/UbiPlugin.java | 10 +- .../java/org/opensearch/ubi/UbiSettings.java | 41 ++++ 14 files changed, 519 insertions(+), 12 deletions(-) create mode 100644 licenses/httpclient-4.5.14.jar.sha1 create mode 100644 licenses/httpclient-LICENSE.txt create mode 100644 licenses/httpclient-NOTICE.txt create mode 100644 licenses/httpcore-4.4.16.jar.sha1 create mode 100644 licenses/httpcore-LICENSE.txt create mode 100644 licenses/httpcore-NOTICE.txt create mode 100644 scripts/get-indexed-queries.sh create mode 100755 scripts/search.sh create mode 100644 src/main/java/org/opensearch/ubi/UbiSettings.java diff --git a/README.md b/README.md index b062415..c1380f0 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,7 @@ For details on the JSON Schema used by UBI to send and receive queries and event ## Useful Commands -* Get the indexed queries: `curl http://localhost:9200/ubi_queries/_search | jq` -* +The `scripts/` directory contains example UBI requests for common use cases. ## User Quick Start @@ -40,7 +39,7 @@ bin/opensearch-plugin install file:/opensearch-ubi-1.0.0-os2.14.0.zip To create the UBI indexes called `ubi_queries` and `ubi_events`, send a query to an OpenSearch index with the `ubi` query block added: ``` -curl -s http://localhost:9200/your-index/_search -H "Content-Type: application/json" -d' +curl -s http://localhost:9200/ecommerce/_search -H "Content-Type: application/json" -d' { "ext": { "ubi": { @@ -154,9 +153,11 @@ Similar to a query request, query responses will also include a `ubi` section in The only field present in the query response will be the `query_id`. The value of the `query_id` is the same as the `query_id` provided in the query, or, if not provided, a random UUID. -### Indexed Queries +### Indexing Queries + +Queries can be either indexed in the local OpenSearch in the `ubi_queries` index, or queries can be sent to a Data Prepper `http_source` endpoint. -To see how the query is indexed, you can search the `ubi_queries` index: +By default, queries are written to the local OpenSearch `ubi_queries` index as they are received. To see how the query is indexed, you can search the `ubi_queries` index: ``` curl -s http://localhost:9200/ubi_queries/_search -H "Content-Type: application/json" | jq @@ -206,6 +207,16 @@ Each indexed query will have the following fields: * `query` - The raw query that was provided to OpenSearch. * `timestamp` - The Unix timestamp when the query was indexed. +#### Sending Queries to Data Prepper + +To send queries to Data Prepper, configure the following properties in OpenSearch: + +| Property | Description | Example Value | +|---------------------|---------------------------------------|-------------------------------| +| ubi.dataprepper.url | Data Prepper's `http_source` endpoint | `http://localhost:2021/log/ingest` | + +With these properties set, queries will no longer be indexed into the local OpenSearch. The `ubi_queries` index can be deleted. Queries will be sent to Data Prepper as they are received by OpenSearch. + ### Capturing Events The UBI plugin does *not* provide a way to capture client-side events. Sending client-side events requires action on the client to send the events to OpenSearch for indexing. diff --git a/build.gradle b/build.gradle index a5bbf55..ed2bceb 100644 --- a/build.gradle +++ b/build.gradle @@ -40,12 +40,16 @@ repositories { maven { url "https://plugins.gradle.org/m2/" } } +thirdPartyAudit.enabled = false + dependencies { // required for the yaml test to run yamlRestTestImplementation "org.apache.logging.log4j:log4j-core:${versions.log4j}" runtimeOnly "org.apache.logging.log4j:log4j-core:${versions.log4j}" implementation "com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}" implementation "com.fasterxml.jackson.core:jackson-databind:${versions.jackson_databind}" + implementation "org.apache.httpcomponents:httpcore:${versions.httpcore}" + implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.14' } publishing { diff --git a/docker-compose.yaml b/docker-compose.yaml index a4d7919..154154e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,3 @@ -version: '3' - services: ubi-dev-os: build: ./ @@ -18,6 +16,7 @@ services: http.cors.allow-headers: X-Requested-With,X-Auth-Token,Content-Type,Content-Length,Authorization,X-ubi-store,X-ubi-query-id,X-ubi-user-id,X-ubi-session-id logger.level: info OPENSEARCH_INITIAL_ADMIN_PASSWORD: SuperSecretPassword_123 + #ubi.dataprepper.url: "http://localhost:2021/log/ingest" ulimits: memlock: soft: -1 diff --git a/licenses/httpclient-4.5.14.jar.sha1 b/licenses/httpclient-4.5.14.jar.sha1 new file mode 100644 index 0000000..66e0585 --- /dev/null +++ b/licenses/httpclient-4.5.14.jar.sha1 @@ -0,0 +1 @@ +1194890e6f56ec29177673f2f12d0b8e627dec98 \ No newline at end of file diff --git a/licenses/httpclient-LICENSE.txt b/licenses/httpclient-LICENSE.txt new file mode 100644 index 0000000..f433b1a --- /dev/null +++ b/licenses/httpclient-LICENSE.txt @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/licenses/httpclient-NOTICE.txt b/licenses/httpclient-NOTICE.txt new file mode 100644 index 0000000..9664aa0 --- /dev/null +++ b/licenses/httpclient-NOTICE.txt @@ -0,0 +1,5 @@ +Apache HttpComponents Core +Copyright 2005-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). \ No newline at end of file diff --git a/licenses/httpcore-4.4.16.jar.sha1 b/licenses/httpcore-4.4.16.jar.sha1 new file mode 100644 index 0000000..1721106 --- /dev/null +++ b/licenses/httpcore-4.4.16.jar.sha1 @@ -0,0 +1 @@ +51cf043c87253c9f58b539c9f7e44c8894223850 \ No newline at end of file diff --git a/licenses/httpcore-LICENSE.txt b/licenses/httpcore-LICENSE.txt new file mode 100644 index 0000000..f433b1a --- /dev/null +++ b/licenses/httpcore-LICENSE.txt @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/licenses/httpcore-NOTICE.txt b/licenses/httpcore-NOTICE.txt new file mode 100644 index 0000000..9664aa0 --- /dev/null +++ b/licenses/httpcore-NOTICE.txt @@ -0,0 +1,5 @@ +Apache HttpComponents Core +Copyright 2005-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). \ No newline at end of file diff --git a/scripts/get-indexed-queries.sh b/scripts/get-indexed-queries.sh new file mode 100644 index 0000000..351d2a6 --- /dev/null +++ b/scripts/get-indexed-queries.sh @@ -0,0 +1,5 @@ +#!/bin/bash -e + +# Get the indexed queries. + +curl http://localhost:9200/ubi_queries/_search | jq diff --git a/scripts/search.sh b/scripts/search.sh new file mode 100755 index 0000000..3cc2bcb --- /dev/null +++ b/scripts/search.sh @@ -0,0 +1,16 @@ +#!/bin/bash -e + +# An example UBI search of the ecommerce index. + +curl -s http://localhost:9200/ecommerce/_search -H "Content-Type: application/json" -d' + { + "ext": { + "ubi": { + } + }, + "query": { + "match": { + "name": "toner" + } + } + }' | jq diff --git a/src/main/java/org/opensearch/ubi/UbiActionFilter.java b/src/main/java/org/opensearch/ubi/UbiActionFilter.java index 13f2f2d..26fa87d 100644 --- a/src/main/java/org/opensearch/ubi/UbiActionFilter.java +++ b/src/main/java/org/opensearch/ubi/UbiActionFilter.java @@ -8,6 +8,15 @@ package org.opensearch.ubi; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.HttpEntity; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.action.ActionRequest; @@ -27,6 +36,7 @@ import org.opensearch.common.xcontent.XContentType; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; +import org.opensearch.env.Environment; import org.opensearch.search.SearchHit; import org.opensearch.tasks.Task; import org.opensearch.ubi.ext.UbiParameters; @@ -56,13 +66,16 @@ public class UbiActionFilter implements ActionFilter { private static final String QUERIES_MAPPING_FILE = "/queries-mapping.json"; private final Client client; + private final Environment environment; /** * Creates a new filter. * @param client An OpenSearch {@link Client}. + * @param environment The OpenSearch {@link Environment}. */ - public UbiActionFilter(Client client) { + public UbiActionFilter(Client client, Environment environment) { this.client = client; + this.environment = environment; } @Override @@ -122,6 +135,20 @@ public void onResponse(Response response) { final QueryResponse queryResponse = new QueryResponse(queryId, queryResponseId, queryResponseHitIds); final QueryRequest queryRequest = new QueryRequest(queryId, userQuery, userId, query, queryAttributes, queryResponse); + final String dataPrepperUrl = environment.settings().get(UbiSettings.DATA_PREPPER_URL); + if(dataPrepperUrl != null) { + + try { + sendToDataPrepper(dataPrepperUrl, queryRequest); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } else { + LOGGER.info("Dataprepper url is NOT set"); + indexQuery(queryRequest); + } + SearchResponse searchResponse = (SearchResponse) response; response = (Response) new UbiSearchResponse( @@ -136,8 +163,6 @@ public void onResponse(Response response) { queryId ); - indexQuery(queryRequest); - } } @@ -155,6 +180,40 @@ public void onFailure(Exception ex) { } + private void sendToDataPrepper(final String dataPrepperUrl, final QueryRequest queryRequest) throws IOException { + + LOGGER.debug("Sending query to DataPrepper at " + dataPrepperUrl); + + final ObjectMapper objMapper = new ObjectMapper(); + final String json = objMapper.writeValueAsString(queryRequest); + + try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + + HttpPost httpPost = new HttpPost(dataPrepperUrl); + + final StringEntity entity = new StringEntity(json); + httpPost.setEntity(entity); + httpPost.setHeader("Content-type", "application/json"); + + final ResponseHandler responseHandler = response -> { + + int status = response.getStatusLine().getStatusCode(); + if (status >= 200 && status < 300) { + HttpEntity entity1 = response.getEntity(); + return entity1 != null ? EntityUtils.toString(entity1) : null; + } else { + throw new ClientProtocolException("Unexpected response status: " + status); + } + + }; + + final String responseBody = httpclient.execute(httpPost, responseHandler); + LOGGER.info(responseBody); + + } + + } + private void indexQuery(final QueryRequest queryRequest) { final IndicesExistsRequest indicesExistsRequest = new IndicesExistsRequest(UBI_EVENTS_INDEX, UBI_QUERIES_INDEX); diff --git a/src/main/java/org/opensearch/ubi/UbiPlugin.java b/src/main/java/org/opensearch/ubi/UbiPlugin.java index 0f211a6..4626e75 100644 --- a/src/main/java/org/opensearch/ubi/UbiPlugin.java +++ b/src/main/java/org/opensearch/ubi/UbiPlugin.java @@ -12,6 +12,8 @@ import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.settings.Setting; +import org.opensearch.common.settings.Settings; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -45,6 +47,11 @@ public class UbiPlugin extends Plugin implements ActionPlugin, SearchPlugin { */ public UbiPlugin() {} + @Override + public List> getSettings() { + return UbiSettings.getSettings(); + } + @Override public List getActionFilters() { return singletonList(ubiActionFilter); @@ -65,8 +72,7 @@ public Collection createComponents( Supplier repositoriesServiceSupplier ) { - this.ubiActionFilter = new UbiActionFilter(client); - + this.ubiActionFilter = new UbiActionFilter(client, environment); return Collections.emptyList(); } diff --git a/src/main/java/org/opensearch/ubi/UbiSettings.java b/src/main/java/org/opensearch/ubi/UbiSettings.java new file mode 100644 index 0000000..656962a --- /dev/null +++ b/src/main/java/org/opensearch/ubi/UbiSettings.java @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.ubi; + +import org.opensearch.common.settings.Setting; + +import java.util.Collections; +import java.util.List; + +/** + * The UBI settings. + */ +public class UbiSettings { + + /** + * The name of the Data Prepper http_source URL for receiving queries. + */ + public static final String DATA_PREPPER_URL = "ubi.dataprepper.url"; + + private static final Setting DATA_PREPPER_URL_SETTING = Setting.simpleString( + DATA_PREPPER_URL, + Setting.Property.Dynamic, + Setting.Property.NodeScope); + + /** + * Gets a list of the UBI plugin settings. + * @return A list of the UBI plugin settings. + */ + public static List> getSettings() { + return Collections.singletonList( + DATA_PREPPER_URL_SETTING + ); + } + +} From 5f7f391a158d03615e9b6f4d494eb0b8e2ca1579 Mon Sep 17 00:00:00 2001 From: jzonthemtn Date: Sat, 1 Jun 2024 09:19:42 -0400 Subject: [PATCH 2/8] #176 Sending queries to Data Prepper. --- .../org/opensearch/ubi/UbiActionFilter.java | 46 ++++++++----------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/opensearch/ubi/UbiActionFilter.java b/src/main/java/org/opensearch/ubi/UbiActionFilter.java index 26fa87d..899baf7 100644 --- a/src/main/java/org/opensearch/ubi/UbiActionFilter.java +++ b/src/main/java/org/opensearch/ubi/UbiActionFilter.java @@ -10,8 +10,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.HttpEntity; +import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; @@ -137,15 +139,8 @@ public void onResponse(Response response) { final String dataPrepperUrl = environment.settings().get(UbiSettings.DATA_PREPPER_URL); if(dataPrepperUrl != null) { - - try { - sendToDataPrepper(dataPrepperUrl, queryRequest); - } catch (IOException e) { - throw new RuntimeException(e); - } - + sendToDataPrepper(dataPrepperUrl, queryRequest); } else { - LOGGER.info("Dataprepper url is NOT set"); indexQuery(queryRequest); } @@ -180,36 +175,33 @@ public void onFailure(Exception ex) { } - private void sendToDataPrepper(final String dataPrepperUrl, final QueryRequest queryRequest) throws IOException { + private void sendToDataPrepper(final String dataPrepperUrl, final QueryRequest queryRequest) { LOGGER.debug("Sending query to DataPrepper at " + dataPrepperUrl); - final ObjectMapper objMapper = new ObjectMapper(); - final String json = objMapper.writeValueAsString(queryRequest); + try { - try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + final ObjectMapper objMapper = new ObjectMapper(); + final String json = objMapper.writeValueAsString(queryRequest); - HttpPost httpPost = new HttpPost(dataPrepperUrl); + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - final StringEntity entity = new StringEntity(json); - httpPost.setEntity(entity); - httpPost.setHeader("Content-type", "application/json"); + final HttpPost httpPost = new HttpPost(dataPrepperUrl); - final ResponseHandler responseHandler = response -> { + httpPost.setEntity(new StringEntity(json)); + httpPost.setHeader("Content-type", "application/json"); - int status = response.getStatusLine().getStatusCode(); - if (status >= 200 && status < 300) { - HttpEntity entity1 = response.getEntity(); - return entity1 != null ? EntityUtils.toString(entity1) : null; - } else { - throw new ClientProtocolException("Unexpected response status: " + status); + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + final int status = response.getStatusLine().getStatusCode(); + if (status != 200) { + LOGGER.error("Unexpected response status from Data Prepper: " + status); + } } - }; - - final String responseBody = httpclient.execute(httpPost, responseHandler); - LOGGER.info(responseBody); + } + } catch (IOException ex) { + LOGGER.error("Failed to send query to Data Prepper", ex); } } From ea57accd73f4ee433e73a74a3207a7f056b9298c Mon Sep 17 00:00:00 2001 From: jzonthemtn Date: Sat, 1 Jun 2024 09:25:36 -0400 Subject: [PATCH 3/8] Clean up code. --- src/main/java/org/opensearch/ubi/UbiActionFilter.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/opensearch/ubi/UbiActionFilter.java b/src/main/java/org/opensearch/ubi/UbiActionFilter.java index 899baf7..fe0c54f 100644 --- a/src/main/java/org/opensearch/ubi/UbiActionFilter.java +++ b/src/main/java/org/opensearch/ubi/UbiActionFilter.java @@ -9,16 +9,11 @@ package org.opensearch.ubi; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.http.HttpEntity; -import org.apache.http.StatusLine; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.action.ActionRequest; @@ -179,6 +174,7 @@ private void sendToDataPrepper(final String dataPrepperUrl, final QueryRequest q LOGGER.debug("Sending query to DataPrepper at " + dataPrepperUrl); + // TODO: Do this in a background thread? try { final ObjectMapper objMapper = new ObjectMapper(); From 10d041de650d98a435f146c4fb28c34fdaf7c073 Mon Sep 17 00:00:00 2001 From: jzonthemtn Date: Mon, 3 Jun 2024 08:52:29 -0400 Subject: [PATCH 4/8] Adding dataprepper to the docker compose. --- dataprepper/data-prepper-config.yaml | 1 + dataprepper/pipelines.yaml | 10 ++++++++ docker-compose-cluster.yaml | 34 ++++++++++++++++++++++++---- docker-compose.yaml | 25 ++++++++++++-------- 4 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 dataprepper/data-prepper-config.yaml create mode 100644 dataprepper/pipelines.yaml diff --git a/dataprepper/data-prepper-config.yaml b/dataprepper/data-prepper-config.yaml new file mode 100644 index 0000000..7462c0a --- /dev/null +++ b/dataprepper/data-prepper-config.yaml @@ -0,0 +1 @@ +ssl: false diff --git a/dataprepper/pipelines.yaml b/dataprepper/pipelines.yaml new file mode 100644 index 0000000..ac78a7d --- /dev/null +++ b/dataprepper/pipelines.yaml @@ -0,0 +1,10 @@ +chorus-ubi-pipeline: + source: + http: + port: 2021 + ssl: false + sink: + - opensearch: + hosts: [ "http://ubi-dev-os:9200" ] + index_type: custom + index: ubi_queries diff --git a/docker-compose-cluster.yaml b/docker-compose-cluster.yaml index 04f4b19..ee8fa6c 100644 --- a/docker-compose-cluster.yaml +++ b/docker-compose-cluster.yaml @@ -2,7 +2,23 @@ version: '3.7' services: - os01: + dataprepper-dev-os: + depends_on: + - ubi-dev-os + - ubi-dev-os-2 + - ubi-dev-os-3 + container_name: dataprepper + image: opensearchproject/data-prepper:2.8.0 + ports: + - 4900:4900 + - 2021:2021 + volumes: + - ./dataprepper/pipelines.yaml:/usr/share/data-prepper/pipelines/pipelines.yaml + - ./dataprepper/data-prepper-config.yaml:/usr/share/data-prepper/config/data-prepper-config.yaml + networks: + - ubi-dev-os-net + + ubi-dev-os: build: ./ environment: node.name: os01 @@ -24,8 +40,10 @@ services: ports: - 9200:9200 - 9600:9600 - - os02: + networks: + - ubi-dev-os-net + + ubi-dev-os-2: build: ./ environment: node.name: os02 @@ -44,8 +62,10 @@ services: nofile: soft: 65536 hard: 65536 + networks: + - ubi-dev-os-net - os03: + ubi-dev-os-3: build: ./ environment: node.name: os03 @@ -64,9 +84,11 @@ services: nofile: soft: 65536 hard: 65536 + networks: + - ubi-dev-os-net os-dashboards: - image: opensearchproject/opensearch-dashboards:2.12.0 + image: opensearchproject/opensearch-dashboards:2.14.0 container_name: opensearch-dashboards ports: - 5601:5601 @@ -77,3 +99,5 @@ services: DISABLE_SECURITY_DASHBOARDS_PLUGIN: "true" depends_on: - os01 + networks: + - ubi-dev-os-net \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 154154e..98291ad 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,4 +1,19 @@ services: + + dataprepper-dev-os: + depends_on: + - ubi-dev-os + container_name: dataprepper + image: opensearchproject/data-prepper:2.8.0 + ports: + - 4900:4900 + - 2021:2021 + volumes: + - ./dataprepper/pipelines.yaml:/usr/share/data-prepper/pipelines/pipelines.yaml + - ./dataprepper/data-prepper-config.yaml:/usr/share/data-prepper/config/data-prepper-config.yaml + networks: + - ubi-dev-os-net + ubi-dev-os: build: ./ container_name: ubi-dev-os @@ -6,17 +21,9 @@ services: discovery.type: single-node node.name: opensearch plugins.security.disabled: "true" -# See https://forum.opensearch.org/t/how-to-enable-cors-cross-origin-resource-sharing/426/3 for more - http.cors.enabled: true -# Warning: this is opening it up to all cross domains -# http.cors.allow-origin: "http://localhost"... - http.cors.allow-origin: "*" - http.cors.allow-methods: OPTIONS,TRACE,HEAD,GET,POST,PUT,DELETE - http.cors.allow-credentials: true - http.cors.allow-headers: X-Requested-With,X-Auth-Token,Content-Type,Content-Length,Authorization,X-ubi-store,X-ubi-query-id,X-ubi-user-id,X-ubi-session-id logger.level: info OPENSEARCH_INITIAL_ADMIN_PASSWORD: SuperSecretPassword_123 - #ubi.dataprepper.url: "http://localhost:2021/log/ingest" + ubi.dataprepper.url: "http://dataprepper-dev-os:2021/log/ingest" ulimits: memlock: soft: -1 From 8f139fa6957c6ce8f970891c73dce8425571b5bc Mon Sep 17 00:00:00 2001 From: jzonthemtn Date: Mon, 3 Jun 2024 09:40:02 -0400 Subject: [PATCH 5/8] Updating unit tests. Updating query request json serialization. --- build.gradle | 12 +- licenses/commons-logging-1.2.jar.sha1 | 1 + licenses/commons-logging-LICENSE.txt | 177 ++++++++++++++++++ licenses/commons-logging-NOTICE.txt | 5 + .../java/org/opensearch/ubi/QueryRequest.java | 50 ++++- .../org/opensearch/ubi/UbiActionFilter.java | 8 +- .../org/opensearch/ubi/QueryRequestTests.java | 29 +++ .../opensearch/ubi/UbIParametersTests.java | 11 +- .../opensearch/ubi/UbiActionFilterTests.java | 19 +- .../opensearch/ubi/UbiModulePluginTests.java | 4 +- .../ubi/UbiParametersExtBuilderTests.java | 57 ++---- 11 files changed, 303 insertions(+), 70 deletions(-) create mode 100644 licenses/commons-logging-1.2.jar.sha1 create mode 100644 licenses/commons-logging-LICENSE.txt create mode 100644 licenses/commons-logging-NOTICE.txt create mode 100644 src/test/java/org/opensearch/ubi/QueryRequestTests.java rename src/{main => }/test/java/org/opensearch/ubi/UbIParametersTests.java (90%) rename src/{main => }/test/java/org/opensearch/ubi/UbiActionFilterTests.java (89%) rename src/{main => }/test/java/org/opensearch/ubi/UbiModulePluginTests.java (92%) rename src/{main => }/test/java/org/opensearch/ubi/UbiParametersExtBuilderTests.java (77%) diff --git a/build.gradle b/build.gradle index ed2bceb..ad914b5 100644 --- a/build.gradle +++ b/build.gradle @@ -43,13 +43,13 @@ repositories { thirdPartyAudit.enabled = false dependencies { - // required for the yaml test to run - yamlRestTestImplementation "org.apache.logging.log4j:log4j-core:${versions.log4j}" runtimeOnly "org.apache.logging.log4j:log4j-core:${versions.log4j}" - implementation "com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}" - implementation "com.fasterxml.jackson.core:jackson-databind:${versions.jackson_databind}" - implementation "org.apache.httpcomponents:httpcore:${versions.httpcore}" - implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.14' + api "com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}" + api "com.fasterxml.jackson.core:jackson-databind:${versions.jackson_databind}" + api "org.apache.httpcomponents:httpcore:${versions.httpcore}" + api "org.apache.httpcomponents:httpclient:${versions.httpclient}" + api "commons-logging:commons-logging:${versions.commonslogging}" + yamlRestTestImplementation "org.apache.logging.log4j:log4j-core:${versions.log4j}" } publishing { diff --git a/licenses/commons-logging-1.2.jar.sha1 b/licenses/commons-logging-1.2.jar.sha1 new file mode 100644 index 0000000..f40f024 --- /dev/null +++ b/licenses/commons-logging-1.2.jar.sha1 @@ -0,0 +1 @@ +4bfc12adfe4842bf07b657f0369c4cb522955686 \ No newline at end of file diff --git a/licenses/commons-logging-LICENSE.txt b/licenses/commons-logging-LICENSE.txt new file mode 100644 index 0000000..f433b1a --- /dev/null +++ b/licenses/commons-logging-LICENSE.txt @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/licenses/commons-logging-NOTICE.txt b/licenses/commons-logging-NOTICE.txt new file mode 100644 index 0000000..9664aa0 --- /dev/null +++ b/licenses/commons-logging-NOTICE.txt @@ -0,0 +1,5 @@ +Apache HttpComponents Core +Copyright 2005-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). \ No newline at end of file diff --git a/src/main/java/org/opensearch/ubi/QueryRequest.java b/src/main/java/org/opensearch/ubi/QueryRequest.java index 173f510..dceca82 100644 --- a/src/main/java/org/opensearch/ubi/QueryRequest.java +++ b/src/main/java/org/opensearch/ubi/QueryRequest.java @@ -17,7 +17,7 @@ public class QueryRequest { private final long timestamp; private final String queryId; - private final String userId; + private final String clientId; private final String userQuery; private final String query; private final Map queryAttributes; @@ -27,22 +27,56 @@ public class QueryRequest { * Creates a query request. * @param queryId The ID of the query. * @param userQuery The user-entered query. - * @param userId The ID of the user that initiated the query. + * @param clientId The ID of the client that initiated the query. * @param query The raw query. * @param queryAttributes An optional map of additional attributes for the query. * @param queryResponse The {@link QueryResponse} for this query request. */ - public QueryRequest(final String queryId, final String userQuery, final String userId, final String query, + public QueryRequest(final String queryId, final String userQuery, final String clientId, final String query, final Map queryAttributes, final QueryResponse queryResponse) { this.timestamp = System.currentTimeMillis(); this.queryId = queryId; - this.userId = userId; + this.clientId = clientId; this.userQuery = userQuery; this.query = query; this.queryAttributes = queryAttributes; this.queryResponse = queryResponse; } + @Override + public String toString() { + + final StringBuilder sb = new StringBuilder(); + + // Query Request + sb.append("{"); + sb.append("\"query_id\": \"").append(queryId).append("\", "); + sb.append("\"user_query\": \"").append(userQuery).append("\", "); + sb.append("\"user_id\": \"").append(clientId).append("\", "); + + sb.append("query_attributes: {"); + for(final String key : queryAttributes.keySet()) { + sb.append("\"").append(key).append("\": ").append("\"").append(queryAttributes.get(key)).append("\", "); + } + sb.append("},"); + + // Query Response + sb.append("\"query_response\": {"); + sb.append("\"query_id\": ").append(queryResponse.getQueryId()).append("\", "); + sb.append("\"query_response_id\": ").append(queryResponse.getQueryResponseId()).append("\", "); + sb.append("\"query_response_object_ids\": ["); + for(final String objectId : queryResponse.getQueryResponseObjectIds()) { + sb.append("\"").append(objectId).append("\", "); + } + sb.append("],"); + sb.append("}"); + + sb.append("}"); + + return sb.toString(); + + } + /** * Gets the query attributes. * @return The query attributes. @@ -76,11 +110,11 @@ public String getUserQuery() { } /** - * Gets the user ID. - * @return The user ID. + * Gets the client ID. + * @return The client ID. */ - public String getUserId() { - return userId; + public String getClientId() { + return clientId; } /** diff --git a/src/main/java/org/opensearch/ubi/UbiActionFilter.java b/src/main/java/org/opensearch/ubi/UbiActionFilter.java index fe0c54f..276f5ad 100644 --- a/src/main/java/org/opensearch/ubi/UbiActionFilter.java +++ b/src/main/java/org/opensearch/ubi/UbiActionFilter.java @@ -8,7 +8,6 @@ package org.opensearch.ubi; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; @@ -177,14 +176,11 @@ private void sendToDataPrepper(final String dataPrepperUrl, final QueryRequest q // TODO: Do this in a background thread? try { - final ObjectMapper objMapper = new ObjectMapper(); - final String json = objMapper.writeValueAsString(queryRequest); - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { final HttpPost httpPost = new HttpPost(dataPrepperUrl); - httpPost.setEntity(new StringEntity(json)); + httpPost.setEntity(new StringEntity(queryRequest.toString())); httpPost.setHeader("Content-type", "application/json"); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { @@ -247,7 +243,7 @@ public void onResponse(IndicesExistsResponse indicesExistsResponse) { source.put("query_id", queryRequest.getQueryId()); source.put("query_response_id", queryRequest.getQueryResponse().getQueryResponseId()); source.put("query_response_object_ids", queryRequest.getQueryResponse().getQueryResponseObjectIds()); - source.put("client_id", queryRequest.getUserId()); + source.put("client_id", queryRequest.getClientId()); source.put("user_query", queryRequest.getUserQuery()); source.put("query_attributes", queryRequest.getQueryAttributes()); diff --git a/src/test/java/org/opensearch/ubi/QueryRequestTests.java b/src/test/java/org/opensearch/ubi/QueryRequestTests.java new file mode 100644 index 0000000..a5f98e3 --- /dev/null +++ b/src/test/java/org/opensearch/ubi/QueryRequestTests.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.ubi; + +import org.opensearch.test.OpenSearchTestCase; + +import java.util.List; +import java.util.Map; + +public class QueryRequestTests extends OpenSearchTestCase { + + public void testSerialization() { + + final QueryResponse queryResponse = new QueryResponse("queryid", "queryrequestid", List.of("12345", "67890")); + + final QueryRequest queryRequest = new QueryRequest("queryid", "userquery", "clientid", "query", + Map.of("key1", "value1", "key2", "value2"), queryResponse); + + final String json = queryRequest.toString(); + + } + +} diff --git a/src/main/test/java/org/opensearch/ubi/UbIParametersTests.java b/src/test/java/org/opensearch/ubi/UbIParametersTests.java similarity index 90% rename from src/main/test/java/org/opensearch/ubi/UbIParametersTests.java rename to src/test/java/org/opensearch/ubi/UbIParametersTests.java index ac57a8f..02e528f 100644 --- a/src/main/test/java/org/opensearch/ubi/UbIParametersTests.java +++ b/src/test/java/org/opensearch/ubi/UbIParametersTests.java @@ -15,10 +15,13 @@ import org.opensearch.core.xcontent.XContentGenerator; import org.opensearch.search.builder.SearchSourceBuilder; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.ubi.ext.UbiParameters; +import org.opensearch.ubi.ext.UbiParametersExtBuilder; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static org.mockito.ArgumentMatchers.any; @@ -77,7 +80,7 @@ public void reset() throws IOException { } public void testUbiParameters() { - final UbiParameters params = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + final UbiParameters params = new UbiParameters("query_id", "user_query", "client_id", "object_id", Collections.emptyMap()); UbiParametersExtBuilder extBuilder = new UbiParametersExtBuilder(); extBuilder.setParams(params); SearchSourceBuilder srcBulder = SearchSourceBuilder.searchSource().ext(List.of(extBuilder)); @@ -87,7 +90,7 @@ public void testUbiParameters() { } public void testWriteTo() throws IOException { - final UbiParameters params = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + final UbiParameters params = new UbiParameters("query_id", "user_query", "client_id", "object_id", Collections.emptyMap()); StreamOutput output = new DummyStreamOutput(); params.writeTo(output); List actual = ((DummyStreamOutput) output).getList(); @@ -98,7 +101,7 @@ public void testWriteTo() throws IOException { } public void testToXContent() throws IOException { - final UbiParameters params = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + final UbiParameters params = new UbiParameters("query_id", "user_query", "client_id", "object_id", Collections.emptyMap()); XContent xc = mock(XContent.class); OutputStream os = mock(OutputStream.class); XContentGenerator generator = mock(XContentGenerator.class); @@ -108,7 +111,7 @@ public void testToXContent() throws IOException { } public void testToXContentAllOptionalParameters() throws IOException { - final UbiParameters params = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + final UbiParameters params = new UbiParameters("query_id", "user_query", "client_id", "object_id", Collections.emptyMap()); XContent xc = mock(XContent.class); OutputStream os = mock(OutputStream.class); XContentGenerator generator = mock(XContentGenerator.class); diff --git a/src/main/test/java/org/opensearch/ubi/UbiActionFilterTests.java b/src/test/java/org/opensearch/ubi/UbiActionFilterTests.java similarity index 89% rename from src/main/test/java/org/opensearch/ubi/UbiActionFilterTests.java rename to src/test/java/org/opensearch/ubi/UbiActionFilterTests.java index c3288c1..d1f490d 100644 --- a/src/main/test/java/org/opensearch/ubi/UbiActionFilterTests.java +++ b/src/test/java/org/opensearch/ubi/UbiActionFilterTests.java @@ -18,7 +18,10 @@ import org.opensearch.client.Client; import org.opensearch.client.IndicesAdminClient; import org.opensearch.common.action.ActionFuture; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.unit.TimeValue; import org.opensearch.core.action.ActionListener; +import org.opensearch.env.Environment; import org.opensearch.search.SearchExtBuilder; import org.opensearch.search.SearchHit; import org.opensearch.search.SearchHits; @@ -52,10 +55,13 @@ public void testApplyWithoutUbiBlock() { when(client.admin()).thenReturn(adminClient); when(adminClient.indices()).thenReturn(indicesAdminClient); + final Environment environment = mock(Environment.class); + when(environment.settings()).thenReturn(Settings.EMPTY); + final ActionFuture actionFuture = mock(ActionFuture.class); when(indicesAdminClient.exists(any(IndicesExistsRequest.class))).thenReturn(actionFuture); - final UbiActionFilter ubiActionFilter = new UbiActionFilter(client); + final UbiActionFilter ubiActionFilter = new UbiActionFilter(client, environment); final ActionListener listener = mock(ActionListener.class); final SearchRequest request = mock(SearchRequest.class); @@ -65,6 +71,9 @@ public void testApplyWithoutUbiBlock() { final SearchResponse response = mock(SearchResponse.class); when(response.getHits()).thenReturn(searchHits); + final TimeValue timeValue = new TimeValue(System.currentTimeMillis()); + when(response.getTook()).thenReturn(timeValue); + final Task task = mock(Task.class); final ActionFilterChain chain = mock(ActionFilterChain.class); @@ -103,10 +112,13 @@ public void testApplyWithUbiBlockWithoutQueryId() { when(client.admin()).thenReturn(adminClient); when(adminClient.indices()).thenReturn(indicesAdminClient); + final Environment environment = mock(Environment.class); + when(environment.settings()).thenReturn(Settings.EMPTY); + final ActionFuture actionFuture = mock(ActionFuture.class); when(indicesAdminClient.exists(any(IndicesExistsRequest.class))).thenReturn(actionFuture); - final UbiActionFilter ubiActionFilter = new UbiActionFilter(client); + final UbiActionFilter ubiActionFilter = new UbiActionFilter(client, environment); final ActionListener listener = mock(ActionListener.class); final SearchRequest request = mock(SearchRequest.class); @@ -116,6 +128,9 @@ public void testApplyWithUbiBlockWithoutQueryId() { final SearchResponse response = mock(SearchResponse.class); when(response.getHits()).thenReturn(searchHits); + final TimeValue timeValue = new TimeValue(System.currentTimeMillis()); + when(response.getTook()).thenReturn(timeValue); + final Task task = mock(Task.class); final ActionFilterChain chain = mock(ActionFilterChain.class); diff --git a/src/main/test/java/org/opensearch/ubi/UbiModulePluginTests.java b/src/test/java/org/opensearch/ubi/UbiModulePluginTests.java similarity index 92% rename from src/main/test/java/org/opensearch/ubi/UbiModulePluginTests.java rename to src/test/java/org/opensearch/ubi/UbiModulePluginTests.java index 43d218f..892a8ef 100644 --- a/src/main/test/java/org/opensearch/ubi/UbiModulePluginTests.java +++ b/src/test/java/org/opensearch/ubi/UbiModulePluginTests.java @@ -20,13 +20,13 @@ public class UbiModulePluginTests extends OpenSearchTestCase { - private UbiModulePlugin ubiModulePlugin; + private UbiPlugin ubiModulePlugin; private final Client client = mock(Client.class); @Before public void setup() { - ubiModulePlugin = new UbiModulePlugin(); + ubiModulePlugin = new UbiPlugin(); } public void testCreateComponent() { diff --git a/src/main/test/java/org/opensearch/ubi/UbiParametersExtBuilderTests.java b/src/test/java/org/opensearch/ubi/UbiParametersExtBuilderTests.java similarity index 77% rename from src/main/test/java/org/opensearch/ubi/UbiParametersExtBuilderTests.java rename to src/test/java/org/opensearch/ubi/UbiParametersExtBuilderTests.java index 2f7b3a5..8d13e81 100644 --- a/src/main/test/java/org/opensearch/ubi/UbiParametersExtBuilderTests.java +++ b/src/test/java/org/opensearch/ubi/UbiParametersExtBuilderTests.java @@ -15,56 +15,29 @@ import org.opensearch.core.xcontent.XContentHelper; import org.opensearch.core.xcontent.XContentParser; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.ubi.ext.UbiParameters; +import org.opensearch.ubi.ext.UbiParametersExtBuilder; import java.io.EOFException; import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class UbiParametersExtBuilderTests extends OpenSearchTestCase { - public void testCtor() throws IOException { + public void testCtor() { + + final Map queryAttributes = new HashMap<>(); final UbiParametersExtBuilder builder = new UbiParametersExtBuilder(); - final UbiParameters parameters = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + final UbiParameters parameters = new UbiParameters("query_id", "user_query", "client_id", "object_id_field", queryAttributes); builder.setParams(parameters); assertEquals(parameters, builder.getParams()); - final UbiParametersExtBuilder builder1 = new UbiParametersExtBuilder(new StreamInput() { - @Override - public byte readByte() throws IOException { - return 0; - } - - @Override - public void readBytes(byte[] b, int offset, int len) throws IOException { - - } - - @Override - public void close() throws IOException { - - } - - @Override - public int available() throws IOException { - return 0; - } - - @Override - protected void ensureCanReadBytes(int length) throws EOFException { - - } - - @Override - public int read() throws IOException { - return 0; - } - }); - - assertNotNull(builder1); - } public void testParse() throws IOException { @@ -76,7 +49,7 @@ public void testParse() throws IOException { } public void testXContentRoundTrip() throws IOException { - UbiParameters param1 = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + UbiParameters param1 = new UbiParameters("query_id", "user_query", "client_id", "object_id_field", Collections.emptyMap()); UbiParametersExtBuilder extBuilder = new UbiParametersExtBuilder(); extBuilder.setParams(param1); XContentType xContentType = randomFrom(XContentType.values()); @@ -88,11 +61,11 @@ public void testXContentRoundTrip() throws IOException { assertEquals("query_id", parameters.getQueryId()); assertEquals("user_query", parameters.getUserQuery()); assertEquals("client_id", parameters.getClientId()); - assertEquals("object_id", parameters.getObjectId()); + assertEquals("object_id_field", parameters.getObjectIdField()); } public void testXContentRoundTripAllValues() throws IOException { - UbiParameters param1 = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + UbiParameters param1 = new UbiParameters("query_id", "user_query", "client_id", "object_id_field", Collections.emptyMap()); UbiParametersExtBuilder extBuilder = new UbiParametersExtBuilder(); extBuilder.setParams(param1); XContentType xContentType = randomFrom(XContentType.values()); @@ -103,7 +76,7 @@ public void testXContentRoundTripAllValues() throws IOException { } public void testStreamRoundTrip() throws IOException { - UbiParameters param1 = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + UbiParameters param1 = new UbiParameters("query_id", "user_query", "client_id", "object_id_field", Collections.emptyMap()); UbiParametersExtBuilder extBuilder = new UbiParametersExtBuilder(); extBuilder.setParams(param1); BytesStreamOutput bso = new BytesStreamOutput(); @@ -114,11 +87,11 @@ public void testStreamRoundTrip() throws IOException { assertEquals("query_id", parameters.getQueryId()); assertEquals("user_query", parameters.getUserQuery()); assertEquals("client_id", parameters.getClientId()); - assertEquals("object_id", parameters.getObjectId()); + assertEquals("object_id_field", parameters.getObjectIdField()); } public void testStreamRoundTripAllValues() throws IOException { - UbiParameters param1 = new UbiParameters("query_id", "user_query", "client_id", "object_id"); + UbiParameters param1 = new UbiParameters("query_id", "user_query", "client_id", "object_id_field", Collections.emptyMap()); UbiParametersExtBuilder extBuilder = new UbiParametersExtBuilder(); extBuilder.setParams(param1); BytesStreamOutput bso = new BytesStreamOutput(); From d3405578cc16ded8d0eeda5d715b6fb043227fcb Mon Sep 17 00:00:00 2001 From: jzonthemtn Date: Mon, 3 Jun 2024 10:09:56 -0400 Subject: [PATCH 6/8] Adding security policy for json and http. --- Dockerfile | 2 +- .../java/org/opensearch/ubi/QueryRequest.java | 51 +++++++++---------- .../org/opensearch/ubi/UbiActionFilter.java | 25 +++++++-- .../plugin-metadata/plugin-security.policy | 8 +++ .../org/opensearch/ubi/QueryRequestTests.java | 29 ----------- 5 files changed, 54 insertions(+), 61 deletions(-) create mode 100644 src/main/plugin-metadata/plugin-security.policy delete mode 100644 src/test/java/org/opensearch/ubi/QueryRequestTests.java diff --git a/Dockerfile b/Dockerfile index fcb59f0..aaf1f6e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,4 +2,4 @@ FROM opensearchproject/opensearch:2.14.0 COPY ./build/distributions/opensearch-ubi-0.0.12.1-os2.14.0.zip /tmp/ -RUN /usr/share/opensearch/bin/opensearch-plugin install file:/tmp/opensearch-ubi-0.0.12.1-os2.14.0.zip +RUN /usr/share/opensearch/bin/opensearch-plugin install --batch file:/tmp/opensearch-ubi-0.0.12.1-os2.14.0.zip diff --git a/src/main/java/org/opensearch/ubi/QueryRequest.java b/src/main/java/org/opensearch/ubi/QueryRequest.java index dceca82..5334610 100644 --- a/src/main/java/org/opensearch/ubi/QueryRequest.java +++ b/src/main/java/org/opensearch/ubi/QueryRequest.java @@ -8,6 +8,11 @@ package org.opensearch.ubi; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Map; /** @@ -34,6 +39,7 @@ public class QueryRequest { */ public QueryRequest(final String queryId, final String userQuery, final String clientId, final String query, final Map queryAttributes, final QueryResponse queryResponse) { + this.timestamp = System.currentTimeMillis(); this.queryId = queryId; this.clientId = clientId; @@ -41,39 +47,23 @@ public QueryRequest(final String queryId, final String userQuery, final String c this.query = query; this.queryAttributes = queryAttributes; this.queryResponse = queryResponse; + } @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - - // Query Request - sb.append("{"); - sb.append("\"query_id\": \"").append(queryId).append("\", "); - sb.append("\"user_query\": \"").append(userQuery).append("\", "); - sb.append("\"user_id\": \"").append(clientId).append("\", "); - - sb.append("query_attributes: {"); - for(final String key : queryAttributes.keySet()) { - sb.append("\"").append(key).append("\": ").append("\"").append(queryAttributes.get(key)).append("\", "); - } - sb.append("},"); - - // Query Response - sb.append("\"query_response\": {"); - sb.append("\"query_id\": ").append(queryResponse.getQueryId()).append("\", "); - sb.append("\"query_response_id\": ").append(queryResponse.getQueryResponseId()).append("\", "); - sb.append("\"query_response_object_ids\": ["); - for(final String objectId : queryResponse.getQueryResponseObjectIds()) { - sb.append("\"").append(objectId).append("\", "); - } - sb.append("],"); - sb.append("}"); + final ObjectMapper objectMapper = new ObjectMapper(); - sb.append("}"); + final String json = AccessController.doPrivileged((PrivilegedAction) () -> { + try { + return objectMapper.writeValueAsString(this); + } catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + }); - return sb.toString(); + return "[" + json + "]"; } @@ -106,6 +96,9 @@ public String getQueryId() { * @return The user query. */ public String getUserQuery() { + if(userQuery == null) { + return ""; + } return userQuery; } @@ -114,6 +107,9 @@ public String getUserQuery() { * @return The client ID. */ public String getClientId() { + if(clientId == null) { + return ""; + } return clientId; } @@ -122,6 +118,9 @@ public String getClientId() { * @return The raw query. */ public String getQuery() { + if(query == null) { + return ""; + } return query; } diff --git a/src/main/java/org/opensearch/ubi/UbiActionFilter.java b/src/main/java/org/opensearch/ubi/UbiActionFilter.java index 276f5ad..816024b 100644 --- a/src/main/java/org/opensearch/ubi/UbiActionFilter.java +++ b/src/main/java/org/opensearch/ubi/UbiActionFilter.java @@ -8,6 +8,10 @@ package org.opensearch.ubi; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; @@ -41,6 +45,8 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -111,6 +117,8 @@ public void onResponse(Response response) { final String userId = ubiParameters.getClientId(); final String objectIdField = ubiParameters.getObjectIdField(); final Map queryAttributes = ubiParameters.getQueryAttributes(); + + // TODO: Ignore the UBI in ext. final String query = searchRequest.source().toString(); final List queryResponseHitIds = new LinkedList<>(); @@ -183,12 +191,19 @@ private void sendToDataPrepper(final String dataPrepperUrl, final QueryRequest q httpPost.setEntity(new StringEntity(queryRequest.toString())); httpPost.setHeader("Content-type", "application/json"); - try (CloseableHttpResponse response = httpClient.execute(httpPost)) { - final int status = response.getStatusLine().getStatusCode(); - if (status != 200) { - LOGGER.error("Unexpected response status from Data Prepper: " + status); + AccessController.doPrivileged((PrivilegedAction) () -> { + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + final int status = response.getStatusLine().getStatusCode(); + if (status != 200) { + LOGGER.error("Unexpected response status from Data Prepper: {}", status); + return false; + } + } catch (Exception ex) { + LOGGER.error("Unable to send query to Data Prepper", ex); + return false; } - } + return true; + }); } diff --git a/src/main/plugin-metadata/plugin-security.policy b/src/main/plugin-metadata/plugin-security.policy new file mode 100644 index 0000000..466f8d1 --- /dev/null +++ b/src/main/plugin-metadata/plugin-security.policy @@ -0,0 +1,8 @@ +grant { + // Jackson de/serialization + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + permission java.lang.RuntimePermission "accessDeclaredMembers"; + + // Connecting to Data Prepper + permission java.net.SocketPermission "*", "connect,resolve"; +}; \ No newline at end of file diff --git a/src/test/java/org/opensearch/ubi/QueryRequestTests.java b/src/test/java/org/opensearch/ubi/QueryRequestTests.java deleted file mode 100644 index a5f98e3..0000000 --- a/src/test/java/org/opensearch/ubi/QueryRequestTests.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.ubi; - -import org.opensearch.test.OpenSearchTestCase; - -import java.util.List; -import java.util.Map; - -public class QueryRequestTests extends OpenSearchTestCase { - - public void testSerialization() { - - final QueryResponse queryResponse = new QueryResponse("queryid", "queryrequestid", List.of("12345", "67890")); - - final QueryRequest queryRequest = new QueryRequest("queryid", "userquery", "clientid", "query", - Map.of("key1", "value1", "key2", "value2"), queryResponse); - - final String json = queryRequest.toString(); - - } - -} From 56b24db0d2aa91b3eb83e4eb495d5ceaed269e44 Mon Sep 17 00:00:00 2001 From: jzonthemtn Date: Mon, 3 Jun 2024 10:11:12 -0400 Subject: [PATCH 7/8] Disabling dataprepper. --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 98291ad..2aa1d54 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -23,7 +23,7 @@ services: plugins.security.disabled: "true" logger.level: info OPENSEARCH_INITIAL_ADMIN_PASSWORD: SuperSecretPassword_123 - ubi.dataprepper.url: "http://dataprepper-dev-os:2021/log/ingest" + #ubi.dataprepper.url: "http://dataprepper-dev-os:2021/log/ingest" ulimits: memlock: soft: -1 From bbcabf9e476e257abd066f48d7db1a7cd26f5253 Mon Sep 17 00:00:00 2001 From: jzonthemtn Date: Mon, 3 Jun 2024 10:26:57 -0400 Subject: [PATCH 8/8] Updating readme. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c1380f0..16458c5 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ To get started, download the plugin zip file from the [releases](https://github. bin/opensearch-plugin install file:/opensearch-ubi-1.0.0-os2.14.0.zip ``` +You will be prompted while installing the plugin beacuse the plugin defines additional security permissions. These permissions allow the plugin to serialize query requests to JSON for storing and to allow the plugin to send query requests to Data Prepper. You can skip the prompt by adding the `--batch` argument to the above command. + To create the UBI indexes called `ubi_queries` and `ubi_events`, send a query to an OpenSearch index with the `ubi` query block added: ```