logstash-core 5.4.3-java → 5.5.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/logstash-core/logstash-core.jar +0 -0
  3. data/lib/logstash-core/version.rb +1 -1
  4. data/lib/logstash/api/commands/hot_threads_reporter.rb +2 -2
  5. data/lib/logstash/api/commands/node.rb +0 -1
  6. data/lib/logstash/api/commands/stats.rb +0 -1
  7. data/lib/logstash/config/mixin.rb +5 -43
  8. data/lib/logstash/config/modules_common.rb +71 -0
  9. data/lib/logstash/elasticsearch_client.rb +120 -0
  10. data/lib/logstash/environment.rb +14 -3
  11. data/lib/logstash/errors.rb +1 -0
  12. data/lib/logstash/execution_context.rb +11 -3
  13. data/lib/logstash/inputs/base.rb +2 -0
  14. data/lib/logstash/instrument/global_metrics.rb +13 -0
  15. data/lib/logstash/instrument/metric_type/mean.rb +5 -0
  16. data/lib/logstash/instrument/periodic_poller/jvm.rb +5 -5
  17. data/lib/logstash/logging/logger.rb +26 -1
  18. data/lib/logstash/modules/cli_parser.rb +74 -0
  19. data/lib/logstash/modules/elasticsearch_config.rb +22 -0
  20. data/lib/logstash/modules/elasticsearch_resource.rb +10 -0
  21. data/lib/logstash/modules/file_reader.rb +36 -0
  22. data/lib/logstash/modules/importer.rb +37 -0
  23. data/lib/logstash/modules/kibana_base_resource.rb +10 -0
  24. data/lib/logstash/modules/kibana_config.rb +104 -0
  25. data/lib/logstash/modules/kibana_resource.rb +10 -0
  26. data/lib/logstash/modules/logstash_config.rb +48 -0
  27. data/lib/logstash/modules/resource_base.rb +37 -0
  28. data/lib/logstash/modules/scaffold.rb +44 -0
  29. data/lib/logstash/namespace.rb +1 -0
  30. data/lib/logstash/outputs/base.rb +2 -0
  31. data/lib/logstash/pipeline.rb +18 -4
  32. data/lib/logstash/plugin.rb +1 -0
  33. data/lib/logstash/plugins/registry.rb +5 -0
  34. data/lib/logstash/runner.rb +42 -2
  35. data/lib/logstash/settings.rb +7 -1
  36. data/lib/logstash/timestamp.rb +4 -0
  37. data/lib/logstash/util/dead_letter_queue_manager.rb +61 -0
  38. data/lib/logstash/util/safe_uri.rb +130 -11
  39. data/lib/logstash/util/thread_dump.rb +3 -1
  40. data/lib/logstash/util/wrapped_acked_queue.rb +24 -6
  41. data/lib/logstash/util/wrapped_synchronous_queue.rb +19 -5
  42. data/lib/logstash/version.rb +1 -1
  43. data/locales/en.yml +46 -0
  44. data/logstash-core.gemspec +7 -2
  45. data/spec/{api/lib/commands/stats.rb → logstash/api/commands/stats_spec.rb} +7 -2
  46. data/spec/{api/lib → logstash/api}/errors_spec.rb +1 -1
  47. data/spec/{api/lib/api → logstash/api/modules}/logging_spec.rb +1 -10
  48. data/spec/{api/lib/api → logstash/api/modules}/node_plugins_spec.rb +2 -3
  49. data/spec/{api/lib/api → logstash/api/modules}/node_spec.rb +6 -7
  50. data/spec/{api/lib/api → logstash/api/modules}/node_stats_spec.rb +2 -2
  51. data/spec/{api/lib/api → logstash/api/modules}/plugins_spec.rb +4 -3
  52. data/spec/{api/lib/api → logstash/api/modules}/root_spec.rb +3 -3
  53. data/spec/{api/lib → logstash/api}/rack_app_spec.rb +0 -0
  54. data/spec/logstash/config/mixin_spec.rb +2 -2
  55. data/spec/logstash/execution_context_spec.rb +20 -1
  56. data/spec/logstash/filter_delegator_spec.rb +2 -1
  57. data/spec/logstash/inputs/base_spec.rb +1 -1
  58. data/spec/logstash/output_delegator_spec.rb +2 -1
  59. data/spec/logstash/outputs/base_spec.rb +1 -1
  60. data/spec/logstash/pipeline_dlq_commit_spec.rb +107 -0
  61. data/spec/logstash/pipeline_pq_file_spec.rb +1 -1
  62. data/spec/logstash/plugin_spec.rb +1 -1
  63. data/spec/logstash/plugins/registry_spec.rb +22 -5
  64. data/spec/logstash/runner_spec.rb +122 -19
  65. data/spec/logstash/settings_spec.rb +91 -0
  66. data/spec/logstash/timestamp_spec.rb +6 -0
  67. data/spec/support/helpers.rb +80 -1
  68. data/spec/support/matchers.rb +13 -0
  69. data/spec/support/shared_contexts.rb +38 -0
  70. data/spec/support/shared_examples.rb +1 -1
  71. metadata +95 -40
  72. data/spec/api/lib/api/support/resource_dsl_methods.rb +0 -87
  73. data/spec/api/spec_helper.rb +0 -111
@@ -14,7 +14,8 @@ describe LogStash::FilterDelegator do
14
14
  let(:collector) { [] }
15
15
  let(:metric) { LogStash::Instrument::NamespacedNullMetric.new(collector, :null) }
16
16
  let(:events) { [LogStash::Event.new, LogStash::Event.new] }
17
- let(:default_execution_context) { LogStash::ExecutionContext.new(:main) }
17
+ let(:default_execution_context) { LogStash::ExecutionContext.new(:main, filter_id, "filter",
18
+ LogStash::Util::DummyDeadLetterQueueWriter.new) }
18
19
 
19
20
  before :each do
20
21
  allow(metric).to receive(:namespace).with(anything).and_return(metric)
@@ -64,7 +64,7 @@ describe "LogStash::Inputs::Base#decorate" do
64
64
  end
65
65
 
66
66
  context "execution context" do
67
- let(:default_execution_context) { LogStash::ExecutionContext.new(:main) }
67
+ let(:default_execution_context) { LogStash::ExecutionContext.new(:main, "id", "input", LogStash::Util::DummyDeadLetterQueueWriter.new) }
68
68
  let(:klass) { LogStash::Inputs::NOOP }
69
69
 
70
70
  subject(:instance) { klass.new({}) }
@@ -9,7 +9,8 @@ describe LogStash::OutputDelegator do
9
9
  let(:plugin_args) { {"id" => "foo", "arg1" => "val1"} }
10
10
  let(:collector) { [] }
11
11
  let(:metric) { LogStash::Instrument::NamespacedNullMetric.new(collector, :null) }
12
- let(:default_execution_context) { LogStash::ExecutionContext.new(:main) }
12
+ let(:default_execution_context) { LogStash::ExecutionContext.new(:main, "foo", "output",
13
+ LogStash::Util::DummyDeadLetterQueueWriter.new) }
13
14
 
14
15
  subject { described_class.new(logger, out_klass, metric, default_execution_context, ::LogStash::OutputDelegatorStrategyRegistry.instance, plugin_args) }
15
16
 
@@ -80,7 +80,7 @@ describe "LogStash::Outputs::Base#new" do
80
80
  end
81
81
 
82
82
  context "execution context" do
83
- let(:default_execution_context) { LogStash::ExecutionContext.new(:main) }
83
+ let(:default_execution_context) { LogStash::ExecutionContext.new(:main, "id", "output", LogStash::Util::DummyDeadLetterQueueWriter.new) }
84
84
  let(:klass) { LogStash::Outputs::NOOPSingle }
85
85
 
86
86
  subject(:instance) { klass.new(params.dup) }
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+ require "tmpdir"
3
+ require "spec_helper"
4
+ require "logstash/codecs/plain"
5
+ require_relative "../support/mocks_classes"
6
+
7
+ class SingleGeneratorInput < LogStash::Inputs::Base
8
+ config_name "singlegenerator"
9
+ milestone 2
10
+
11
+ def register
12
+ end
13
+
14
+ def run(queue)
15
+ queue << LogStash::Event.new
16
+ end
17
+
18
+ def close
19
+ end
20
+ end
21
+
22
+ class DLQCommittingFilter < LogStash::Filters::Base
23
+ config_name "dlq_commit"
24
+ milestone 2
25
+
26
+ def register()
27
+ end
28
+
29
+ def filter(event)
30
+ execution_context.dlq_writer.write(event, "my reason")
31
+ end
32
+
33
+ def threadsafe?() true; end
34
+
35
+ def close() end
36
+ end
37
+
38
+ describe LogStash::Pipeline do
39
+ let(:pipeline_settings_obj) { LogStash::SETTINGS }
40
+ let(:pipeline_settings) do
41
+ {
42
+ "pipeline.workers" => 2,
43
+ "pipeline.id" => pipeline_id,
44
+ "dead_letter_queue.enable" => enable_dlq,
45
+ "path.dead_letter_queue" => Dir.mktmpdir
46
+ }
47
+ end
48
+ let(:metric) { LogStash::Instrument::Metric.new(LogStash::Instrument::Collector.new) }
49
+ let(:test_config) {
50
+ <<-eos
51
+ input { singlegenerator { id => input_id } }
52
+
53
+ filter { dlq_commit { id => filter_id } }
54
+
55
+ output { dummyoutput { id => output_id } }
56
+ eos
57
+ }
58
+
59
+ subject { LogStash::Pipeline.new(test_config, pipeline_settings_obj, metric) }
60
+
61
+ before(:each) do
62
+ pipeline_settings.each {|k, v| pipeline_settings_obj.set(k, v) }
63
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "singlegenerator").and_return(SingleGeneratorInput)
64
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(LogStash::Codecs::Plain)
65
+ allow(LogStash::Plugin).to receive(:lookup).with("filter", "dlq_commit").and_return(DLQCommittingFilter)
66
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(::LogStash::Outputs::DummyOutput)
67
+ end
68
+
69
+ after(:each) do
70
+ FileUtils.remove_entry pipeline_settings["path.dead_letter_queue"]
71
+ end
72
+
73
+ context "dlq is enabled" do
74
+ let(:enable_dlq) { true }
75
+ let(:pipeline_id) { "test-dlq" }
76
+
77
+ it "retrieves proper pipeline-level DLQ writer" do
78
+ expect(LogStash::Util::PluginDeadLetterQueueWriter).to receive(:new).with(anything, "input_id", "singlegenerator").and_call_original
79
+ expect(LogStash::Util::PluginDeadLetterQueueWriter).to receive(:new).with(anything, "filter_id", "dlq_commit").and_call_original
80
+ expect(LogStash::Util::PluginDeadLetterQueueWriter).to receive(:new).with(anything, "output_id", "dummyoutput").and_call_original
81
+ expect_any_instance_of(org.logstash.common.io.DeadLetterQueueWriter).to receive(:close).and_call_original
82
+ subject.run
83
+ dlq_path = java.nio.file.Paths.get(pipeline_settings_obj.get("path.dead_letter_queue"), pipeline_id)
84
+ dlq_reader = org.logstash.common.io.DeadLetterQueueReader.new(dlq_path)
85
+ entry = dlq_reader.pollEntry(40)
86
+ expect(entry).to_not be_nil
87
+ expect(entry.reason).to eq("my reason")
88
+ end
89
+ end
90
+
91
+ context "dlq is disabled" do
92
+ let(:enable_dlq) { false }
93
+ let(:pipeline_id) { "test-without-dlq" }
94
+
95
+ it "does not write to the DLQ" do
96
+ expect(LogStash::Util::PluginDeadLetterQueueWriter).to receive(:new).with(anything, "input_id", "singlegenerator").and_call_original
97
+ expect(LogStash::Util::PluginDeadLetterQueueWriter).to receive(:new).with(anything, "filter_id", "dlq_commit").and_call_original
98
+ expect(LogStash::Util::PluginDeadLetterQueueWriter).to receive(:new).with(anything, "output_id", "dummyoutput").and_call_original
99
+ expect(LogStash::Util::DummyDeadLetterQueueWriter).to receive(:new).and_call_original
100
+ expect_any_instance_of(LogStash::Util::DummyDeadLetterQueueWriter).to receive(:close).and_call_original
101
+ subject.run
102
+ dlq_path = java.nio.file.Paths.get(pipeline_settings_obj.get("path.dead_letter_queue"), pipeline_id)
103
+ expect(java.nio.file.Files.exists(dlq_path)).to eq(false)
104
+ end
105
+ end
106
+
107
+ end
@@ -36,7 +36,7 @@ class PipelinePqFileOutput < LogStash::Outputs::Base
36
36
  end
37
37
 
38
38
  describe LogStash::Pipeline do
39
- let(:pipeline_settings_obj) { LogStash::SETTINGS }
39
+ let(:pipeline_settings_obj) { LogStash::SETTINGS.clone }
40
40
  let(:pipeline_id) { "main" }
41
41
 
42
42
  let(:multiline_id) { "my-multiline" }
@@ -48,7 +48,7 @@ describe LogStash::Plugin do
48
48
 
49
49
  it "can be set and get" do
50
50
  expect(subject.execution_context).to be_nil
51
- execution_context = LogStash::ExecutionContext.new(:main)
51
+ execution_context = LogStash::ExecutionContext.new(:main, "id", "type", nil)
52
52
  subject.execution_context = execution_context
53
53
  expect(subject.execution_context).to eq(execution_context)
54
54
  end
@@ -53,13 +53,30 @@ describe LogStash::Plugins::Registry do
53
53
  end
54
54
 
55
55
  context "when loading plugin manually configured" do
56
- it "should return the plugin" do
57
- class SimplePlugin
58
- end
56
+ let(:simple_plugin) { Class.new }
59
57
 
58
+ it "should return the plugin" do
60
59
  expect { registry.lookup("filter", "simple_plugin") }.to raise_error(LoadError)
61
- registry.add(:filter, "simple_plugin", SimplePlugin)
62
- expect(registry.lookup("filter", "simple_plugin")).to eq(SimplePlugin)
60
+ registry.add(:filter, "simple_plugin", simple_plugin)
61
+ expect(registry.lookup("filter", "simple_plugin")).to eq(simple_plugin)
62
+ end
63
+
64
+ it "doesn't add multiple time the same plugin" do
65
+ plugin1 = Class.new
66
+ plugin2 = Class.new
67
+
68
+ registry.add(:filter, "simple_plugin", plugin1)
69
+ registry.add(:filter, "simple_plugin", plugin2)
70
+
71
+ expect(registry.plugins_with_type(:filter)).to include(plugin1)
72
+ expect(registry.plugins_with_type(:filter).size).to eq(1)
73
+ end
74
+
75
+ it "allow you find plugin by type" do
76
+ registry.add(:filter, "simple_plugin", simple_plugin)
77
+
78
+ expect(registry.plugins_with_type(:filter)).to include(simple_plugin)
79
+ expect(registry.plugins_with_type(:modules)).to match([])
63
80
  end
64
81
  end
65
82
  end
@@ -6,7 +6,11 @@ require "stud/trap"
6
6
  require "stud/temporary"
7
7
  require "logstash/util/java_version"
8
8
  require "logstash/logging/json"
9
+ require "logstash/config/modules_common"
10
+ require "logstash/elasticsearch_client"
9
11
  require "json"
12
+ require_relative "../support/helpers"
13
+ require_relative "../support/matchers"
10
14
 
11
15
  class NullRunner
12
16
  def run(args); end
@@ -32,13 +36,6 @@ describe LogStash::Runner do
32
36
  end
33
37
  end
34
38
 
35
- after :each do
36
- LogStash::SETTINGS.reset
37
- end
38
-
39
- after :all do
40
- end
41
-
42
39
  describe "argument precedence" do
43
40
  let(:config) { "input {} output {}" }
44
41
  let(:cli_args) { ["-e", config, "-w", "20"] }
@@ -48,10 +45,6 @@ describe LogStash::Runner do
48
45
  allow(LogStash::SETTINGS).to receive(:read_yaml).and_return(settings_yml_hash)
49
46
  end
50
47
 
51
- after :each do
52
- LogStash::SETTINGS.reset
53
- end
54
-
55
48
  it "favors the last occurence of an option" do
56
49
  expect(LogStash::Agent).to receive(:new) do |settings|
57
50
  expect(settings.get("config.string")).to eq(config)
@@ -142,6 +135,7 @@ describe LogStash::Runner do
142
135
  context "with a good configuration" do
143
136
  let(:pipeline_string) { "input { } filter { } output { }" }
144
137
  it "should exit successfully" do
138
+ expect(logger).not_to receive(:fatal)
145
139
  expect(subject.run(args)).to eq(0)
146
140
  end
147
141
  end
@@ -165,38 +159,56 @@ describe LogStash::Runner do
165
159
  allow(pipeline).to receive(:run).and_return(task)
166
160
  allow(pipeline).to receive(:shutdown)
167
161
  end
168
-
162
+
169
163
  context "when :path.data is defined by the user" do
170
164
  let(:test_data_path) { "/tmp/ls-test-data" }
171
165
  let(:test_queue_path) { test_data_path + "/" + "queue" }
172
-
166
+ let(:test_dlq_path) { test_data_path + "/" + "dead_letter_queue" }
167
+
173
168
  it "should set data paths" do
174
169
  expect(LogStash::Agent).to receive(:new) do |settings|
175
170
  expect(settings.get("path.data")).to eq(test_data_path)
176
171
  expect(settings.get("path.queue")).to eq(test_queue_path)
172
+ expect(settings.get("path.dead_letter_queue")).to eq(test_dlq_path)
177
173
  end
178
-
174
+
179
175
  args = ["--path.data", test_data_path, "-e", pipeline_string]
180
176
  subject.run("bin/logstash", args)
181
177
  end
182
-
178
+
183
179
  context "and path.queue is manually set" do
184
180
  let(:queue_override_path) { "/tmp/queue-override_path" }
185
-
181
+
186
182
  it "should set data paths" do
187
183
  expect(LogStash::Agent).to receive(:new) do |settings|
188
184
  expect(settings.get("path.data")).to eq(test_data_path)
189
185
  expect(settings.get("path.queue")).to eq(queue_override_path)
190
186
  end
191
-
187
+
192
188
  LogStash::SETTINGS.set("path.queue", queue_override_path)
193
-
189
+
190
+ args = ["--path.data", test_data_path, "-e", pipeline_string]
191
+ subject.run("bin/logstash", args)
192
+ end
193
+ end
194
+
195
+ context "and path.dead_letter_queue is manually set" do
196
+ let(:queue_override_path) { "/tmp/queue-override_path" }
197
+
198
+ it "should set data paths" do
199
+ expect(LogStash::Agent).to receive(:new) do |settings|
200
+ expect(settings.get("path.data")).to eq(test_data_path)
201
+ expect(settings.get("path.dead_letter_queue")).to eq(queue_override_path)
202
+ end
203
+
204
+ LogStash::SETTINGS.set("path.dead_letter_queue", queue_override_path)
205
+
194
206
  args = ["--path.data", test_data_path, "-e", pipeline_string]
195
207
  subject.run("bin/logstash", args)
196
208
  end
197
209
  end
198
210
  end
199
-
211
+
200
212
  context "when :http.host is defined by the user" do
201
213
  it "should pass the value to the webserver" do
202
214
  expect(LogStash::Agent).to receive(:new) do |settings|
@@ -303,6 +315,97 @@ describe LogStash::Runner do
303
315
  end
304
316
  end
305
317
 
318
+ describe "logstash modules" do
319
+ describe "--config.test_and_exit" do
320
+ subject { LogStash::Runner.new("") }
321
+ let(:args) { ["-t", "--modules", module_string] }
322
+
323
+ context "with a good configuration" do
324
+ let(:module_string) { "cef" }
325
+ it "should exit successfully" do
326
+ skip("Skipped until cef module is added back to the codebase as explained in #7455")
327
+ expect(logger).not_to receive(:fatal)
328
+ expect(subject.run(args)).to eq(0)
329
+ end
330
+ end
331
+
332
+ context "with a bad configuration" do
333
+ let(:module_string) { "rlwekjhrewlqrkjh" }
334
+ it "should fail by returning a bad exit code" do
335
+ expect(logger).to receive(:fatal)
336
+ expect(subject.run(args)).to eq(1)
337
+ end
338
+ end
339
+ end
340
+
341
+ describe "--modules" do
342
+ let(:args) { ["--modules", module_string] }
343
+ let(:agent_instance) { double("agent") }
344
+ context "with an available module specified but no connection to elasticsearch" do
345
+ let(:module_string) { "cef" }
346
+ before do
347
+ expect(logger).to receive(:fatal) do |msg, hash|
348
+ expect(msg).to eq("An unexpected error occurred!")
349
+ expect(hash).to be_a_config_loading_error_hash(
350
+ /Failed to import module configurations to Elasticsearch. Module: cef/)
351
+ end
352
+ end
353
+ it "should log fatally and return a bad exit code" do
354
+ skip("Skipped until cef module is added back to the codebase as explained in #7455")
355
+ expect(subject.run("bin/logstash", args)).to eq(1)
356
+ end
357
+ end
358
+
359
+ context "with an available module specified and a mocked connection to elasticsearch" do
360
+ let(:module_string) { "cef" }
361
+ let(:client) { double(:client) }
362
+ let(:response) { double(:response) }
363
+ before do
364
+ allow(response).to receive(:status).and_return(404)
365
+ allow(client).to receive(:head).and_return(response)
366
+ allow(client).to receive(:can_connect?).and_return(true)
367
+ allow(agent_instance).to receive(:register_pipeline)
368
+ allow(agent_instance).to receive(:execute)
369
+ allow(agent_instance).to receive(:shutdown)
370
+ allow(LogStash::ElasticsearchClient).to receive(:build).and_return(client)
371
+
372
+ expect(client).to receive(:put).at_least(15).times do |path, content|
373
+ LogStash::ElasticsearchClient::Response.new(201, "", {})
374
+ end
375
+ expect(LogStash::Agent).to receive(:new) do |settings|
376
+ pipelines = LogStash::Config::ModulesCommon.pipeline_configs(settings)
377
+ expect(pipelines).not_to be_empty
378
+ cef_pipeline = pipelines.first
379
+ expect(cef_pipeline).to include("pipeline_id", "config_string")
380
+ expect(cef_pipeline["pipeline_id"]).to include('cef')
381
+ expect(cef_pipeline["config_string"]).to include('index => "cef-')
382
+ agent_instance
383
+ end
384
+ expect(logger).not_to receive(:fatal)
385
+ expect(logger).not_to receive(:error)
386
+ end
387
+ it "should not terminate logstash" do
388
+ skip("Skipped until cef module is added back to the codebase as explained in #7455")
389
+ expect(subject.run("bin/logstash", args)).to be_nil
390
+ end
391
+ end
392
+
393
+ context "with an unavailable module specified" do
394
+ let(:module_string) { "fancypants" }
395
+ before do
396
+ expect(logger).to receive(:fatal) do |msg, hash|
397
+ expect(msg).to eq("An unexpected error occurred!")
398
+ expect(hash).to be_a_config_loading_error_hash(
399
+ /The modules specified are not available yet. Specified modules: \["fancypants"\] Available modules:/)
400
+ end
401
+ end
402
+ it "should log fatally and return a bad exit code" do
403
+ expect(subject.run("bin/logstash", args)).to eq(1)
404
+ end
405
+ end
406
+ end
407
+ end
408
+
306
409
  describe "--log.level" do
307
410
  before :each do
308
411
  allow_any_instance_of(subject).to receive(:show_version)
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require "spec_helper"
3
+ require "logstash/util/environment_variables"
3
4
  require "logstash/settings"
4
5
  require "fileutils"
5
6
 
@@ -146,4 +147,94 @@ describe LogStash::Settings do
146
147
  end
147
148
  end
148
149
  end
150
+
151
+ describe "#from_yaml" do
152
+
153
+ context "env placeholders in flat logstash.yml" do
154
+
155
+ after do
156
+ ENV.delete('SOME_LOGSTASH_SPEC_ENV_VAR')
157
+ ENV.delete('some.logstash.spec.env.var')
158
+ end
159
+
160
+ subject do
161
+ settings = described_class.new
162
+ settings.register(LogStash::Setting::String.new("interpolated", "missing"))
163
+ settings.register(LogStash::Setting::String.new("with_dot", "missing"))
164
+ settings
165
+ end
166
+
167
+ let(:values) {{
168
+ "interpolated" => "${SOME_LOGSTASH_SPEC_ENV_VAR}",
169
+ "with_dot" => "${some.logstash.spec.env.var}"
170
+ }}
171
+ let(:yaml_path) do
172
+ p = Stud::Temporary.pathname
173
+ FileUtils.mkdir_p(p)
174
+
175
+ ::File.open(::File.join(p, "logstash.yml"), "w+") do |f|
176
+ f.write(YAML.dump(values))
177
+ end
178
+ p
179
+ end
180
+
181
+ it "can interpolate environment into settings" do
182
+ expect(subject.get('interpolated')).to eq("missing")
183
+ expect(subject.get('with_dot')).to eq("missing")
184
+ ENV['SOME_LOGSTASH_SPEC_ENV_VAR'] = "correct_setting"
185
+ ENV['some.logstash.spec.env.var'] = "correct_setting_for_dotted"
186
+ subject.from_yaml(yaml_path)
187
+ expect(subject.get('interpolated')).to eq("correct_setting")
188
+ expect(subject.get('with_dot')).to eq("correct_setting_for_dotted")
189
+ end
190
+ end
191
+ end
192
+
193
+ context "env placeholders in nested logstash.yml" do
194
+
195
+ before do
196
+ ENV['lsspecdomain'] = "domain1"
197
+ ENV['lsspecdomain2'] = "domain2"
198
+ end
199
+
200
+ after do
201
+ ENV.delete('lsspecdomain')
202
+ ENV.delete('lsspecdomain2')
203
+ end
204
+
205
+ subject do
206
+ settings = described_class.new
207
+ settings.register(LogStash::Setting::ArrayCoercible.new("host", String, []))
208
+ settings.register(LogStash::Setting::ArrayCoercible.new("modules", Hash, []))
209
+ settings
210
+ end
211
+
212
+ let(:values) {{
213
+ "host" => ["dev1.${lsspecdomain}", "dev2.${lsspecdomain}"],
214
+ "modules" => [
215
+ {"name" => "${lsspecdomain}", "testing" => "${lsspecdomain}"},
216
+ {"name" => "${lsspecdomain2}", "testing" => "${lsspecdomain2}"}
217
+ ]
218
+ }}
219
+ let(:yaml_path) do
220
+ p = Stud::Temporary.pathname
221
+ FileUtils.mkdir_p(p)
222
+
223
+ ::File.open(::File.join(p, "logstash.yml"), "w+") do |f|
224
+ f.write(YAML.dump(values))
225
+ end
226
+ p
227
+ end
228
+
229
+ it "can interpolate environment into settings" do
230
+ expect(subject.get('host')).to match_array([])
231
+ expect(subject.get('modules')).to match_array([])
232
+ subject.from_yaml(yaml_path)
233
+ expect(subject.get('host')).to match_array(["dev1.domain1", "dev2.domain1"])
234
+ expect(subject.get('modules')).to match_array([
235
+ {"name" => "domain1", "testing" => "domain1"},
236
+ {"name" => "domain2", "testing" => "domain2"}
237
+ ])
238
+ end
239
+ end
149
240
  end