logstash-output-opensearch 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ADMINS.md +29 -0
  5. data/CODE_OF_CONDUCT.md +25 -0
  6. data/CONTRIBUTING.md +99 -0
  7. data/DEVELOPER_GUIDE.md +208 -0
  8. data/Gemfile +20 -0
  9. data/LICENSE +202 -0
  10. data/MAINTAINERS.md +71 -0
  11. data/NOTICE +2 -0
  12. data/README.md +37 -0
  13. data/RELEASING.md +36 -0
  14. data/SECURITY.md +3 -0
  15. data/lib/logstash/outputs/opensearch.rb +449 -0
  16. data/lib/logstash/outputs/opensearch/distribution_checker.rb +44 -0
  17. data/lib/logstash/outputs/opensearch/http_client.rb +465 -0
  18. data/lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb +140 -0
  19. data/lib/logstash/outputs/opensearch/http_client/pool.rb +467 -0
  20. data/lib/logstash/outputs/opensearch/http_client_builder.rb +182 -0
  21. data/lib/logstash/outputs/opensearch/template_manager.rb +60 -0
  22. data/lib/logstash/outputs/opensearch/templates/ecs-disabled/1x.json +44 -0
  23. data/lib/logstash/outputs/opensearch/templates/ecs-disabled/7x.json +44 -0
  24. data/lib/logstash/plugin_mixins/opensearch/api_configs.rb +168 -0
  25. data/lib/logstash/plugin_mixins/opensearch/common.rb +294 -0
  26. data/lib/logstash/plugin_mixins/opensearch/noop_distribution_checker.rb +18 -0
  27. data/logstash-output-opensearch.gemspec +40 -0
  28. data/spec/fixtures/_nodes/nodes.json +74 -0
  29. data/spec/fixtures/htpasswd +2 -0
  30. data/spec/fixtures/nginx_reverse_proxy.conf +22 -0
  31. data/spec/fixtures/scripts/painless/scripted_update.painless +2 -0
  32. data/spec/fixtures/scripts/painless/scripted_update_nested.painless +1 -0
  33. data/spec/fixtures/scripts/painless/scripted_upsert.painless +1 -0
  34. data/spec/integration/outputs/compressed_indexing_spec.rb +76 -0
  35. data/spec/integration/outputs/create_spec.rb +76 -0
  36. data/spec/integration/outputs/delete_spec.rb +72 -0
  37. data/spec/integration/outputs/index_spec.rb +164 -0
  38. data/spec/integration/outputs/index_version_spec.rb +110 -0
  39. data/spec/integration/outputs/ingest_pipeline_spec.rb +82 -0
  40. data/spec/integration/outputs/metrics_spec.rb +75 -0
  41. data/spec/integration/outputs/no_opensearch_on_startup_spec.rb +67 -0
  42. data/spec/integration/outputs/painless_update_spec.rb +147 -0
  43. data/spec/integration/outputs/parent_spec.rb +103 -0
  44. data/spec/integration/outputs/retry_spec.rb +182 -0
  45. data/spec/integration/outputs/routing_spec.rb +70 -0
  46. data/spec/integration/outputs/sniffer_spec.rb +70 -0
  47. data/spec/integration/outputs/templates_spec.rb +105 -0
  48. data/spec/integration/outputs/update_spec.rb +123 -0
  49. data/spec/opensearch_spec_helper.rb +141 -0
  50. data/spec/spec_helper.rb +19 -0
  51. data/spec/unit/http_client_builder_spec.rb +194 -0
  52. data/spec/unit/outputs/error_whitelist_spec.rb +62 -0
  53. data/spec/unit/outputs/opensearch/http_client/manticore_adapter_spec.rb +159 -0
  54. data/spec/unit/outputs/opensearch/http_client/pool_spec.rb +306 -0
  55. data/spec/unit/outputs/opensearch/http_client_spec.rb +292 -0
  56. data/spec/unit/outputs/opensearch/template_manager_spec.rb +36 -0
  57. data/spec/unit/outputs/opensearch_proxy_spec.rb +112 -0
  58. data/spec/unit/outputs/opensearch_spec.rb +800 -0
  59. data/spec/unit/outputs/opensearch_ssl_spec.rb +179 -0
  60. metadata +289 -0
  61. metadata.gz.sig +0 -0
@@ -0,0 +1,182 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # The OpenSearch Contributors require contributions made to
4
+ # this file be licensed under the Apache-2.0 license or a
5
+ # compatible open source license.
6
+ #
7
+ # Modifications Copyright OpenSearch Contributors. See
8
+ # GitHub history for details.
9
+
10
+ require 'cgi'
11
+ require "base64"
12
+
13
+ module LogStash; module Outputs; class OpenSearch;
14
+ module HttpClientBuilder
15
+ def self.build(logger, hosts, params)
16
+ client_settings = {
17
+ :pool_max => params["pool_max"],
18
+ :pool_max_per_route => params["pool_max_per_route"],
19
+ :check_connection_timeout => params["validate_after_inactivity"],
20
+ :http_compression => params["http_compression"],
21
+ :headers => params["custom_headers"] || {}
22
+ }
23
+
24
+ client_settings[:proxy] = params["proxy"] if params["proxy"]
25
+
26
+ common_options = {
27
+ :distribution_checker => params["distribution_checker"],
28
+ :client_settings => client_settings,
29
+ :metric => params["metric"],
30
+ :resurrect_delay => params["resurrect_delay"]
31
+ }
32
+
33
+ if params["sniffing"]
34
+ common_options[:sniffing] = true
35
+ common_options[:sniffer_delay] = params["sniffing_delay"]
36
+ end
37
+
38
+ common_options[:timeout] = params["timeout"] if params["timeout"]
39
+
40
+ if params["path"]
41
+ client_settings[:path] = dedup_slashes("/#{params["path"]}/")
42
+ end
43
+
44
+ common_options[:bulk_path] = if params["bulk_path"]
45
+ dedup_slashes("/#{params["bulk_path"]}")
46
+ else
47
+ dedup_slashes("/#{params["path"]}/_bulk")
48
+ end
49
+
50
+ common_options[:sniffing_path] = if params["sniffing_path"]
51
+ dedup_slashes("/#{params["sniffing_path"]}")
52
+ else
53
+ dedup_slashes("/#{params["path"]}/_nodes/http")
54
+ end
55
+
56
+ common_options[:healthcheck_path] = if params["healthcheck_path"]
57
+ dedup_slashes("/#{params["healthcheck_path"]}")
58
+ else
59
+ dedup_slashes("/#{params["path"]}")
60
+ end
61
+
62
+ if params["parameters"]
63
+ client_settings[:parameters] = params["parameters"]
64
+ end
65
+
66
+ logger.debug? && logger.debug("Normalizing http path", :path => params["path"], :normalized => client_settings[:path])
67
+
68
+ client_settings.merge! setup_ssl(logger, params)
69
+ common_options.merge! setup_basic_auth(logger, params)
70
+
71
+ external_version_types = ["external", "external_gt", "external_gte"]
72
+ # External Version validation
73
+ raise(
74
+ LogStash::ConfigurationError,
75
+ "External versioning requires the presence of a version number."
76
+ ) if external_version_types.include?(params.fetch('version_type', '')) and params.fetch("version", nil) == nil
77
+
78
+
79
+ # Create API setup
80
+ raise(
81
+ LogStash::ConfigurationError,
82
+ "External versioning is not supported by the create action."
83
+ ) if params['action'] == 'create' and external_version_types.include?(params.fetch('version_type', ''))
84
+
85
+ # Update API setup
86
+ raise( LogStash::ConfigurationError,
87
+ "doc_as_upsert and scripted_upsert are mutually exclusive."
88
+ ) if params["doc_as_upsert"] and params["scripted_upsert"]
89
+
90
+ raise(
91
+ LogStash::ConfigurationError,
92
+ "Specifying action => 'update' needs a document_id."
93
+ ) if params['action'] == 'update' and params.fetch('document_id', '') == ''
94
+
95
+ raise(
96
+ LogStash::ConfigurationError,
97
+ "External versioning is not supported by the update action."
98
+ ) if params['action'] == 'update' and external_version_types.include?(params.fetch('version_type', ''))
99
+
100
+ # Update API setup
101
+ update_options = {
102
+ :doc_as_upsert => params["doc_as_upsert"],
103
+ :script_var_name => params["script_var_name"],
104
+ :script_type => params["script_type"],
105
+ :script_lang => params["script_lang"],
106
+ :scripted_upsert => params["scripted_upsert"]
107
+ }
108
+ common_options.merge! update_options if params["action"] == 'update'
109
+
110
+ create_http_client(common_options.merge(:hosts => hosts, :logger => logger))
111
+ end
112
+
113
+ def self.create_http_client(options)
114
+ LogStash::Outputs::OpenSearch::HttpClient.new(options)
115
+ end
116
+
117
+ def self.setup_ssl(logger, params)
118
+ params["ssl"] = true if params["hosts"].any? {|h| h.scheme == "https" }
119
+ return {} if params["ssl"].nil?
120
+
121
+ return {:ssl => {:enabled => false}} if params["ssl"] == false
122
+
123
+ cacert, truststore, truststore_password, keystore, keystore_password, tls_client_cert, tls_client_key =
124
+ params.values_at('cacert', 'truststore', 'truststore_password', 'keystore', 'keystore_password', 'tls_certificate', 'tls_key')
125
+
126
+ if cacert && truststore
127
+ raise(LogStash::ConfigurationError, "Use either \"cacert\" or \"truststore\" when configuring the CA certificate") if truststore
128
+ end
129
+
130
+ if (tls_client_cert && !tls_client_key)
131
+ raise(LogStash::ConfigurationError, "\"tls_key\" is missing")
132
+ end
133
+
134
+ if (!tls_client_cert && tls_client_key)
135
+ raise(LogStash::ConfigurationError, "\"tls_certificate\" is missing")
136
+ end
137
+
138
+ ssl_options = {:enabled => true}
139
+
140
+ if cacert
141
+ ssl_options[:ca_file] = cacert
142
+ elsif truststore
143
+ ssl_options[:truststore_password] = truststore_password.value if truststore_password
144
+ end
145
+
146
+ ssl_options[:truststore] = truststore if truststore
147
+ if keystore
148
+ ssl_options[:keystore] = keystore
149
+ ssl_options[:keystore_password] = keystore_password.value if keystore_password
150
+ end
151
+ if (tls_client_cert && tls_client_key)
152
+ ssl_options[:client_cert] = tls_client_cert
153
+ ssl_options[:client_key] = tls_client_key
154
+ end
155
+ if !params["ssl_certificate_verification"]
156
+ logger.warn [
157
+ "** WARNING ** Detected UNSAFE options in opensearch output configuration!",
158
+ "** WARNING ** You have enabled encryption but DISABLED certificate verification.",
159
+ "** WARNING ** To make sure your data is secure change :ssl_certificate_verification to true"
160
+ ].join("\n")
161
+ ssl_options[:verify] = false
162
+ end
163
+ { ssl: ssl_options }
164
+ end
165
+
166
+ def self.setup_basic_auth(logger, params)
167
+ user, password = params["user"], params["password"]
168
+
169
+ return {} unless user && password && password.value
170
+
171
+ {
172
+ :user => CGI.escape(user),
173
+ :password => CGI.escape(password.value)
174
+ }
175
+ end
176
+
177
+ private
178
+ def self.dedup_slashes(url)
179
+ url.gsub(/\/+/, "/")
180
+ end
181
+ end
182
+ end; end; end
@@ -0,0 +1,60 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # The OpenSearch Contributors require contributions made to
4
+ # this file be licensed under the Apache-2.0 license or a
5
+ # compatible open source license.
6
+ #
7
+ # Modifications Copyright OpenSearch Contributors. See
8
+ # GitHub history for details.
9
+
10
+ module LogStash; module Outputs; class OpenSearch
11
+ class TemplateManager
12
+ # To be mixed into the opensearch plugin base
13
+ def self.install_template(plugin)
14
+ return unless plugin.manage_template
15
+ if plugin.template
16
+ plugin.logger.info("Using mapping template from", :path => plugin.template)
17
+ template = read_template_file(plugin.template)
18
+ else
19
+ plugin.logger.info("Using a default mapping template", :version => plugin.maximum_seen_major_version,
20
+ :ecs_compatibility => plugin.ecs_compatibility)
21
+ template = load_default_template(plugin.maximum_seen_major_version, plugin.ecs_compatibility)
22
+ end
23
+
24
+ plugin.logger.debug("Attempting to install template", template: template)
25
+ install(plugin.client, template_name(plugin), template, plugin.template_overwrite)
26
+ end
27
+
28
+ private
29
+ def self.load_default_template(major_version, ecs_compatibility)
30
+ template_path = default_template_path(major_version, ecs_compatibility)
31
+ read_template_file(template_path)
32
+ rescue => e
33
+ fail "Failed to load default template for OpenSearch v#{major_version} with ECS #{ecs_compatibility}; caused by: #{e.inspect}"
34
+ end
35
+
36
+ def self.install(client, template_name, template, template_overwrite)
37
+ client.template_install(template_name, template, template_overwrite)
38
+ end
39
+
40
+ def self.template_settings(plugin, template)
41
+ template['settings']
42
+ end
43
+
44
+ def self.template_name(plugin)
45
+ plugin.template_name
46
+ end
47
+
48
+ def self.default_template_path(major_version, ecs_compatibility=:disabled)
49
+ template_version = major_version
50
+ default_template_name = "templates/ecs-#{ecs_compatibility}/#{template_version}x.json"
51
+ ::File.expand_path(default_template_name, ::File.dirname(__FILE__))
52
+ end
53
+
54
+ def self.read_template_file(template_path)
55
+ raise ArgumentError, "Template file '#{template_path}' could not be found" unless ::File.exists?(template_path)
56
+ template_data = ::IO.read(template_path)
57
+ LogStash::Json.load(template_data)
58
+ end
59
+ end
60
+ end end end
@@ -0,0 +1,44 @@
1
+ {
2
+ "index_patterns" : "logstash-*",
3
+ "version" : 60001,
4
+ "settings" : {
5
+ "index.refresh_interval" : "5s",
6
+ "number_of_shards": 1
7
+ },
8
+ "mappings" : {
9
+ "dynamic_templates" : [ {
10
+ "message_field" : {
11
+ "path_match" : "message",
12
+ "match_mapping_type" : "string",
13
+ "mapping" : {
14
+ "type" : "text",
15
+ "norms" : false
16
+ }
17
+ }
18
+ }, {
19
+ "string_fields" : {
20
+ "match" : "*",
21
+ "match_mapping_type" : "string",
22
+ "mapping" : {
23
+ "type" : "text", "norms" : false,
24
+ "fields" : {
25
+ "keyword" : { "type": "keyword", "ignore_above": 256 }
26
+ }
27
+ }
28
+ }
29
+ } ],
30
+ "properties" : {
31
+ "@timestamp": { "type": "date"},
32
+ "@version": { "type": "keyword"},
33
+ "geoip" : {
34
+ "dynamic": true,
35
+ "properties" : {
36
+ "ip": { "type": "ip" },
37
+ "location" : { "type" : "geo_point" },
38
+ "latitude" : { "type" : "half_float" },
39
+ "longitude" : { "type" : "half_float" }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "index_patterns" : "logstash-*",
3
+ "version" : 60001,
4
+ "settings" : {
5
+ "index.refresh_interval" : "5s",
6
+ "number_of_shards": 1
7
+ },
8
+ "mappings" : {
9
+ "dynamic_templates" : [ {
10
+ "message_field" : {
11
+ "path_match" : "message",
12
+ "match_mapping_type" : "string",
13
+ "mapping" : {
14
+ "type" : "text",
15
+ "norms" : false
16
+ }
17
+ }
18
+ }, {
19
+ "string_fields" : {
20
+ "match" : "*",
21
+ "match_mapping_type" : "string",
22
+ "mapping" : {
23
+ "type" : "text", "norms" : false,
24
+ "fields" : {
25
+ "keyword" : { "type": "keyword", "ignore_above": 256 }
26
+ }
27
+ }
28
+ }
29
+ } ],
30
+ "properties" : {
31
+ "@timestamp": { "type": "date"},
32
+ "@version": { "type": "keyword"},
33
+ "geoip" : {
34
+ "dynamic": true,
35
+ "properties" : {
36
+ "ip": { "type": "ip" },
37
+ "location" : { "type" : "geo_point" },
38
+ "latitude" : { "type" : "half_float" },
39
+ "longitude" : { "type" : "half_float" }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,168 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # The OpenSearch Contributors require contributions made to
4
+ # this file be licensed under the Apache-2.0 license or a
5
+ # compatible open source license.
6
+ #
7
+ # Modifications Copyright OpenSearch Contributors. See
8
+ # GitHub history for details.
9
+
10
+ module LogStash; module PluginMixins; module OpenSearch
11
+ module APIConfigs
12
+
13
+ # This module defines common options that can be reused by alternate OpenSearch output plugins.
14
+
15
+ DEFAULT_HOST = ::LogStash::Util::SafeURI.new("//127.0.0.1")
16
+
17
+ CONFIG_PARAMS = {
18
+ # Username to authenticate to a secure OpenSearch cluster
19
+ :user => { :validate => :string },
20
+ # Password to authenticate to a secure OpenSearch cluster
21
+ :password => { :validate => :password },
22
+
23
+ # The document ID for the index. Useful for overwriting existing entries in
24
+ # OpenSearch with the same ID.
25
+ :document_id => { :validate => :string },
26
+
27
+ # HTTP Path at which the OpenSearch server lives. Use this if you must run OpenSearch behind a proxy that remaps
28
+ # the root path for the OpenSearch HTTP API lives.
29
+ # Note that if you use paths as components of URLs in the 'hosts' field you may
30
+ # not also set this field. That will raise an error at startup
31
+ :path => { :validate => :string },
32
+
33
+ # HTTP Path to perform the _bulk requests to
34
+ # this defaults to a concatenation of the path parameter and "_bulk"
35
+ :bulk_path => { :validate => :string },
36
+
37
+ # Pass a set of key value pairs as the URL query string. This query string is added
38
+ # to every host listed in the 'hosts' configuration. If the 'hosts' list contains
39
+ # urls that already have query strings, the one specified here will be appended.
40
+ :parameters => { :validate => :hash },
41
+
42
+ # Enable SSL/TLS secured communication to OpenSearch cluster. Leaving this unspecified will use whatever scheme
43
+ # is specified in the URLs listed in 'hosts'. If no explicit protocol is specified plain HTTP will be used.
44
+ # If SSL is explicitly disabled here the plugin will refuse to start if an HTTPS URL is given in 'hosts'
45
+ :ssl => { :validate => :boolean },
46
+
47
+ # Option to validate the server's certificate. Disabling this severely compromises security.
48
+ # For more information on disabling certificate verification please read
49
+ # https://www.cs.utexas.edu/~shmat/shmat_ccs12.pdf
50
+ :ssl_certificate_verification => { :validate => :boolean, :default => true },
51
+
52
+ # The .cer or .pem file to validate the server's certificate
53
+ :cacert => { :validate => :path },
54
+
55
+ # The JKS truststore to validate the server's certificate.
56
+ # Use either `:truststore` or `:cacert`
57
+ :truststore => { :validate => :path },
58
+
59
+ # Set the truststore password
60
+ :truststore_password => { :validate => :password },
61
+
62
+ # The keystore used to present a certificate to the server.
63
+ # It can be either .jks or .p12
64
+ :keystore => { :validate => :path },
65
+
66
+ # Set the keystore password
67
+ :keystore_password => { :validate => :password },
68
+
69
+ # Set the TLS Client certificate file
70
+ :tls_certificate => { :validate => :path },
71
+
72
+ # Private key file name
73
+ :tls_key => { :validate => :path },
74
+
75
+ # This setting asks OpenSearch for the list of all cluster nodes and adds them to the hosts list.
76
+ # Note: This will return ALL nodes with HTTP enabled (including master nodes!). If you use
77
+ # this with master nodes, you probably want to disable HTTP on them by setting
78
+ # `http.enabled` to false in their OpenSearch.yml. You can either use the `sniffing` option or
79
+ # manually enter multiple OpenSearch hosts using the `hosts` parameter.
80
+ :sniffing => { :validate => :boolean, :default => false },
81
+
82
+ # How long to wait, in seconds, between sniffing attempts
83
+ :sniffing_delay => { :validate => :number, :default => 5 },
84
+
85
+ # HTTP Path to be used for the sniffing requests
86
+ # the default value is computed by concatenating the path value and "_nodes/http"
87
+ # if sniffing_path is set it will be used as an absolute path
88
+ # do not use full URL here, only paths, e.g. "/sniff/_nodes/http"
89
+ :sniffing_path => { :validate => :string },
90
+
91
+ # Set the address of a forward HTTP proxy.
92
+ # This used to accept hashes as arguments but now only accepts
93
+ # arguments of the URI type to prevent leaking credentials.
94
+ :proxy => { :validate => :uri }, # but empty string is allowed
95
+
96
+ # Set the timeout, in seconds, for network operations and requests sent OpenSearch. If
97
+ # a timeout occurs, the request will be retried.
98
+ :timeout => { :validate => :number, :default => 60 },
99
+
100
+ # Set the OpenSearch errors in the whitelist that you don't want to log.
101
+ # A useful example is when you want to skip all 409 errors
102
+ # which are `document_already_exists_exception`.
103
+ :failure_type_logging_whitelist => { :validate => :array, :default => [] },
104
+
105
+ # While the output tries to reuse connections efficiently we have a maximum.
106
+ # This sets the maximum number of open connections the output will create.
107
+ # Setting this too low may mean frequently closing / opening connections
108
+ # which is bad.
109
+ :pool_max => { :validate => :number, :default => 1000 },
110
+
111
+ # While the output tries to reuse connections efficiently we have a maximum per endpoint.
112
+ # This sets the maximum number of open connections per endpoint the output will create.
113
+ # Setting this too low may mean frequently closing / opening connections
114
+ # which is bad.
115
+ :pool_max_per_route => { :validate => :number, :default => 100 },
116
+
117
+ # HTTP Path where a HEAD request is sent when a backend is marked down
118
+ # the request is sent in the background to see if it has come back again
119
+ # before it is once again eligible to service requests.
120
+ # If you have custom firewall rules you may need to change this
121
+ :healthcheck_path => { :validate => :string },
122
+
123
+ # How frequently, in seconds, to wait between resurrection attempts.
124
+ # Resurrection is the process by which backend endpoints marked 'down' are checked
125
+ # to see if they have come back to life
126
+ :resurrect_delay => { :validate => :number, :default => 5 },
127
+
128
+ # How long to wait before checking if the connection is stale before executing a request on a connection using keepalive.
129
+ # You may want to set this lower, if you get connection errors regularly
130
+ # Quoting the Apache commons docs (this client is based Apache Commmons):
131
+ # 'Defines period of inactivity in milliseconds after which persistent connections must
132
+ # be re-validated prior to being leased to the consumer. Non-positive value passed to
133
+ # this method disables connection validation. This check helps detect connections that
134
+ # have become stale (half-closed) while kept inactive in the pool.'
135
+ # See https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html#setValidateAfterInactivity(int)[these docs for more info]
136
+ :validate_after_inactivity => { :validate => :number, :default => 10000 },
137
+
138
+ # Enable gzip compression on requests.
139
+ :http_compression => { :validate => :boolean, :default => false },
140
+
141
+ # Custom Headers to send on each request to OpenSearch nodes
142
+ :custom_headers => { :validate => :hash, :default => {} },
143
+
144
+ # Sets the host(s) of the remote instance. If given an array it will load balance requests across the hosts specified in the `hosts` parameter.
145
+ # Remember the `http` protocol uses the http address (eg. 9200, not 9300).
146
+ # `"127.0.0.1"`
147
+ # `["127.0.0.1:9200","127.0.0.2:9200"]`
148
+ # `["http://127.0.0.1"]`
149
+ # `["https://127.0.0.1:9200"]`
150
+ # `["https://127.0.0.1:9200/mypath"]` (If using a proxy on a subpath)
151
+ # It is important to exclude dedicated master nodes from the `hosts` list
152
+ # to prevent LS from sending bulk requests to the master nodes. So this parameter should only reference either data or client nodes in OpenSearch.
153
+ #
154
+ # Any special characters present in the URLs here MUST be URL escaped! This means `#` should be put in as `%23` for instance.
155
+ :hosts => { :validate => :uri, :default => [ DEFAULT_HOST ], :list => true },
156
+
157
+ # Set initial interval in seconds between bulk retries. Doubled on each retry up to `retry_max_interval`
158
+ :retry_initial_interval => { :validate => :number, :default => 2 },
159
+
160
+ # Set max interval in seconds between bulk retries.
161
+ :retry_max_interval => { :validate => :number, :default => 64 }
162
+ }.freeze
163
+
164
+ def self.included(base)
165
+ CONFIG_PARAMS.each { |name, opts| base.config(name, opts) }
166
+ end
167
+ end
168
+ end; end; end