logstash-output-opensearch 1.3.0-java → 2.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbe40e1f039f2d91a4adfb8b8fb9a28fd877156bf270060fa1d294986a769983
4
- data.tar.gz: 9c2bd44c3e32cbf31d3ffac173a5e9b0ff2e4bcb9c4bd27267ac70a3a88ee6da
3
+ metadata.gz: e66800b300125b8b99d1425526e5f0f7661303b7a56dd25e6177a0780b9d5631
4
+ data.tar.gz: 77228ee0c56dca37f849023fa2159c52c4125b1dbf9fda6cf269ec489417d0d7
5
5
  SHA512:
6
- metadata.gz: ed114d31a8dd15ebe57cba0d87c278efe3be2a47743aa2cdfe99bf861e0934edb2772d09aa59eda0d9428b119dde77a16c82371ce19ca1cbfb5c6ce736692690
7
- data.tar.gz: df6263f5109d5834bc19fa9804c082c95dc1867eed7926be99b7682c4c1cfb3abffa0ff23b16f123f55f196e353527d31d8d5a61f3011bbf56805f43fa890fdc
6
+ metadata.gz: 9ee5db1f3d9ed8275a3329538d2b82c8a30db156c375fed8d250874511a29da8fe020019fb4b106caf42c3d0ad9b7c8136aa3312d307b45047930dceae0eebd4
7
+ data.tar.gz: bfa35bf7dd1e5621cf04f7a5b8f9d79d4bdbda2529f1d7cd697a6723b3487cb507079acc89dee1e075309b80eccd72984bffc3c96bcb23a2cc7a1739d68da592
checksums.yaml.gz.sig CHANGED
Binary file
data/COMPATIBILITY.md CHANGED
@@ -5,23 +5,25 @@
5
5
  | logstash-output-opensearch | Logstash OSS|
6
6
  | ------------- | ------------- |
7
7
  | 1.0.0+ | 7.13.2 |
8
+ | 2.0.0+ | 7.13.2 |
8
9
 
9
10
  ### Matrix for OpenSearch
10
11
 
11
12
  | logstash-output-opensearch | OpenSearch |
12
13
  | ------------- | ------------- |
13
- | 1.0.0+ | 1.0.0 |
14
-
14
+ | 1.0.0+ | 1.0.0 |
15
+ | 2.0.0+ | 1.0.0 |
15
16
 
16
17
  ### Matrix for ODFE
17
18
 
18
19
  | logstash-output-opensearch | ODFE |
19
20
  | ------------- | ------------- |
20
21
  | 1.0.0+ | 1.x - 1.13.2 |
21
-
22
+ | 2.0.0+ | 1.x - 1.13.2 |
22
23
 
23
24
  ### Matrix for Elasticsearch OSS
24
25
 
25
26
  | logstash-output-opensearch | Elasticsearch OSS|
26
27
  | ------------- | ------------- |
27
28
  | 1.0.0+ | 7.x - 7.10.2 |
29
+ | 2.0.0+ | 7.x - 7.10.2 |
data/MAINTAINERS.md CHANGED
@@ -1,74 +1,14 @@
1
- - [Overview](#overview)
2
- - [Current Maintainers](#current-maintainers)
3
- - [Maintainer Responsibilities](#maintainer-responsibilities)
4
- - [Uphold Code of Conduct](#uphold-code-of-conduct)
5
- - [Prioritize Security](#prioritize-security)
6
- - [Review Pull Requests](#review-pull-requests)
7
- - [Triage Open Issues](#triage-open-issues)
8
- - [Be Responsive](#be-responsive)
9
- - [Maintain Overall Health of the Repo](#maintain-overall-health-of-the-repo)
10
- - [Use Semver](#use-semver)
11
- - [Release Frequently](#release-frequently)
12
- - [Promote Other Maintainers](#promote-other-maintainers)
13
-
14
1
  ## Overview
15
2
 
16
- This document explains who the maintainers are (see below), what they do in this repo, and how they should be doing it. If you're interested in contributing, see [CONTRIBUTING](CONTRIBUTING.md).
3
+ This document contains a list of maintainers in this repo. See [opensearch-project/.github/RESPONSIBILITIES.md](https://github.com/opensearch-project/.github/blob/main/RESPONSIBILITIES.md#maintainer-responsibilities) that explains what the role of maintainer means, what maintainers do in this and other repos, and how they should be doing it. If you're interested in contributing, and becoming a maintainer, see [CONTRIBUTING](CONTRIBUTING.md).
17
4
 
18
5
  ## Current Maintainers
19
6
 
20
- | Maintainer | GitHub ID | Affiliation |
21
- | ------------------------ | --------------------------------------- | ----------- |
22
- | Jack Mazanec | [jmazanec15](https://github.com/jmazanec15) | Amazon |
23
- | Vamshi Vijay Nakkirtha | [vamshin](https://github.com/vamshin) | Amazon |
24
- | Vijayan Balasubramanian | [VijayanB](https://github.com/VijayanB) | Amazon |
25
- | Deep Datta | [deepdatta](https://github.com/deepdatta) | Amazon |
26
- | David Venable | [dlvenable](https://github.com/dlvenable) | Amazon |
27
- | Shivani Shukla | [sshivanii](https://github.com/sshivanii) | Amazon |
28
-
29
- ## Maintainer Responsibilities
30
-
31
- Maintainers are active and visible members of the community, and have [maintain-level permissions on a repository](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization). Use those privileges to serve the community and evolve code as follows.
32
-
33
- ### Uphold Code of Conduct
34
-
35
- Model the behavior set forward by the [Code of Conduct](CODE_OF_CONDUCT.md) and raise any violations to other maintainers and admins.
36
-
37
- ### Prioritize Security
38
-
39
- Security is your number one priority. Maintainer's Github keys must be password protected securely and any reported security vulnerabilities are addressed before features or bugs.
40
-
41
- Note that this repository is monitored and supported 24/7 by Amazon Security, see [Reporting a Vulnerability](SECURITY.md) for details.
42
-
43
- ### Review Pull Requests
44
-
45
- Review pull requests regularly, comment, suggest, reject, merge and close. Accept only high quality pull-requests. Provide code reviews and guidance on incomming pull requests. Don't let PRs be stale and do your best to be helpful to contributors.
46
-
47
- ### Triage Open Issues
48
-
49
- Manage labels, review issues regularly, and triage by labelling them.
50
-
51
- All repositories in this organization have a standard set of labels, including `bug`, `documentation`, `duplicate`, `enhancement`, `good first issue`, `help wanted`, `blocker`, `invalid`, `question`, `wontfix`, and `untriaged`, along with release labels, such as `v1.0.0`, `v1.1.0` and `v2.0.0`, and `backport`.
52
-
53
- Use labels to target an issue or a PR for a given release, add `help wanted` to good issues for new community members, and `blocker` for issues that scare you or need immediate attention. Request for more information from a submitter if an issue is not clear. Create new labels as needed by the project.
54
-
55
- ### Be Responsive
56
-
57
- Respond to enhancement requests, and forum posts. Allocate time to reviewing and commenting on issues and conversations as they come in.
58
-
59
- ### Maintain Overall Health of the Repo
60
-
61
- Keep the `main` branch at production quality at all times. Backport features as needed. Cut release branches and tags to enable future patches.
62
-
63
- ### Use Semver
64
-
65
- Use and enforce [semantic versioning](https://semver.org/) and do not let breaking changes be made outside of major releases.
66
-
67
- ### Release Frequently
68
-
69
- Make frequent project releases to the community.
70
-
71
- ### Promote Other Maintainers
72
-
73
- Assist, add, and remove [MAINTAINERS](MAINTAINERS.md). Exercise good judgement, and propose high quality contributors to become co-maintainers.
74
-
7
+ | Maintainer | GitHub ID | Affiliation |
8
+ | ----------------------- | ------------------------------------------- | ----------- |
9
+ | Jack Mazanec | [jmazanec15](https://github.com/jmazanec15) | Amazon |
10
+ | Vamshi Vijay Nakkirtha | [vamshin](https://github.com/vamshin) | Amazon |
11
+ | Vijayan Balasubramanian | [VijayanB](https://github.com/VijayanB) | Amazon |
12
+ | Deep Datta | [deepdatta](https://github.com/deepdatta) | Amazon |
13
+ | David Venable | [dlvenable](https://github.com/dlvenable) | Amazon |
14
+ | Shivani Shukla | [sshivanii](https://github.com/sshivanii) | Amazon |
data/README.md CHANGED
@@ -18,7 +18,8 @@ The logstash-output-opensearch plugin helps to ship events from Logstash to Open
18
18
  ## Project Resources
19
19
 
20
20
  * [Project Website](https://opensearch.org/)
21
- * [Documentation](https://opensearch.org/docs/clients/logstash/index/)
21
+ * [Detailed Documentation](https://opensearch.org/docs/latest/tools/logstash/ship-to-opensearch/)
22
+ * [Logstash Overview](https://opensearch.org/docs/clients/logstash/index/)
22
23
  * [Developer Guide](DEVELOPER_GUIDE.md)
23
24
  * Need help? Try [Forums](https://discuss.opendistrocommunity.dev/)
24
25
  * [Project Principles](https://opensearch.org/#principles)
@@ -44,17 +45,17 @@ output {
44
45
 
45
46
  To run the Logstash Output Opensearch plugin using aws_iam authentication, refer to the sample configuration shown below:
46
47
  ```
47
- output {
48
- opensearch {
49
- hosts => ["hostname:port"]
50
- auth_type => {
51
- type => 'aws_iam'
52
- aws_access_key_id => 'ACCESS_KEY'
53
- aws_secret_access_key => 'SECRET_KEY'
54
- region => 'us-west-2'
55
- }
56
- index => "logstash-logs-%{+YYYY.MM.dd}"
57
- }
48
+ output {
49
+ opensearch {
50
+ hosts => ["hostname:port"]
51
+ auth_type => {
52
+ type => 'aws_iam'
53
+ aws_access_key_id => 'ACCESS_KEY'
54
+ aws_secret_access_key => 'SECRET_KEY'
55
+ region => 'us-west-2'
56
+ }
57
+ index => "logstash-logs-%{+YYYY.MM.dd}"
58
+ }
58
59
  }
59
60
  ```
60
61
 
@@ -62,37 +63,53 @@ In addition to the existing authentication mechanisms, if we want to add new aut
62
63
 
63
64
  Example Configuration for basic authentication:
64
65
  ```
65
- output {
66
- opensearch {
67
- hosts => ["hostname:port"]
68
- auth_type => {
69
- type => 'basic'
70
- user => 'admin'
71
- password => 'admin'
72
- }
73
- index => "logstash-logs-%{+YYYY.MM.dd}"
74
- }
75
- }
66
+ output {
67
+ opensearch {
68
+ hosts => ["hostname:port"]
69
+ auth_type => {
70
+ type => 'basic'
71
+ user => 'admin'
72
+ password => 'admin'
73
+ }
74
+ index => "logstash-logs-%{+YYYY.MM.dd}"
75
+ }
76
+ }
76
77
  ```
77
78
 
78
79
  To ingest data into a `data stream` through logstash, we need to create the data stream and specify the name of data stream and the `op_type` of `create` in the output configuration. The sample configuration is shown below:
79
80
 
80
81
  ```yml
81
- output {
82
- opensearch {
83
- hosts => ["https://hostname:port"]
84
- auth_type => {
85
- type => 'basic'
86
- user => 'admin'
87
- password => 'admin'
82
+ output {
83
+ opensearch {
84
+ hosts => ["https://hostname:port"]
85
+ auth_type => {
86
+ type => 'basic'
87
+ user => 'admin'
88
+ password => 'admin'
88
89
  }
89
90
  index => "my-data-stream"
90
91
  action => "create"
91
- }
92
- }
92
+ }
93
+ }
94
+ ```
95
+
96
+ Starting in 2.0.0, the aws sdk version is bumped to v3. In order for all other AWS plugins to work together, please remove pre-installed aws plugins and install logstash-integration-aws plugin as follows. See also https://github.com/logstash-plugins/logstash-mixin-aws/issues/38
97
+ ```
98
+ # Remove existing logstash aws plugins and install logstash-integration-aws to keep sdk dependency the same
99
+ # https://github.com/logstash-plugins/logstash-mixin-aws/issues/38
100
+ /usr/share/logstash/bin/logstash-plugin remove logstash-input-s3
101
+ /usr/share/logstash/bin/logstash-plugin remove logstash-input-sqs
102
+ /usr/share/logstash/bin/logstash-plugin remove logstash-output-s3
103
+ /usr/share/logstash/bin/logstash-plugin remove logstash-output-sns
104
+ /usr/share/logstash/bin/logstash-plugin remove logstash-output-sqs
105
+ /usr/share/logstash/bin/logstash-plugin remove logstash-output-cloudwatch
106
+
107
+ /usr/share/logstash/bin/logstash-plugin install --version 0.1.0.pre logstash-integration-aws
108
+ bin/logstash-plugin install --version 2.0.0 logstash-output-opensearch
93
109
  ```
110
+ ## ECS Compatibility
111
+ [Elastic Common Schema(ECS)](https://www.elastic.co/guide/en/ecs/current/index.html]) compatibility for V8 was added in 1.3.0. For more details on ECS support refer to this [documentation](docs/ecs_compatibility.md).
94
112
 
95
- For more details refer to this [documentation](https://opensearch.org/docs/latest/clients/logstash/ship-to-opensearch/#opensearch-output-plugin)
96
113
 
97
114
  ## Code of Conduct
98
115
 
@@ -104,4 +121,4 @@ This project is licensed under the [Apache v2.0 License](LICENSE).
104
121
 
105
122
  ## Copyright
106
123
 
107
- Copyright OpenSearch Contributors. See [NOTICE](NOTICE) for details.
124
+ Copyright OpenSearch Contributors. See [NOTICE](NOTICE) for details.
data/RELEASING.md CHANGED
@@ -33,4 +33,8 @@ Repositories create consistent release labels, such as `v1.0.0`, `v1.1.0` and `v
33
33
 
34
34
  The release process is standard across repositories in this org and is run by a release manager volunteering from amongst [MAINTAINERS](MAINTAINERS.md).
35
35
 
36
- TODO
36
+ 1. Create a tag, e.g. 1.0.0, and push it to this GitHub repository.
37
+ 1. The [release-drafter.yml](.github/workflows/release-drafter.yml) will be automatically kicked off and a draft release will be created.
38
+ 1. This draft release triggers the [jenkins release workflow](https://build.ci.opensearch.org/job/logstash-ouput-opensearch-release) as a As a result of which the logstash-output-plugin is released on [rubygems.org](https://rubygems.org/gems/logstash-output-opensearch). Please note that the release workflow is triggered only if created release is in draft state.
39
+ 1. Once the above release workflow is successful, the drafted release on GitHub is published automatically.
40
+ 1. Increment "version" in [logstash-output-opensearch.gemspec](./logstash-output-opensearch.gemspec) to the next iteration, e.g. 1.0.1.
@@ -0,0 +1,42 @@
1
+ # ECS Compatibility Support in logstash-output-opensearch
2
+ Compatibility for ECS v8 was added in release 1.3.0 of the plugin. This would enable the plugin to work with Logstash 8.x without the need to disable ecs_compatibility.
3
+ The output plugin doesn't create any events itself, but merely forwards events to OpenSearch that were shaped by plugins preceding it in the pipeline. So, it doesn't play a direct role in making the events ECS compatible.
4
+ However, the default index templates that the plugin installs into OpenSearch in the ecs_compatibility modes (v1 & v8) ensures that the document fields stored in the indices are ECS compatible. OpenSearch would throw errors for documents that have fields which are ECS incompatible and can't be coerced.
5
+
6
+ ## ECS index templates used by logstash-output-opensearch 1.3.0
7
+ * v8 [ECS 8.0.0](https://github.com/elastic/ecs/releases/tag/v8.0.0) [ecs-8.0.0/generated/elasticsearch/legacy/template.json](https://raw.githubusercontent.com/elastic/ecs/v8.0.0/generated/elasticsearch/legacy/template.json)
8
+ * v1 [ECS 1.9.0](https://github.com/elastic/ecs/releases/tag/v1.9.0) [ecs-1.9.0/generated/elasticsearch/7/template.json](https://raw.githubusercontent.com/elastic/ecs/v1.9.0/generated/elasticsearch/7/template.json)
9
+
10
+ ## ECS incompatibility
11
+ Incompatibility can arise for an event when it has fields with the same name as an ECS defined field but a type which can't be coerced into the ECS field.
12
+ It is Ok to have fields that are not defined in ECS [ref](https://www.elastic.co/guide/en/ecs/current/ecs-faq.html#addl-fields).
13
+ The dynamic template included in the ECS templates would dynamically map any non-ECS fields.
14
+
15
+ ### Example
16
+ [ECS defines the "server"](https://www.elastic.co/guide/en/ecs/current/ecs-server.html) field as an object. But let's say the plugin gets the event below, with a string in the `server` field. It will receive an error from OpenSearch as strings can't be coerced into an object and the ECS incompatible event won't be indexed.
17
+ ```
18
+ {
19
+ "@timestamp": "2022-08-22T15:39:18.142175244Z",
20
+ "@version": "1",
21
+ "message": "Doc1",
22
+ "server": "remoteserver.com"
23
+ }
24
+ ```
25
+
26
+ Error received from OpenSearch in the Logstash logs
27
+ ```
28
+ [2022-08-23T00:01:53,366][WARN ][logstash.outputs.opensearch][main][a36555c6fad3f301db8efff2dfbed768fd85e0b6f4ee35626abe62432f83b95d] Could not index event to OpenSearch. {:status=>400, :action=>["index", {:_id=>nil, :_index=>"ecs-logstash-2022.08.23", :routing=>nil}, {"@timestamp"=>2022-08-22T15:39:18.142175244Z, "@version"=>"1", "server"=>"remoteserver.com", "message"=>"Doc1"}], :response=>{"index"=>{"_index"=>"ecs-logstash-2022.08.23", "_id"=>"CAEUyYIBQM7JQrwxF5NR", "status"=>400, "error"=>{"type"=>"mapper_parsing_exception", "reason"=>"object mapping for [server] tried to parse field [server] as object, but found a concrete value"}}}}
29
+ ```
30
+ ## How to ensure ECS compatibility
31
+ * The plugins in the pipeline that create the events like the `input` and `codec` plugins should all use ECS defined fields.
32
+ * Filter plugins like [mutate](https://github.com/logstash-plugins/logstash-filter-mutate/blob/main/docs/index.asciidoc) can be used to map incompatible fields into ECS compatible ones.
33
+ In the above example the `server` field can be mapped to the `server.domain` field to make it compatible.
34
+ * You can use your own custom template in the plugin using the `template` and `template_name` configs.
35
+ [According to this](https://www.elastic.co/guide/en/ecs/current/ecs-faq.html#type-interop) some field types can be changed while staying compatible.
36
+
37
+ As a last resort the `ecs_compatibility` config for the logstash-output-opensearch can be set to `disabled`.
38
+
39
+
40
+ _______________
41
+ ## References
42
+ * [Elastic Common Schema (ECS) Reference](https://www.elastic.co/guide/en/ecs/current/index.html)
@@ -57,7 +57,7 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
57
57
  if options[:proxy]
58
58
  options[:proxy] = manticore_proxy_hash(options[:proxy])
59
59
  end
60
-
60
+
61
61
  @manticore = ::Manticore::Client.new(options)
62
62
  end
63
63
 
@@ -76,6 +76,7 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
76
76
  instance_cred_timeout = options[:auth_type]["instance_profile_credentials_timeout"] || AWS_DEFAULT_PROFILE_CREDENTIAL_TIMEOUT
77
77
  region = options[:auth_type]["region"] || AWS_DEFAULT_REGION
78
78
  set_aws_region(region)
79
+ set_service_name(options[:auth_type]["service_name"] || AWS_SERVICE)
79
80
 
80
81
  credential_config = AWSIAMCredential.new(aws_access_key_id, aws_secret_access_key, session_token, profile, instance_cred_retries, instance_cred_timeout, region)
81
82
  @credentials = Aws::CredentialProviderChain.new(credential_config).resolve
@@ -93,6 +94,14 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
93
94
  @region
94
95
  end
95
96
 
97
+ def set_service_name(service_name)
98
+ @service_name = service_name
99
+ end
100
+
101
+ def get_service_name()
102
+ @service_name
103
+ end
104
+
96
105
  def set_user_password(options)
97
106
  @user = options[:auth_type]["user"]
98
107
  @password = options[:auth_type]["password"]
@@ -105,7 +114,7 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
105
114
  def get_password()
106
115
  @password
107
116
  end
108
-
117
+
109
118
  # Transform the proxy option to a hash. Manticore's support for non-hash
110
119
  # proxy options is broken. This was fixed in https://github.com/cheald/manticore/commit/34a00cee57a56148629ed0a47c329181e7319af5
111
120
  # but this is not yet released
@@ -137,12 +146,12 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
137
146
  params[:body] = body if body
138
147
 
139
148
  if url.user
140
- params[:auth] = {
149
+ params[:auth] = {
141
150
  :user => CGI.unescape(url.user),
142
151
  # We have to unescape the password here since manticore won't do it
143
152
  # for us unless its part of the URL
144
- :password => CGI.unescape(url.password),
145
- :eager => true
153
+ :password => CGI.unescape(url.password),
154
+ :eager => true
146
155
  }
147
156
  elsif @type == BASIC_AUTH_TYPE
148
157
  add_basic_auth_to_params(params)
@@ -174,11 +183,17 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
174
183
 
175
184
  def sign_aws_request(request_uri, path, method, params)
176
185
  url = URI::HTTPS.build({:host=>URI(request_uri.to_s).host, :port=>AWS_DEFAULT_PORT.to_s, :path=>path})
177
- key = Seahorse::Client::Http::Request.new(options={:endpoint=>url, :http_method => method.to_s.upcase,
178
- :headers => params[:headers],:body => params[:body]})
179
- aws_signer = Aws::Signers::V4.new(@credentials, AWS_SERVICE, get_aws_region )
180
- signed_key = aws_signer.sign(key)
181
- params[:headers] = params[:headers].merge(signed_key.headers)
186
+ request = Seahorse::Client::Http::Request.new(options={:endpoint=>url, :http_method => method.to_s.upcase,
187
+ :headers => params[:headers],:body => params[:body]})
188
+
189
+ aws_signer = Aws::Sigv4::Signer.new(service: @service_name, region: @region, credentials_provider: @credentials)
190
+ signed_key = aws_signer.sign_request(
191
+ http_method: request.http_method,
192
+ url: url,
193
+ headers: params[:headers],
194
+ body: params[:body]
195
+ )
196
+ params[:headers] = params[:headers].merge(signed_key.headers)
182
197
  end
183
198
 
184
199
  def add_basic_auth_to_params(params)
@@ -192,7 +207,7 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
192
207
  # Returned urls from this method should be checked for double escaping.
193
208
  def format_url(url, path_and_query=nil)
194
209
  request_uri = url.clone
195
-
210
+
196
211
  # We excise auth info from the URL in case manticore itself tries to stick
197
212
  # sensitive data in a thrown exception or log data
198
213
  request_uri.user = nil
@@ -208,7 +223,7 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
208
223
  new_query_parts = [request_uri.query, parsed_path_and_query.query].select do |part|
209
224
  part && !part.empty? # Skip empty nil and ""
210
225
  end
211
-
226
+
212
227
  request_uri.query = new_query_parts.join("&") unless new_query_parts.empty?
213
228
 
214
229
  # use `raw_path`` as `path` will unescape any escaped '/' in the path
@@ -40,6 +40,7 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
40
40
  end
41
41
 
42
42
  attr_reader :logger, :adapter, :sniffing, :sniffer_delay, :resurrect_delay, :healthcheck_path, :sniffing_path, :bulk_path
43
+ attr_reader :default_server_major_version
43
44
 
44
45
  ROOT_URI_PATH = '/'.freeze
45
46
 
@@ -68,6 +69,7 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
68
69
  @resurrect_delay = merged[:resurrect_delay]
69
70
  @sniffing = merged[:sniffing]
70
71
  @sniffer_delay = merged[:sniffer_delay]
72
+ @default_server_major_version = merged[:default_server_major_version]
71
73
  end
72
74
 
73
75
  # Used for all concurrent operations in this class
@@ -412,8 +414,15 @@ module LogStash; module Outputs; class OpenSearch; class HttpClient;
412
414
  end
413
415
 
414
416
  def get_version(url)
415
- request = perform_request_to_url(url, :get, ROOT_URI_PATH)
416
- LogStash::Json.load(request.body)["version"]["number"] # e.g. "7.10.0"
417
+ response = perform_request_to_url(url, :get, ROOT_URI_PATH)
418
+ if response.code != 404 && !response.body.empty?
419
+ return LogStash::Json.load(response.body)["version"]["number"] # e.g. "7.10.0"
420
+ end
421
+ if @default_server_major_version.nil?
422
+ @logger.error("Failed to get version from health_check endpoint and default_server_major_version is not configured.")
423
+ raise "get_version failed! no default_server_major_version configured."
424
+ end
425
+ "#{default_server_major_version}.0.0"
417
426
  end
418
427
 
419
428
  def last_version
@@ -107,7 +107,6 @@ module LogStash; module Outputs; class OpenSearch;
107
107
 
108
108
  body_stream = StringIO.new
109
109
  if http_compression
110
- body_stream.set_encoding "BINARY"
111
110
  stream_writer = gzip_writer(body_stream)
112
111
  else
113
112
  stream_writer = body_stream
@@ -126,9 +125,24 @@ module LogStash; module Outputs; class OpenSearch;
126
125
  :payload_size => stream_writer.pos,
127
126
  :content_length => body_stream.size,
128
127
  :batch_offset => (index + 1 - batch_actions.size))
128
+
129
+ # Have to close gzip writer before reading from body_stream; otherwise stream doesn't end properly
130
+ # and will cause server side error
131
+ if http_compression
132
+ stream_writer.close
133
+ end
134
+
129
135
  bulk_responses << bulk_send(body_stream, batch_actions)
130
- body_stream.truncate(0) && body_stream.seek(0)
131
- stream_writer = gzip_writer(body_stream) if http_compression
136
+
137
+ if http_compression
138
+ # Get a new StringIO object and gzip writer
139
+ body_stream = StringIO.new
140
+ stream_writer = gzip_writer(body_stream)
141
+ else
142
+ # Clear existing StringIO object and reuse existing stream writer
143
+ body_stream.truncate(0) && body_stream.seek(0)
144
+ end
145
+
132
146
  batch_actions.clear
133
147
  end
134
148
  stream_writer.write(as_json)
@@ -149,6 +163,7 @@ module LogStash; module Outputs; class OpenSearch;
149
163
  fail(ArgumentError, "Cannot create gzip writer on IO with unread bytes") unless io.eof?
150
164
  fail(ArgumentError, "Cannot create gzip writer on non-empty IO") unless io.pos == 0
151
165
 
166
+ io.set_encoding "BINARY"
152
167
  Zlib::GzipWriter.new(io, Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY)
153
168
  end
154
169
 
@@ -328,7 +343,8 @@ module LogStash; module Outputs; class OpenSearch;
328
343
  :healthcheck_path => options[:healthcheck_path],
329
344
  :resurrect_delay => options[:resurrect_delay],
330
345
  :url_normalizer => self.method(:host_to_url),
331
- :metric => options[:metric]
346
+ :metric => options[:metric],
347
+ :default_server_major_version => options[:default_server_major_version]
332
348
  }
333
349
  pool_options[:scheme] = self.scheme if self.scheme
334
350
 
@@ -388,10 +404,16 @@ module LogStash; module Outputs; class OpenSearch;
388
404
  @pool.put(path, nil, LogStash::Json.dump(template))
389
405
  end
390
406
 
407
+ def legacy_template?()
408
+ # TODO: Also check Version and return true for < 7.8 even if :legacy_template=false
409
+ # Need to figure a way to distinguish between OpenSearch, OpenDistro and other
410
+ # variants, since they have version numbers in different ranges.
411
+ client_settings.fetch(:legacy_template, true)
412
+ end
413
+
391
414
  def template_endpoint
392
- # TODO: Check Version < 7.8 and use index template for >= 7.8 & OpenSearch
393
415
  # https://opensearch.org/docs/opensearch/index-templates/
394
- '_template'
416
+ legacy_template?() ? '_template' : '_index_template'
395
417
  end
396
418
 
397
419
  # check whether rollover alias already exists
@@ -18,7 +18,8 @@ module LogStash; module Outputs; class OpenSearch;
18
18
  :pool_max_per_route => params["pool_max_per_route"],
19
19
  :check_connection_timeout => params["validate_after_inactivity"],
20
20
  :http_compression => params["http_compression"],
21
- :headers => params["custom_headers"] || {}
21
+ :headers => params["custom_headers"] || {},
22
+ :legacy_template => params["legacy_template"]
22
23
  }
23
24
 
24
25
  client_settings[:proxy] = params["proxy"] if params["proxy"]
@@ -26,7 +27,8 @@ module LogStash; module Outputs; class OpenSearch;
26
27
  common_options = {
27
28
  :client_settings => client_settings,
28
29
  :metric => params["metric"],
29
- :resurrect_delay => params["resurrect_delay"]
30
+ :resurrect_delay => params["resurrect_delay"],
31
+ :default_server_major_version => params["default_server_major_version"]
30
32
  }
31
33
 
32
34
  if params["sniffing"]
@@ -18,7 +18,7 @@ module LogStash; module Outputs; class OpenSearch
18
18
  else
19
19
  plugin.logger.info("Using a default mapping template", :version => plugin.maximum_seen_major_version,
20
20
  :ecs_compatibility => plugin.ecs_compatibility)
21
- template = load_default_template(plugin.maximum_seen_major_version, plugin.ecs_compatibility)
21
+ template = load_default_template(plugin.maximum_seen_major_version, plugin.ecs_compatibility, plugin.client.legacy_template?)
22
22
  end
23
23
 
24
24
  plugin.logger.debug("Attempting to install template", template: template)
@@ -26,8 +26,8 @@ module LogStash; module Outputs; class OpenSearch
26
26
  end
27
27
 
28
28
  private
29
- def self.load_default_template(major_version, ecs_compatibility)
30
- template_path = default_template_path(major_version, ecs_compatibility)
29
+ def self.load_default_template(major_version, ecs_compatibility, legacy_template)
30
+ template_path = default_template_path(major_version, ecs_compatibility, legacy_template)
31
31
  read_template_file(template_path)
32
32
  rescue => e
33
33
  fail "Failed to load default template for OpenSearch v#{major_version} with ECS #{ecs_compatibility}; caused by: #{e.inspect}"
@@ -45,9 +45,10 @@ module LogStash; module Outputs; class OpenSearch
45
45
  plugin.template_name
46
46
  end
47
47
 
48
- def self.default_template_path(major_version, ecs_compatibility=:disabled)
48
+ def self.default_template_path(major_version, ecs_compatibility=:disabled, legacy_template=true)
49
49
  template_version = major_version
50
- default_template_name = "templates/ecs-#{ecs_compatibility}/#{template_version}x.json"
50
+ suffix = legacy_template ? "" : "_index"
51
+ default_template_name = "templates/ecs-#{ecs_compatibility}/#{template_version}x#{suffix}.json"
51
52
  ::File.expand_path(default_template_name, ::File.dirname(__FILE__))
52
53
  end
53
54
 
@@ -0,0 +1,66 @@
1
+ {
2
+ "index_patterns": "logstash-*",
3
+ "version": 60001,
4
+ "priority": 10,
5
+ "template": {
6
+ "settings": {
7
+ "index.refresh_interval": "5s",
8
+ "number_of_shards": 1
9
+ },
10
+ "mappings": {
11
+ "dynamic_templates": [
12
+ {
13
+ "message_field": {
14
+ "path_match": "message",
15
+ "match_mapping_type": "string",
16
+ "mapping": {
17
+ "type": "text",
18
+ "norms": false
19
+ }
20
+ }
21
+ },
22
+ {
23
+ "string_fields": {
24
+ "match": "*",
25
+ "match_mapping_type": "string",
26
+ "mapping": {
27
+ "type": "text",
28
+ "norms": false,
29
+ "fields": {
30
+ "keyword": {
31
+ "type": "keyword",
32
+ "ignore_above": 256
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+ ],
39
+ "properties": {
40
+ "@timestamp": {
41
+ "type": "date"
42
+ },
43
+ "@version": {
44
+ "type": "keyword"
45
+ },
46
+ "geoip": {
47
+ "dynamic": true,
48
+ "properties": {
49
+ "ip": {
50
+ "type": "ip"
51
+ },
52
+ "location": {
53
+ "type": "geo_point"
54
+ },
55
+ "latitude": {
56
+ "type": "half_float"
57
+ },
58
+ "longitude": {
59
+ "type": "half_float"
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }