fluent-plugin-elasticsearch 2.0.0.rc.5 → 2.0.0.rc.6

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
  SHA1:
3
- metadata.gz: 9cc6bc3f6b89a0735bf96c5c0575d39e58458746
4
- data.tar.gz: ee98c63584d8249795b5e4c1e1a75fcc2059b2ab
3
+ metadata.gz: ac60b728ec23b3ba9a24a87f1b58fcf3dbf2376f
4
+ data.tar.gz: fe9d1c7d1f5c07d84a69e27bc534c6c6db5512b6
5
5
  SHA512:
6
- metadata.gz: eb6c6cb81709dc0b7aa2845e64346621db2cfed45ff16d75cb2384e669cfe8e0497efb8b1d36ea94dbc82da40397347662c118afeaef91347f30b73d93ec940f
7
- data.tar.gz: e7eef17ef1e8cab63f79baebba312410455c997c1a5a2128416b48b5bf26c47320c93835e70167b8e218dc022b9171b9d7e802653e205c76dfc81018cfbf3689
6
+ metadata.gz: 51b2bf67047821e1d028acdc507d9f1f235444cd6ffa2d0f6dded6284231ef86473aed7e2e448daa89af31ff3a6cbb2a05aa17a36be5a8717a9a1473ad05941d
7
+ data.tar.gz: b5a8317b90ddd6b52a8c6cdd2fddf7f609682422bcd24308332d1a760acf990851fb3bfde16d7c6ccd7c430aeb0f1b03186e163c21b35d4a00f4b1b87242ad57
data/History.md CHANGED
@@ -4,6 +4,11 @@
4
4
  - Log ES response errors (#230)
5
5
  - Use latest elasticsearch-ruby (#240)
6
6
 
7
+ ### 2.0.0.rc.6
8
+ - Improve documentation (#304)
9
+ - Handle dynamic_config misconfigurations (#305)
10
+ - Escape basic authentication user information placeholders (#306)
11
+
7
12
  ### 2.0.0.rc.5
8
13
  - make configurable with `ssl_version` parameter (#299)
9
14
  - add `logstash_prefix_separator` config parameter (#297)
data/README.md CHANGED
@@ -109,6 +109,12 @@ You can specify multiple ElasticSearch hosts with separator ",".
109
109
 
110
110
  If you specify multiple hosts, this plugin will load balance updates to ElasticSearch. This is an [elasticsearch-ruby](https://github.com/elasticsearch/elasticsearch-ruby) feature, the default strategy is round-robin.
111
111
 
112
+ And this plugin will escape required URL encoded characters within `%{}` placeholders.
113
+
114
+ ```
115
+ hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
116
+ ```
117
+
112
118
  ### user, password, path, scheme, ssl_verify
113
119
 
114
120
  If you specify this option, host and port options are ignored.
@@ -122,6 +128,13 @@ scheme https
122
128
 
123
129
  You can specify user and password for HTTP basic auth. If used in conjunction with a hosts list, then these options will be used by default i.e. if you do not provide any of these options within the hosts listed.
124
130
 
131
+ And this plugin will escape required URL encoded characters within `%{}` placeholders.
132
+
133
+ ```
134
+ user %{demo+}
135
+ password %{@secret}
136
+ ```
137
+
125
138
  Specify `ssl_verify false` to skip ssl verification (defaults to true)
126
139
 
127
140
  ### logstash_format
@@ -132,6 +145,8 @@ logstash_format true # defaults to false
132
145
 
133
146
  This is meant to make writing data into ElasticSearch indices compatible to what [Logstash](https://www.elastic.co/products/logstash) calls them. By doing this, one could take advantage of [Kibana](https://www.elastic.co/products/kibana). See logstash_prefix and logstash_dateformat to customize this index name pattern. The index name will be `#{logstash_prefix}-#{formated_date}`
134
147
 
148
+ :warning: Setting this option to `true` will ignore the `index_name` setting. The default index name prefix is `logstash-`.
149
+
135
150
  ### logstash_prefix
136
151
 
137
152
  ```
@@ -185,7 +200,7 @@ For example, should your input plugin not include a `time_key` in the record but
185
200
  By default, when inserting records in [Logstash](https://www.elastic.co/products/logstash) format, `@timestamp` is dynamically created with the time at log ingestion. If you'd like to use a custom time, include an `@timestamp` with your record.
186
201
 
187
202
  ```
188
- {"@timestamp":"2014-04-07T000:00:00-00:00"}
203
+ {"@timestamp": "2014-04-07T000:00:00-00:00"}
189
204
  ```
190
205
 
191
206
  You can specify an option `time_key` (like the option described in [tail Input Plugin](http://docs.fluentd.org/articles/in_tail)) to replace `@timestamp` key.
@@ -348,7 +363,7 @@ This will add the Fluentd tag in the JSON record. For instance, if you have a co
348
363
  The record inserted into ElasticSearch would be
349
364
 
350
365
  ```
351
- {"_key":"my.logs", "name":"Johnny Doeie"}
366
+ {"_key": "my.logs", "name": "Johnny Doeie"}
352
367
  ```
353
368
 
354
369
  ### id_key
@@ -359,10 +374,10 @@ id_key request_id # use "request_id" field as a record id in ES
359
374
 
360
375
  By default, all records inserted into ElasticSearch get a random _id. This option allows to use a field in the record as an identifier.
361
376
 
362
- This following record `{"name":"Johnny","request_id":"87d89af7daffad6"}` will trigger the following ElasticSearch command
377
+ This following record `{"name": "Johnny", "request_id": "87d89af7daffad6"}` will trigger the following ElasticSearch command
363
378
 
364
379
  ```
365
- { "index" : { "_index" : "logstash-2013.01.01, "_type" : "fluentd", "_id" : "87d89af7daffad6" } }
380
+ { "index" : { "_index": "logstash-2013.01.01", "_type": "fluentd", "_id": "87d89af7daffad6" } }
366
381
  { "name": "Johnny", "request_id": "87d89af7daffad6" }
367
382
  ```
368
383
 
@@ -380,7 +395,7 @@ If your input is
380
395
  ElasticSearch command would be
381
396
 
382
397
  ```
383
- { "index" : { "_index" : "****", "_type" : "****", "_id" : "****", "_parent" : "my_parent" } }
398
+ { "index" : { "_index": "****", "_type": "****", "_id": "****", "_parent": "my_parent" } }
384
399
  { "name": "Johnny", "a_parent": "my_parent" }
385
400
  ```
386
401
 
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'fluent-plugin-elasticsearch'
6
- s.version = '2.0.0.rc.5'
6
+ s.version = '2.0.0.rc.6'
7
7
  s.authors = ['diogo', 'pitr']
8
8
  s.email = ['pitr.vern@gmail.com', 'me@diogoterror.com']
9
9
  s.description = %q{ElasticSearch output plugin for Fluent event collector}
@@ -121,6 +121,13 @@ module Fluent::Plugin
121
121
  rescue LoadError
122
122
  @dump_proc = Yajl.method(:dump)
123
123
  end
124
+
125
+ if @user && m = @user.match(/%{(?<user>.*)}/)
126
+ @user = URI.encode_www_form_component(m["user"])
127
+ end
128
+ if @password && m = @password.match(/%{(?<password>.*)}/)
129
+ @password = URI.encode_www_form_component(m["password"])
130
+ end
124
131
  end
125
132
 
126
133
  def create_meta_config_map
@@ -188,6 +195,18 @@ module Fluent::Plugin
188
195
  end
189
196
  end
190
197
 
198
+ def get_escaped_userinfo(host_str)
199
+ if m = host_str.match(/(?<scheme>.*)%{(?<user>.*)}:%{(?<password>.*)}(?<path>@.*)/)
200
+ m["scheme"] +
201
+ URI.encode_www_form_component(m["user"]) +
202
+ ':' +
203
+ URI.encode_www_form_component(m["password"]) +
204
+ m["path"]
205
+ else
206
+ host_str
207
+ end
208
+ end
209
+
191
210
  def get_connection_options
192
211
  raise "`password` must be present if `user` is present" if @user && !@password
193
212
 
@@ -202,7 +221,7 @@ module Fluent::Plugin
202
221
  }
203
222
  else
204
223
  # New hosts format expects URLs such as http://logs.foo.com,https://john:pass@logs2.foo.com/elastic
205
- uri = URI(host_str)
224
+ uri = URI(get_escaped_userinfo(host_str))
206
225
  %w(user password path).inject(host: uri.host, port: uri.port, scheme: uri.scheme) do |hash, key|
207
226
  hash[key.to_sym] = uri.public_send(key) unless uri.public_send(key).nil? || uri.public_send(key) == ''
208
227
  hash
@@ -6,6 +6,8 @@ module Fluent::Plugin
6
6
 
7
7
  Fluent::Plugin.register_output('elasticsearch_dynamic', self)
8
8
 
9
+ helpers :event_emitter
10
+
9
11
  config_param :delimiter, :string, :default => "."
10
12
 
11
13
  DYNAMIC_PARAM_NAMES = %W[hosts host port logstash_format logstash_prefix logstash_dateformat time_key utc_index index_name tag_key type_name id_key parent_key routing_key write_operation]
@@ -81,7 +83,7 @@ module Fluent::Plugin
81
83
  }
82
84
  else
83
85
  # New hosts format expects URLs such as http://logs.foo.com,https://john:pass@logs2.foo.com/elastic
84
- uri = URI(host_str)
86
+ uri = URI(get_escaped_userinfo(host_str))
85
87
  %w(user password path).inject(host: uri.host, port: uri.port, scheme: uri.scheme) do |hash, key|
86
88
  hash[key.to_sym] = uri.public_send(key) unless uri.public_send(key).nil? || uri.public_send(key) == ''
87
89
  hash
@@ -128,17 +130,23 @@ module Fluent::Plugin
128
130
  chunk.msgpack_each do |time, record|
129
131
  next unless record.is_a? Hash
130
132
 
131
- # evaluate all configurations here
132
- DYNAMIC_PARAM_SYMBOLS.each_with_index { |var, i|
133
- k = DYNAMIC_PARAM_NAMES[i]
134
- v = self.instance_variable_get(var)
135
- # check here to determine if we should evaluate
136
- if dynamic_conf[k] != v
137
- value = expand_param(v, tag, time, record)
138
- dynamic_conf[k] = value
139
- end
140
- }
133
+ begin
134
+ # evaluate all configurations here
135
+ DYNAMIC_PARAM_SYMBOLS.each_with_index { |var, i|
136
+ k = DYNAMIC_PARAM_NAMES[i]
137
+ v = self.instance_variable_get(var)
138
+ # check here to determine if we should evaluate
139
+ if dynamic_conf[k] != v
140
+ value = expand_param(v, tag, time, record)
141
+ dynamic_conf[k] = value
142
+ end
143
+ }
141
144
  # end eval all configs
145
+ rescue => e
146
+ # handle dynamic parameters misconfigurations
147
+ router.emit_error_event(tag, time, record, e)
148
+ next
149
+ end
142
150
 
143
151
  if eval_or_val(dynamic_conf['logstash_format'])
144
152
  if record.has_key?("@timestamp")
@@ -335,6 +335,32 @@ class ElasticsearchOutput < Test::Unit::TestCase
335
335
  assert_equal '/default_path', host2[:path]
336
336
  end
337
337
 
338
+ def test_hosts_list_with_escape_placeholders
339
+ config = %{
340
+ hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
341
+ path /default_path
342
+ user default_user
343
+ password default_password
344
+ }
345
+ instance = driver(config).instance
346
+
347
+ assert_equal 2, instance.get_connection_options[:hosts].length
348
+ host1, host2 = instance.get_connection_options[:hosts]
349
+
350
+ assert_equal 'host1', host1[:host]
351
+ assert_equal 443, host1[:port]
352
+ assert_equal 'https', host1[:scheme]
353
+ assert_equal 'j%2Bhn', host1[:user]
354
+ assert_equal 'passw%40rd', host1[:password]
355
+ assert_equal '/elastic/', host1[:path]
356
+
357
+ assert_equal 'host2', host2[:host]
358
+ assert_equal 'http', host2[:scheme]
359
+ assert_equal 'default_user', host2[:user]
360
+ assert_equal 'default_password', host2[:password]
361
+ assert_equal '/default_path', host2[:path]
362
+ end
363
+
338
364
  def test_single_host_params_and_defaults
339
365
  config = %{
340
366
  host logs.google.com
@@ -354,6 +380,25 @@ class ElasticsearchOutput < Test::Unit::TestCase
354
380
  assert_equal nil, host1[:path]
355
381
  end
356
382
 
383
+ def test_single_host_params_and_defaults_with_escape_placeholders
384
+ config = %{
385
+ host logs.google.com
386
+ user %{j+hn}
387
+ password %{d@e}
388
+ }
389
+ instance = driver(config).instance
390
+
391
+ assert_equal 1, instance.get_connection_options[:hosts].length
392
+ host1 = instance.get_connection_options[:hosts][0]
393
+
394
+ assert_equal 'logs.google.com', host1[:host]
395
+ assert_equal 9200, host1[:port]
396
+ assert_equal 'http', host1[:scheme]
397
+ assert_equal 'j%2Bhn', host1[:user]
398
+ assert_equal 'd%40e', host1[:password]
399
+ assert_equal nil, host1[:path]
400
+ end
401
+
357
402
  def test_content_type_header
358
403
  stub_request(:head, "http://localhost:9200/").
359
404
  to_return(:status => 200, :body => "", :headers => {})
@@ -1,8 +1,11 @@
1
1
  require 'helper'
2
2
  require 'date'
3
3
  require 'fluent/test/driver/output'
4
+ require 'flexmock/test_unit'
4
5
 
5
6
  class ElasticsearchOutputDynamic < Test::Unit::TestCase
7
+ include FlexMock::TestCase
8
+
6
9
  attr_accessor :index_cmds, :index_command_counts
7
10
 
8
11
  def setup
@@ -140,6 +143,32 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
140
143
  assert_equal '/default_path', host2[:path]
141
144
  end
142
145
 
146
+ def test_hosts_list_with_escape_placeholders
147
+ config = %{
148
+ hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
149
+ path /default_path
150
+ user default_user
151
+ password default_password
152
+ }
153
+ instance = driver(config).instance
154
+
155
+ assert_equal 2, instance.get_connection_options(nil)[:hosts].length
156
+ host1, host2 = instance.get_connection_options(nil)[:hosts]
157
+
158
+ assert_equal 'host1', host1[:host]
159
+ assert_equal 443, host1[:port]
160
+ assert_equal 'https', host1[:scheme]
161
+ assert_equal 'j%2Bhn', host1[:user]
162
+ assert_equal 'passw%40rd', host1[:password]
163
+ assert_equal '/elastic/', host1[:path]
164
+
165
+ assert_equal 'host2', host2[:host]
166
+ assert_equal 'http', host2[:scheme]
167
+ assert_equal 'default_user', host2[:user]
168
+ assert_equal 'default_password', host2[:password]
169
+ assert_equal '/default_path', host2[:path]
170
+ end
171
+
143
172
  def test_single_host_params_and_defaults
144
173
  config = %{
145
174
  host logs.google.com
@@ -159,6 +188,25 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
159
188
  assert_equal nil, host1[:path]
160
189
  end
161
190
 
191
+ def test_single_host_params_and_defaults_with_escape_placeholders
192
+ config = %{
193
+ host logs.google.com
194
+ user %{j+hn}
195
+ password %{d@e}
196
+ }
197
+ instance = driver(config).instance
198
+
199
+ assert_equal 1, instance.get_connection_options(nil)[:hosts].length
200
+ host1 = instance.get_connection_options(nil)[:hosts][0]
201
+
202
+ assert_equal 'logs.google.com', host1[:host]
203
+ assert_equal 9200, host1[:port]
204
+ assert_equal 'http', host1[:scheme]
205
+ assert_equal 'j%2Bhn', host1[:user]
206
+ assert_equal 'd%40e', host1[:password]
207
+ assert_equal nil, host1[:path]
208
+ end
209
+
162
210
  def test_content_type_header
163
211
  stub_request(:head, "http://localhost:9200/").
164
212
  to_return(:status => 200, :body => "", :headers => {})
@@ -566,6 +614,17 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
566
614
  }
567
615
  end
568
616
 
617
+ def test_tag_parts_index_error_event
618
+ stub_elastic_ping
619
+ stub_elastic
620
+ driver.configure("logstash_prefix ${tag_parts[1]}\n")
621
+ flexmock(driver.instance.router).should_receive(:emit_error_event)
622
+ .with('test', Fluent::EventTime, Hash, TypeError).once
623
+ driver.run(default_tag: 'test') do
624
+ driver.feed(sample_record)
625
+ end
626
+ end
627
+
569
628
  def test_connection_failed_retry
570
629
  connection_resets = 0
571
630
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.rc.5
4
+ version: 2.0.0.rc.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - diogo
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-09-25 00:00:00.000000000 Z
12
+ date: 2017-10-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fluentd
@@ -170,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
170
  version: 1.3.1
171
171
  requirements: []
172
172
  rubyforge_project:
173
- rubygems_version: 2.6.11
173
+ rubygems_version: 2.6.13
174
174
  signing_key:
175
175
  specification_version: 4
176
176
  summary: ElasticSearch output plugin for Fluent event collector