logstash-output-elasticsearch 11.12.4-java → 11.15.9-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -0
- data/docs/index.asciidoc +214 -66
- data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +14 -4
- data/lib/logstash/outputs/elasticsearch/http_client_builder.rb +46 -19
- data/lib/logstash/outputs/elasticsearch/template_manager.rb +26 -3
- data/lib/logstash/outputs/elasticsearch.rb +89 -39
- data/lib/logstash/plugin_mixins/elasticsearch/api_configs.rb +60 -8
- data/lib/logstash/plugin_mixins/elasticsearch/common.rb +42 -18
- data/logstash-output-elasticsearch.gemspec +3 -2
- data/spec/es_spec_helper.rb +12 -7
- data/spec/fixtures/test_certs/ca.crt +13 -13
- data/spec/fixtures/test_certs/ca.der.sha256 +1 -1
- data/spec/fixtures/test_certs/test.crt +14 -14
- data/spec/fixtures/test_certs/test.der.sha256 +1 -1
- data/spec/fixtures/test_certs/test.p12 +0 -0
- data/spec/integration/outputs/index_spec.rb +16 -16
- data/spec/integration/outputs/templates_spec.rb +11 -9
- data/spec/unit/outputs/elasticsearch/data_stream_support_spec.rb +4 -2
- data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +9 -2
- data/spec/unit/outputs/elasticsearch/template_manager_spec.rb +72 -20
- data/spec/unit/outputs/elasticsearch_spec.rb +358 -28
- data/spec/unit/outputs/elasticsearch_ssl_spec.rb +166 -50
- metadata +18 -4
@@ -50,6 +50,143 @@ describe LogStash::Outputs::ElasticSearch do
|
|
50
50
|
subject.close
|
51
51
|
end
|
52
52
|
|
53
|
+
context "check aborting of a batch" do
|
54
|
+
context "on an unreachable ES instance" do
|
55
|
+
let(:events) { [ ::LogStash::Event.new("foo" => "bar1"), ::LogStash::Event.new("foo" => "bar2") ] }
|
56
|
+
|
57
|
+
let(:shutdown_value) { true }
|
58
|
+
|
59
|
+
let(:logger) { double("logger") }
|
60
|
+
|
61
|
+
let(:never_ending) { Thread.new { sleep 1 while true } }
|
62
|
+
|
63
|
+
let(:do_register) { false }
|
64
|
+
|
65
|
+
before(:each) do
|
66
|
+
spy_http_client_builder!
|
67
|
+
stub_http_client_pool!
|
68
|
+
|
69
|
+
allow(subject).to receive(:finish_register) # stub-out thread completion (to avoid error log entries)
|
70
|
+
|
71
|
+
# emulate 'failed' ES connection, which sleeps forever
|
72
|
+
allow(subject).to receive(:after_successful_connection) { |&block| never_ending }
|
73
|
+
allow(subject).to receive(:stop_after_successful_connection_thread)
|
74
|
+
|
75
|
+
subject.register
|
76
|
+
|
77
|
+
allow(subject.client).to receive(:maximum_seen_major_version).at_least(:once).and_return(maximum_seen_major_version)
|
78
|
+
allow(subject.client).to receive(:get_xpack_info)
|
79
|
+
|
80
|
+
subject.client.pool.adapter.manticore.respond_with(:body => "{}")
|
81
|
+
|
82
|
+
allow(subject).to receive(:logger).and_return(logger)
|
83
|
+
allow(logger).to receive(:info)
|
84
|
+
|
85
|
+
allow(subject).to receive(:pipeline_shutdown_requested?) do
|
86
|
+
shutdown_value
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it "the #multi_receive abort while waiting on unreachable and a shutdown is requested" do
|
91
|
+
expect { subject.multi_receive(events) }.to raise_error(org.logstash.execution.AbortedBatchException)
|
92
|
+
expect(logger).to have_received(:info).with(/Aborting the batch due to shutdown request while waiting for connections to become live/i)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "on a reachable ES instance" do
|
97
|
+
let(:events) { [ ::LogStash::Event.new("foo" => "bar1"), ::LogStash::Event.new("foo" => "bar2") ] }
|
98
|
+
|
99
|
+
let(:logger) { double("logger") }
|
100
|
+
|
101
|
+
before(:each) do
|
102
|
+
allow(subject).to receive(:logger).and_return(logger)
|
103
|
+
allow(logger).to receive(:info)
|
104
|
+
|
105
|
+
allow(subject).to receive(:pipeline_shutdown_requested?).and_return(true)
|
106
|
+
allow(subject).to receive(:retrying_submit)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "the #multi_receive doesn't abort when waiting for a connection on alive ES and a shutdown is requested" do
|
110
|
+
subject.multi_receive(events)
|
111
|
+
expect(logger).to_not have_received(:info).with(/Aborting the batch due to shutdown request while waiting for connections to become live/i)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "when a connected ES becomes unreachable" do
|
116
|
+
# let(:error) do
|
117
|
+
# ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError.new(
|
118
|
+
# 429, double("url").as_null_object, request_body, double("response body")
|
119
|
+
# )
|
120
|
+
# end
|
121
|
+
|
122
|
+
shared_examples 'raise an abort error' do
|
123
|
+
let(:options) {
|
124
|
+
{
|
125
|
+
"index" => "my-index",
|
126
|
+
"hosts" => ["localhost","localhost:9202"],
|
127
|
+
"path" => "some-path",
|
128
|
+
"manage_template" => false
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
let(:manticore_urls) { subject.client.pool.urls }
|
133
|
+
let(:manticore_url) { manticore_urls.first }
|
134
|
+
|
135
|
+
let(:stub_http_client_pool!) do
|
136
|
+
[:start_resurrectionist, :start_sniffer, :healthcheck!].each do |method|
|
137
|
+
allow_any_instance_of(LogStash::Outputs::ElasticSearch::HttpClient::Pool).to receive(method)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
let(:event) { ::LogStash::Event.new("foo" => "bar") }
|
142
|
+
|
143
|
+
let(:logger) { double("logger").as_null_object }
|
144
|
+
let(:response) { { :errors => [], :items => [] } }
|
145
|
+
|
146
|
+
let(:request_body) { double(:request_body, :bytesize => 1023) }
|
147
|
+
|
148
|
+
before(:each) do
|
149
|
+
bulk_param = [["index", anything, event.to_hash]]
|
150
|
+
|
151
|
+
allow(subject).to receive(:logger).and_return(logger)
|
152
|
+
|
153
|
+
# fail consistently for ever
|
154
|
+
allow(subject.client).to receive(:bulk).with(bulk_param).and_raise(error)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should exit the retry with an abort exception if shutdown is requested" do
|
158
|
+
# trigger the shutdown signal
|
159
|
+
allow(subject).to receive(:pipeline_shutdown_requested?) { true }
|
160
|
+
|
161
|
+
# execute in another thread because it blocks in a retry loop until the shutdown is triggered
|
162
|
+
th = Thread.new do
|
163
|
+
subject.multi_receive([event])
|
164
|
+
rescue org.logstash.execution.AbortedBatchException => e
|
165
|
+
# return exception's class so that it can be verified when retrieving the thread's value
|
166
|
+
e.class
|
167
|
+
end
|
168
|
+
|
169
|
+
expect(th.value).to eq(org.logstash.execution.AbortedBatchException)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "with 429 error" do
|
174
|
+
let(:error) do
|
175
|
+
::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError.new(
|
176
|
+
429, double("url").as_null_object, request_body, double("response body")
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
it_behaves_like 'raise an abort error'
|
181
|
+
end
|
182
|
+
|
183
|
+
context "with 'no connections' error" do
|
184
|
+
let(:error) { ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::NoConnectionAvailableError.new }
|
185
|
+
|
186
|
+
it_behaves_like 'raise an abort error'
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end if LOGSTASH_VERSION >= '8.8'
|
53
190
|
|
54
191
|
context "with an active instance" do
|
55
192
|
let(:options) {
|
@@ -590,7 +727,7 @@ describe LogStash::Outputs::ElasticSearch do
|
|
590
727
|
|
591
728
|
let(:event) { LogStash::Event.new("pipeline" => "my-ingest-pipeline") }
|
592
729
|
|
593
|
-
it "
|
730
|
+
it "interpolate the pipeline value and set it" do
|
594
731
|
expect(subject.send(:event_action_tuple, event)[1]).to include(:pipeline => "my-ingest-pipeline")
|
595
732
|
end
|
596
733
|
end
|
@@ -600,7 +737,66 @@ describe LogStash::Outputs::ElasticSearch do
|
|
600
737
|
|
601
738
|
let(:event) { LogStash::Event.new("pipeline" => "") }
|
602
739
|
|
603
|
-
it "
|
740
|
+
it "interpolates the pipeline value but not set it because it is empty" do
|
741
|
+
expect(subject.send(:event_action_tuple, event)[1]).not_to include(:pipeline)
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
745
|
+
context "with both pipeline and target_ingest_pipeline" do
|
746
|
+
let(:options) { {"pipeline" => "%{pipeline}" } }
|
747
|
+
let(:event) { LogStash::Event.new({"pipeline" => "my-ingest-pipeline", "[@metadata][target_ingest_pipeline]" => "meta-ingest-pipeline"}) }
|
748
|
+
|
749
|
+
it "interpolates the plugin's pipeline value" do
|
750
|
+
expect(subject.send(:event_action_tuple, event)[1]).to include(:pipeline => "my-ingest-pipeline")
|
751
|
+
end
|
752
|
+
|
753
|
+
context "when the plugin's `pipeline` is constant" do
|
754
|
+
let(:options) { super().merge("pipeline" => "my-constant-pipeline") }
|
755
|
+
it "uses plugin's pipeline value" do
|
756
|
+
expect(subject.send(:event_action_tuple, event)[1]).to include(:pipeline => "my-constant-pipeline")
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
context "when the plugin's `pipeline` includes an unresolvable sprintf placeholder" do
|
761
|
+
let(:options) { super().merge("pipeline" => "reference-%{unset}-field") }
|
762
|
+
it "does not use the target_ingest_pipeline" do
|
763
|
+
# when sprintf doesn't resolve a placeholder, the behaviour of our `pipeline` is UNSPECIFIED.
|
764
|
+
# here we only validate that the presence of the magic field does not
|
765
|
+
# override an explicitly-configured pipeline.
|
766
|
+
expect(subject.send(:event_action_tuple, event)[1]).to_not include(:pipeline => "my-ingest-pipeline")
|
767
|
+
end
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
context "with empty pipeline and target_ingest_pipeline" do
|
772
|
+
let(:options) { {"pipeline" => "%{pipeline}" } }
|
773
|
+
let(:event) { LogStash::Event.new({"pipeline" => "", "[@metadata][target_ingest_pipeline]" => "meta-ingest-pipeline"}) }
|
774
|
+
|
775
|
+
it "interpolates the pipeline value but not set it because pipeline is empty" do
|
776
|
+
expect(subject.send(:event_action_tuple, event)[1]).not_to include(:pipeline)
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|
780
|
+
context "with target_ingest_pipeline" do
|
781
|
+
let(:event) { LogStash::Event.new({"pipeline" => "", "@metadata" => {"target_ingest_pipeline" => "meta-ingest-pipeline"}}) }
|
782
|
+
|
783
|
+
it "interpolates the target_ingest_pipeline value and set it" do
|
784
|
+
expect(subject.send(:event_action_tuple, event)[1]).to include(:pipeline => "meta-ingest-pipeline")
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
context "with empty target_ingest_pipeline" do
|
789
|
+
let(:event) { LogStash::Event.new({"pipeline" => "", "@metadata" => {"host" => "elastic"}}) }
|
790
|
+
|
791
|
+
it "does not set pipeline" do
|
792
|
+
expect(subject.send(:event_action_tuple, event)[1]).not_to include(:pipeline)
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
context "with empty pipeline and empty target_ingest_pipeline" do
|
797
|
+
let(:event) { LogStash::Event.new }
|
798
|
+
|
799
|
+
it "does not set pipeline" do
|
604
800
|
expect(subject.send(:event_action_tuple, event)[1]).not_to include(:pipeline)
|
605
801
|
end
|
606
802
|
end
|
@@ -640,9 +836,8 @@ describe LogStash::Outputs::ElasticSearch do
|
|
640
836
|
end
|
641
837
|
end
|
642
838
|
|
643
|
-
|
644
|
-
|
645
|
-
let(:options) { {"ssl" => true}}
|
839
|
+
context "With the 'ssl_enabled' option" do
|
840
|
+
let(:options) { {"ssl_enabled" => true}}
|
646
841
|
|
647
842
|
include_examples("an encrypted client connection")
|
648
843
|
end
|
@@ -653,6 +848,81 @@ describe LogStash::Outputs::ElasticSearch do
|
|
653
848
|
end
|
654
849
|
end
|
655
850
|
|
851
|
+
describe "SSL deprecated settings" do
|
852
|
+
let(:base_options) { {"ssl" => "true"} }
|
853
|
+
|
854
|
+
context "with client certificate" do
|
855
|
+
let(:do_register) { true }
|
856
|
+
let(:cacert) { Stud::Temporary.file.path }
|
857
|
+
let(:options) { base_options.merge(
|
858
|
+
"cacert" => cacert,
|
859
|
+
"ssl_certificate_verification" => false
|
860
|
+
) }
|
861
|
+
|
862
|
+
after :each do
|
863
|
+
File.delete(cacert)
|
864
|
+
end
|
865
|
+
|
866
|
+
it "should map new configs into params" do
|
867
|
+
expect(subject.params).to match hash_including(
|
868
|
+
"ssl_enabled" => true,
|
869
|
+
"ssl_verification_mode" => "none",
|
870
|
+
"ssl_certificate_authorities" => [cacert]
|
871
|
+
)
|
872
|
+
end
|
873
|
+
|
874
|
+
it "should set new configs variables" do
|
875
|
+
expect(subject.instance_variable_get(:@ssl_enabled)).to eql(true)
|
876
|
+
expect(subject.instance_variable_get(:@ssl_verification_mode)).to eql("none")
|
877
|
+
expect(subject.instance_variable_get(:@ssl_certificate_authorities)).to eql([cacert])
|
878
|
+
end
|
879
|
+
end
|
880
|
+
|
881
|
+
context "with java stores" do
|
882
|
+
let(:do_register) { true }
|
883
|
+
let(:keystore) { Stud::Temporary.file.path }
|
884
|
+
let(:truststore) { Stud::Temporary.file.path }
|
885
|
+
let(:options) { base_options.merge(
|
886
|
+
"keystore" => keystore,
|
887
|
+
"keystore_password" => "keystore",
|
888
|
+
"truststore" => truststore,
|
889
|
+
"truststore_password" => "truststore",
|
890
|
+
"ssl_certificate_verification" => true
|
891
|
+
) }
|
892
|
+
|
893
|
+
let(:spy_http_client_builder!) do
|
894
|
+
allow(described_class::HttpClientBuilder).to receive(:build).with(any_args).and_call_original
|
895
|
+
allow(described_class::HttpClientBuilder).to receive(:setup_ssl).with(any_args).and_return({})
|
896
|
+
end
|
897
|
+
|
898
|
+
after :each do
|
899
|
+
File.delete(keystore)
|
900
|
+
File.delete(truststore)
|
901
|
+
end
|
902
|
+
|
903
|
+
it "should map new configs into params" do
|
904
|
+
expect(subject.params).to match hash_including(
|
905
|
+
"ssl_enabled" => true,
|
906
|
+
"ssl_keystore_path" => keystore,
|
907
|
+
"ssl_truststore_path" => truststore,
|
908
|
+
"ssl_verification_mode" => "full"
|
909
|
+
)
|
910
|
+
|
911
|
+
expect(subject.params["ssl_keystore_password"].value).to eql("keystore")
|
912
|
+
expect(subject.params["ssl_truststore_password"].value).to eql("truststore")
|
913
|
+
end
|
914
|
+
|
915
|
+
it "should set new configs variables" do
|
916
|
+
expect(subject.instance_variable_get(:@ssl_enabled)).to eql(true)
|
917
|
+
expect(subject.instance_variable_get(:@ssl_keystore_path)).to eql(keystore)
|
918
|
+
expect(subject.instance_variable_get(:@ssl_keystore_password).value).to eql("keystore")
|
919
|
+
expect(subject.instance_variable_get(:@ssl_truststore_path)).to eql(truststore)
|
920
|
+
expect(subject.instance_variable_get(:@ssl_truststore_password).value).to eql("truststore")
|
921
|
+
expect(subject.instance_variable_get(:@ssl_verification_mode)).to eql("full")
|
922
|
+
end
|
923
|
+
end
|
924
|
+
end
|
925
|
+
|
656
926
|
describe "retry_on_conflict" do
|
657
927
|
let(:num_retries) { 123 }
|
658
928
|
let(:event) { LogStash::Event.new("myactionfield" => "update", "message" => "blah") }
|
@@ -890,41 +1160,63 @@ describe LogStash::Outputs::ElasticSearch do
|
|
890
1160
|
end if LOGSTASH_VERSION > '6.0'
|
891
1161
|
|
892
1162
|
context 'handling elasticsearch document-level status meant for the DLQ' do
|
1163
|
+
let(:es_api_action) { "CUSTOM_ACTION" }
|
1164
|
+
let(:es_api_params) { Hash['_index' => 'MY_INDEX'] }
|
1165
|
+
|
893
1166
|
let(:options) { { "manage_template" => false, "data_stream" => 'false' } }
|
894
|
-
let(:action) { LogStash::Outputs::ElasticSearch::EventActionTuple.new(
|
1167
|
+
let(:action) { LogStash::Outputs::ElasticSearch::EventActionTuple.new(es_api_action, es_api_params, LogStash::Event.new("foo" => "bar")) }
|
1168
|
+
|
1169
|
+
let(:logger) { double('logger').as_null_object }
|
1170
|
+
before(:each) { subject.instance_variable_set(:@logger, logger) }
|
895
1171
|
|
896
1172
|
context 'when @dlq_writer is nil' do
|
897
1173
|
before { subject.instance_variable_set '@dlq_writer', nil }
|
898
|
-
let(:action) { LogStash::Outputs::ElasticSearch::EventActionTuple.new(:action, :params, LogStash::Event.new("foo" => "bar")) }
|
899
1174
|
|
900
1175
|
context 'resorting to previous behaviour of logging the error' do
|
901
1176
|
context 'getting an invalid_index_name_exception' do
|
902
1177
|
it 'should log at ERROR level' do
|
903
|
-
|
1178
|
+
# logger = double("logger").as_null_object
|
1179
|
+
# subject.instance_variable_set(:@logger, logger)
|
1180
|
+
|
904
1181
|
mock_response = { 'index' => { 'error' => { 'type' => 'invalid_index_name_exception' } } }
|
905
1182
|
subject.handle_dlq_response("Could not index event to Elasticsearch.", action, :some_status, mock_response)
|
1183
|
+
|
1184
|
+
expect(logger).to have_received(:error).with(a_string_including("Could not index event to Elasticsearch"),
|
1185
|
+
a_hash_including(:status => :some_status,
|
1186
|
+
:action => [es_api_action, es_api_params, action.event.to_hash],
|
1187
|
+
:response => mock_response))
|
906
1188
|
end
|
907
1189
|
end
|
908
1190
|
|
909
1191
|
context 'when getting any other exception' do
|
910
1192
|
it 'should log at WARN level' do
|
911
|
-
logger = double("logger").as_null_object
|
912
|
-
subject.instance_variable_set(:@logger, logger)
|
913
|
-
|
1193
|
+
# logger = double("logger").as_null_object
|
1194
|
+
# subject.instance_variable_set(:@logger, logger)
|
1195
|
+
|
914
1196
|
mock_response = { 'index' => { 'error' => { 'type' => 'illegal_argument_exception' } } }
|
915
1197
|
subject.handle_dlq_response("Could not index event to Elasticsearch.", action, :some_status, mock_response)
|
1198
|
+
|
1199
|
+
expect(logger).to have_received(:warn).with(a_string_including("Could not index event to Elasticsearch"),
|
1200
|
+
a_hash_including(:status => :some_status,
|
1201
|
+
:action => [es_api_action, es_api_params, action.event.to_hash],
|
1202
|
+
:response => mock_response))
|
916
1203
|
end
|
917
1204
|
end
|
918
1205
|
|
919
1206
|
context 'when the response does not include [error]' do
|
920
1207
|
it 'should not fail, but just log a warning' do
|
921
|
-
logger = double("logger").as_null_object
|
922
|
-
subject.instance_variable_set(:@logger, logger)
|
923
|
-
|
1208
|
+
# logger = double("logger").as_null_object
|
1209
|
+
# subject.instance_variable_set(:@logger, logger)
|
1210
|
+
|
924
1211
|
mock_response = { 'index' => {} }
|
925
1212
|
expect do
|
926
1213
|
subject.handle_dlq_response("Could not index event to Elasticsearch.", action, :some_status, mock_response)
|
927
1214
|
end.to_not raise_error
|
1215
|
+
|
1216
|
+
expect(logger).to have_received(:warn).with(a_string_including("Could not index event to Elasticsearch"),
|
1217
|
+
a_hash_including(:status => :some_status,
|
1218
|
+
:action => [es_api_action, es_api_params, action.event.to_hash],
|
1219
|
+
:response => mock_response))
|
928
1220
|
end
|
929
1221
|
end
|
930
1222
|
end
|
@@ -944,6 +1236,8 @@ describe LogStash::Outputs::ElasticSearch do
|
|
944
1236
|
mock_response = { 'index' => { 'error' => { 'type' => 'illegal_argument_exception' } } }
|
945
1237
|
action = LogStash::Outputs::ElasticSearch::EventActionTuple.new(:action, :params, event)
|
946
1238
|
subject.handle_dlq_response("Could not index event to Elasticsearch.", action, 404, mock_response)
|
1239
|
+
|
1240
|
+
expect(logger).to_not have_received(:warn).with(a_string_including("Could not index event to Elasticsearch"))
|
947
1241
|
end
|
948
1242
|
end
|
949
1243
|
|
@@ -1034,12 +1328,12 @@ describe LogStash::Outputs::ElasticSearch do
|
|
1034
1328
|
it 'adds the appropriate Authorization header to the manticore client' do
|
1035
1329
|
expect(manticore_options[:headers]).to eq({ "Authorization" => base64_api_key })
|
1036
1330
|
end
|
1037
|
-
it 'is provides
|
1038
|
-
expect(described_class::HttpClientBuilder).to have_received(:build).with(anything, anything, hash_including('
|
1331
|
+
it 'is provides ssl_enabled=>true to the http client builder' do; aggregate_failures do
|
1332
|
+
expect(described_class::HttpClientBuilder).to have_received(:build).with(anything, anything, hash_including('ssl_enabled'=>true))
|
1039
1333
|
end; end
|
1040
1334
|
end
|
1041
1335
|
|
1042
|
-
context "when set without
|
1336
|
+
context "when set without ssl_enabled => true" do
|
1043
1337
|
let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
|
1044
1338
|
let(:options) { { "api_key" => api_key } }
|
1045
1339
|
|
@@ -1055,14 +1349,14 @@ describe LogStash::Outputs::ElasticSearch do
|
|
1055
1349
|
end
|
1056
1350
|
end
|
1057
1351
|
|
1058
|
-
context "when set without
|
1352
|
+
context "when set without ssl_enabled specified but with an https host" do
|
1059
1353
|
let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
|
1060
1354
|
let(:options) { { "hosts" => ["https://some.host.com"], "api_key" => api_key } }
|
1061
1355
|
|
1062
1356
|
it_behaves_like 'secure api-key authenticated client'
|
1063
1357
|
end
|
1064
1358
|
|
1065
|
-
context "when set without
|
1359
|
+
context "when set without ssl_enabled specified but with an http host`" do
|
1066
1360
|
let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
|
1067
1361
|
let(:options) { { "hosts" => ["http://some.host.com"], "api_key" => api_key } }
|
1068
1362
|
|
@@ -1071,9 +1365,9 @@ describe LogStash::Outputs::ElasticSearch do
|
|
1071
1365
|
end
|
1072
1366
|
end
|
1073
1367
|
|
1074
|
-
context "when set with `
|
1368
|
+
context "when set with `ssl_enabled => false`" do
|
1075
1369
|
let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
|
1076
|
-
let(:options) { { "
|
1370
|
+
let(:options) { { "ssl_enabled" => "false", "api_key" => api_key } }
|
1077
1371
|
|
1078
1372
|
it "should raise a configuration error" do
|
1079
1373
|
expect { subject.register }.to raise_error LogStash::ConfigurationError, /requires SSL\/TLS/
|
@@ -1083,13 +1377,13 @@ describe LogStash::Outputs::ElasticSearch do
|
|
1083
1377
|
context "when set" do
|
1084
1378
|
let(:options) { { "api_key" => ::LogStash::Util::Password.new(api_key) } }
|
1085
1379
|
|
1086
|
-
context "with
|
1087
|
-
let(:options) { super().merge("
|
1380
|
+
context "with ssl_enabled => true" do
|
1381
|
+
let(:options) { super().merge("ssl_enabled" => true) }
|
1088
1382
|
it_behaves_like 'secure api-key authenticated client'
|
1089
1383
|
end
|
1090
1384
|
|
1091
|
-
context "with
|
1092
|
-
let(:options) { super().merge("
|
1385
|
+
context "with ssl_enabled => false" do
|
1386
|
+
let(:options) { super().merge("ssl_enabled" => "false") }
|
1093
1387
|
|
1094
1388
|
let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
|
1095
1389
|
it "should raise a configuration error" do
|
@@ -1097,7 +1391,7 @@ describe LogStash::Outputs::ElasticSearch do
|
|
1097
1391
|
end
|
1098
1392
|
end
|
1099
1393
|
|
1100
|
-
context "without
|
1394
|
+
context "without ssl_enabled specified" do
|
1101
1395
|
context "with an https host" do
|
1102
1396
|
let(:options) { super().merge("hosts" => ["https://some.host.com"]) }
|
1103
1397
|
it_behaves_like 'secure api-key authenticated client'
|
@@ -1121,7 +1415,7 @@ describe LogStash::Outputs::ElasticSearch do
|
|
1121
1415
|
|
1122
1416
|
context 'user also set' do
|
1123
1417
|
let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
|
1124
|
-
let(:options) { { "
|
1418
|
+
let(:options) { { "ssl_enabled" => true, "api_key" => api_key, 'user' => 'another' } }
|
1125
1419
|
|
1126
1420
|
it "should fail" do
|
1127
1421
|
expect { subject.register }.to raise_error LogStash::ConfigurationError, /Multiple authentication options are specified/
|
@@ -1130,7 +1424,7 @@ describe LogStash::Outputs::ElasticSearch do
|
|
1130
1424
|
|
1131
1425
|
context 'cloud_auth also set' do
|
1132
1426
|
let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
|
1133
|
-
let(:options) { { "
|
1427
|
+
let(:options) { { "ssl_enabled" => true, "api_key" => api_key, 'cloud_auth' => 'foobar' } }
|
1134
1428
|
|
1135
1429
|
it "should fail" do
|
1136
1430
|
expect { subject.register }.to raise_error LogStash::ConfigurationError, /Multiple authentication options are specified/
|
@@ -1225,6 +1519,42 @@ describe LogStash::Outputs::ElasticSearch do
|
|
1225
1519
|
end
|
1226
1520
|
|
1227
1521
|
end
|
1522
|
+
|
1523
|
+
context 'during register/finish_register' do
|
1524
|
+
|
1525
|
+
let(:options) { { 'hosts' => '127.0.0.1:9999', 'data_stream' => 'true' } }
|
1526
|
+
let(:es_version) { '8.7.0' } # DS default on LS 8.x
|
1527
|
+
|
1528
|
+
before do
|
1529
|
+
allow(subject).to receive(:discover_cluster_uuid)
|
1530
|
+
allow(subject).to receive(:maybe_create_rollover_alias)
|
1531
|
+
allow(subject).to receive(:maybe_create_ilm_policy)
|
1532
|
+
allow(subject).to receive(:build_client)
|
1533
|
+
end
|
1534
|
+
|
1535
|
+
# this test could not have been done using latches as the fix to the race
|
1536
|
+
# condition alters the order of the instructions in elasticsearch.rb
|
1537
|
+
#
|
1538
|
+
# the race condition happened when the @index was set to the datastream
|
1539
|
+
# after `ilm_in_use?` is called but before `setup_ilm`
|
1540
|
+
it 'doesn\'t have a race condition leading to resetting back to ILM' do
|
1541
|
+
ilm_in_use = subject.method(:ilm_in_use?)
|
1542
|
+
expect(subject).to receive(:ilm_in_use?) do |params|
|
1543
|
+
ret = ilm_in_use.call
|
1544
|
+
sleep 3
|
1545
|
+
ret
|
1546
|
+
end
|
1547
|
+
setup_mapper_and_target = subject.method(:setup_mapper_and_target)
|
1548
|
+
expect(subject).to receive(:setup_mapper_and_target).once do |params|
|
1549
|
+
sleep 1
|
1550
|
+
setup_mapper_and_target.call(params)
|
1551
|
+
end
|
1552
|
+
subject.register
|
1553
|
+
sleep 6
|
1554
|
+
expect(subject.index).to eq("logs-generic-default")
|
1555
|
+
end
|
1556
|
+
|
1557
|
+
end
|
1228
1558
|
end
|
1229
1559
|
|
1230
1560
|
@private
|