logstash-input-beats 3.1.0.beta1-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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +131 -0
  3. data/CONTRIBUTORS +17 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +14 -0
  6. data/NOTICE.TXT +5 -0
  7. data/PROTOCOL.md +127 -0
  8. data/README.md +98 -0
  9. data/VERSION +1 -0
  10. data/lib/logstash-input-beats_jars.rb +17 -0
  11. data/lib/logstash/inputs/beats.rb +184 -0
  12. data/lib/logstash/inputs/beats/codec_callback_listener.rb +26 -0
  13. data/lib/logstash/inputs/beats/decoded_event_transform.rb +34 -0
  14. data/lib/logstash/inputs/beats/event_transform_common.rb +48 -0
  15. data/lib/logstash/inputs/beats/message_listener.rb +96 -0
  16. data/lib/logstash/inputs/beats/raw_event_transform.rb +18 -0
  17. data/lib/logstash/inputs/beats/tls.rb +40 -0
  18. data/lib/tasks/build.rake +15 -0
  19. data/lib/tasks/test.rake +65 -0
  20. data/logstash-input-beats.gemspec +41 -0
  21. data/spec/inputs/beats/codec_callback_listener_spec.rb +33 -0
  22. data/spec/inputs/beats/decoded_event_transform_spec.rb +74 -0
  23. data/spec/inputs/beats/event_transform_common_spec.rb +11 -0
  24. data/spec/inputs/beats/message_listener_spec.rb +108 -0
  25. data/spec/inputs/beats/raw_event_transform_spec.rb +26 -0
  26. data/spec/inputs/beats/tls_spec.rb +39 -0
  27. data/spec/inputs/beats_spec.rb +99 -0
  28. data/spec/integration/filebeat_spec.rb +234 -0
  29. data/spec/integration/logstash_forwarder_spec.rb +104 -0
  30. data/spec/spec_helper.rb +14 -0
  31. data/spec/support/client_process_helpers.rb +28 -0
  32. data/spec/support/file_helpers.rb +61 -0
  33. data/spec/support/flores_extensions.rb +82 -0
  34. data/spec/support/integration_shared_context.rb +73 -0
  35. data/spec/support/logstash_test.rb +66 -0
  36. data/spec/support/shared_examples.rb +56 -0
  37. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-annotations/2.7.5/jackson-annotations-2.7.5.jar +0 -0
  38. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-core/2.7.5/jackson-core-2.7.5.jar +0 -0
  39. data/vendor/jar-dependencies/com/fasterxml/jackson/core/jackson-databind/2.7.5/jackson-databind-2.7.5.jar +0 -0
  40. data/vendor/jar-dependencies/com/fasterxml/jackson/module/jackson-module-afterburner/2.7.5/jackson-module-afterburner-2.7.5.jar +0 -0
  41. data/vendor/jar-dependencies/io/netty/netty-all/4.1.1.Final/netty-all-4.1.1.Final.jar +0 -0
  42. data/vendor/jar-dependencies/io/netty/netty-tcnative-boringssl-static/1.1.33.Fork17/netty-tcnative-boringssl-static-1.1.33.Fork17.jar +0 -0
  43. data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-1.2-api/2.6.1/log4j-1.2-api-2.6.1.jar +0 -0
  44. data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-api/2.6.1/log4j-api-2.6.1.jar +0 -0
  45. data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-core/2.6.1/log4j-core-2.6.1.jar +0 -0
  46. data/vendor/jar-dependencies/org/apache/logging/log4j/log4j-slf4j-impl/2.6.1/log4j-slf4j-impl-2.6.1.jar +0 -0
  47. data/vendor/jar-dependencies/org/bouncycastle/bcpkix-jdk15on/1.54/bcpkix-jdk15on-1.54.jar +0 -0
  48. data/vendor/jar-dependencies/org/bouncycastle/bcprov-jdk15on/1.54/bcprov-jdk15on-1.54.jar +0 -0
  49. data/vendor/jar-dependencies/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar +0 -0
  50. data/vendor/jar-dependencies/org/logstash/beats/logstash-input-beats/3.1.0.beta1/logstash-input-beats-3.1.0.beta1.jar +0 -0
  51. metadata +313 -0
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ require "logstash/event"
3
+ require "logstash/inputs/beats"
4
+ require_relative "../../support/shared_examples"
5
+ require "spec_helper"
6
+
7
+ describe LogStash::Inputs::Beats::EventTransformCommon do
8
+ subject { described_class.new(input).transform(event) }
9
+
10
+ include_examples "Common Event Transformation"
11
+ end
@@ -0,0 +1,108 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/beats"
3
+ require "logstash/event"
4
+ require "logstash/inputs/beats/message_listener"
5
+ require "thread"
6
+
7
+ class MockMessage
8
+ def initialize(identity_stream, data = {})
9
+ @identity_stream = identity_stream
10
+ @data = data
11
+ end
12
+
13
+ def getData
14
+ @data
15
+ end
16
+
17
+ def getIdentityStream
18
+ @identity_stream
19
+ end
20
+ end
21
+
22
+ class DummyCodec < LogStash::Codecs::Base
23
+ DUMMY_EVENT = LogStash::Event.new
24
+
25
+ def decode(message, &block)
26
+ block.call(LogStash::Event.new({"message" => message}))
27
+ end
28
+
29
+ def flush(&block)
30
+ block.call(DUMMY_EVENT)
31
+ end
32
+ end
33
+
34
+ describe LogStash::Inputs::Beats::MessageListener do
35
+ let(:queue) { Queue.new }
36
+ let(:codec) { DummyCodec.new }
37
+ let(:input) { LogStash::Inputs::Beats.new({ "port" => 5555, "codec" => codec }) }
38
+ let(:ctx) { double("ChannelHandlerContext") }
39
+ let(:message) { MockMessage.new("abc", { "message" => "hello world"}) }
40
+
41
+ subject { described_class.new(queue, input) }
42
+
43
+ before do
44
+ subject.onNewConnection(ctx)
45
+ end
46
+
47
+ context "onNewConnection" do
48
+ it "register the connection to the connection list" do
49
+ expect { subject.onNewConnection(double("ChannelHandlerContext")) }.to change { subject.connections_list.count }.by(1)
50
+ end
51
+ end
52
+
53
+ context "onNewMessage" do
54
+ context "when the message is from filebeat" do
55
+ let(:message) { MockMessage.new("abc", { "message" => "hello world" } )}
56
+
57
+ it "extract the event" do
58
+ subject.onNewMessage(ctx, message)
59
+ event = queue.pop
60
+ expect(event.get("message")).to eq("hello world")
61
+ end
62
+ end
63
+
64
+ context "when the message is from LSF" do
65
+ let(:message) { MockMessage.new("abc", { "line" => "hello world" } )}
66
+
67
+ it "extract the event" do
68
+ subject.onNewMessage(ctx, message)
69
+ event = queue.pop
70
+ expect(event.get("message")).to eq("hello world")
71
+ end
72
+ end
73
+
74
+ context "when the message is from any libbeat" do
75
+ let(:message) { MockMessage.new("abc", { "metric" => 1, "name" => "super-stats"} )}
76
+
77
+ it "extract the event" do
78
+ subject.onNewMessage(ctx, message)
79
+ event = queue.pop
80
+ expect(event.get("message")).to be_nil
81
+ expect(event.get("metric")).to eq(1)
82
+ expect(event.get("name")).to eq("super-stats")
83
+ end
84
+ end
85
+ end
86
+
87
+ context "onException" do
88
+ it "remove the connection to the connection list" do
89
+ expect { subject.onException(ctx) }.to change { subject.connections_list.count }.by(-1)
90
+ end
91
+
92
+ it "calls flush on codec" do
93
+ subject.onConnectionClose(ctx)
94
+ expect(queue).not_to be_empty
95
+ end
96
+ end
97
+
98
+ context "onConnectionClose" do
99
+ it "remove the connection to the connection list" do
100
+ expect { subject.onConnectionClose(ctx) }.to change { subject.connections_list.count }.by(-1)
101
+ end
102
+
103
+ it "calls flush on codec" do
104
+ subject.onConnectionClose(ctx)
105
+ expect(queue).not_to be_empty
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ require "logstash/event"
3
+ require "logstash/inputs/beats"
4
+ require_relative "../../support/shared_examples"
5
+ require "spec_helper"
6
+
7
+ describe LogStash::Inputs::Beats::RawEventTransform do
8
+ let(:config) do
9
+ {
10
+ "port" => 0,
11
+ "type" => "example",
12
+ "tags" => "beats"
13
+ }
14
+ end
15
+
16
+ let(:input) { LogStash::Inputs::Beats.new(config) }
17
+ let(:event) { LogStash::Event.new }
18
+
19
+ subject { described_class.new(input).transform(event) }
20
+
21
+ include_examples "Common Event Transformation"
22
+
23
+ it "tags the event" do
24
+ expect(subject.get("tags")).to include("beats_input_raw_event")
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/beats/tls"
3
+
4
+ describe LogStash::Inputs::Beats::TLS do
5
+ subject { described_class }
6
+
7
+ it "returns the minimum supported tls" do
8
+ expect(subject.min.version).to eq(1)
9
+ expect(subject.min.name).to eq("TLSv1")
10
+ end
11
+
12
+ it "returns the maximum supported tls" do
13
+ expect(subject.max.version).to eq(1.2)
14
+ expect(subject.max.name).to eq("TLSv1.2")
15
+ end
16
+
17
+ describe ".get_supported" do
18
+ context "when a range is given" do
19
+ it "returns the list of compatible TLS from a range" do
20
+ expect(subject.get_supported((1.1)..(1.2)).map(&:version)).to match([1.1, 1.2])
21
+ end
22
+
23
+ it "it return an empty array when nothing match" do
24
+ expect(subject.get_supported((3.1)..(8.2))).to be_empty
25
+ end
26
+ end
27
+
28
+ context "when a scalar is given" do
29
+ it "when a scalar is given we return the compatible value" do
30
+ expect(subject.get_supported(1.1).map(&:version)).to match([1.1])
31
+ end
32
+
33
+
34
+ it "it return an empty array when nothing match" do
35
+ expect(subject.get_supported(9)).to be_empty
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,99 @@
1
+ # encoding: utf-8
2
+ require_relative "../spec_helper"
3
+ require "stud/temporary"
4
+ require "logstash/inputs/beats"
5
+ require "logstash/codecs/plain"
6
+ require "logstash/codecs/json"
7
+ require "logstash/codecs/multiline"
8
+ require "logstash/event"
9
+
10
+ describe LogStash::Inputs::Beats do
11
+ let(:connection) { double("connection") }
12
+ let(:certificate) { BeatsInputTest.certificate }
13
+ let(:port) { BeatsInputTest.random_port }
14
+ let(:queue) { Queue.new }
15
+ let(:config) { { "port" => 0, "ssl_certificate" => certificate.ssl_cert, "ssl_key" => certificate.ssl_key, "type" => "example", "tags" => "beats"} }
16
+
17
+ context "#register" do
18
+ context "identity map" do
19
+ subject(:plugin) { LogStash::Inputs::Beats.new(config) }
20
+ before { plugin.register }
21
+
22
+ context "when using the multiline codec" do
23
+ let(:codec) { LogStash::Codecs::Multiline.new("pattern" => '^2015',
24
+ "what" => "previous",
25
+ "negate" => true) }
26
+ let(:config) { super.merge({ "codec" => codec }) }
27
+
28
+ it "wraps the codec with the identity_map" do
29
+ expect(plugin.codec).to be_kind_of(LogStash::Codecs::IdentityMapCodec)
30
+ end
31
+ end
32
+
33
+ context "when using non buffered codecs" do
34
+ let(:config) { super.merge({ "codec" => "json" }) }
35
+
36
+ it "doesnt wrap the codec with the identity map" do
37
+ expect(plugin.codec).to be_kind_of(LogStash::Codecs::JSON)
38
+ end
39
+ end
40
+ end
41
+
42
+ it "raise no exception" do
43
+ plugin = LogStash::Inputs::Beats.new(config)
44
+ expect { plugin.register }.not_to raise_error
45
+ end
46
+
47
+ context "with ssl enabled" do
48
+ context "without certificate configuration" do
49
+ let(:config) {{ "port" => 0, "ssl" => true, "ssl_key" => certificate.ssl_key, "type" => "example", "tags" => "beats" }}
50
+
51
+ it "should fail to register the plugin with ConfigurationError" do
52
+ plugin = LogStash::Inputs::Beats.new(config)
53
+ expect {plugin.register}.to raise_error(LogStash::ConfigurationError)
54
+ end
55
+ end
56
+
57
+ context "without key configuration" do
58
+ let(:config) { { "port" => 0, "ssl" => true, "ssl_certificate" => certificate.ssl_cert, "type" => "example", "tags" => "Beats"} }
59
+ it "should fail to register the plugin with ConfigurationError" do
60
+ plugin = LogStash::Inputs::Beats.new(config)
61
+ expect {plugin.register}.to raise_error(LogStash::ConfigurationError)
62
+ end
63
+ end
64
+ end
65
+
66
+ context "with ssl disabled" do
67
+ context "and certificate configuration" do
68
+ let(:config) { { "port" => 0, "ssl" => false, "ssl_certificate" => certificate.ssl_cert, "type" => "example", "tags" => "Beats" } }
69
+
70
+ it "should not fail" do
71
+ plugin = LogStash::Inputs::Beats.new(config)
72
+ expect {plugin.register}.not_to raise_error
73
+ end
74
+ end
75
+
76
+ context "and certificate key configuration" do
77
+ let(:config) {{ "port" => 0, "ssl" => false, "ssl_key" => certificate.ssl_key, "type" => "example", "tags" => "beats" }}
78
+
79
+ it "should not fail" do
80
+ plugin = LogStash::Inputs::Beats.new(config)
81
+ expect {plugin.register}.not_to raise_error
82
+ end
83
+ end
84
+
85
+ context "and no certificate or key configured" do
86
+ let(:config) {{ "ssl" => false, "port" => 0, "type" => "example", "tags" => "beats" }}
87
+
88
+ it "should work just fine" do
89
+ plugin = LogStash::Inputs::Beats.new(config)
90
+ expect {plugin.register}.not_to raise_error
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ context "when interrupting the plugin" do
97
+ it_behaves_like "an interruptible input plugin"
98
+ end
99
+ end
@@ -0,0 +1,234 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/beats"
3
+ require "stud/temporary"
4
+ require "flores/pki"
5
+ require "fileutils"
6
+ require "thread"
7
+ require "spec_helper"
8
+ require "yaml"
9
+ require "fileutils"
10
+ require "flores/pki"
11
+ require_relative "../support/flores_extensions"
12
+ require_relative "../support/file_helpers"
13
+ require_relative "../support/integration_shared_context"
14
+ require_relative "../support/client_process_helpers"
15
+
16
+ FILEBEAT_BINARY = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "vendor", "filebeat", "filebeat"))
17
+
18
+ describe "Filebeat", :integration => true do
19
+ include ClientProcessHelpers
20
+ include FileHelpers
21
+
22
+ before :all do
23
+ unless File.exist?(FILEBEAT_BINARY)
24
+ raise "Cannot find `Filebeat` binary in `vendor/filebeat`. Did you run `bundle exec rake test:integration:setup` before running the integration suite?"
25
+ end
26
+ end
27
+
28
+ include_context "beats configuration"
29
+
30
+ # Filebeat related variables
31
+ let(:cmd) { [filebeat_exec, "-c", filebeat_config_path, "-e", "-v"] }
32
+
33
+ let(:filebeat_exec) { FILEBEAT_BINARY }
34
+
35
+ let_empty_tmp_file(:registry_file)
36
+ let(:filebeat_config) do
37
+ {
38
+ "filebeat" => {
39
+ "prospectors" => [{ "paths" => [log_file], "input_type" => "log" }],
40
+ "registry_file" => registry_file,
41
+ "scan_frequency" => "1s"
42
+ },
43
+ "output" => {
44
+ "logstash" => { "hosts" => ["#{host}:#{port}"] },
45
+ "logging" => { "level" => "debug" }
46
+ }
47
+ }
48
+ end
49
+
50
+ let_tmp_file(:filebeat_config_path) { YAML.dump(filebeat_config) }
51
+ before :each do
52
+ start_client
53
+ sleep(2) # give some time to FB to send something
54
+ stop_client
55
+ end
56
+
57
+ ###########################################################
58
+ shared_context "Root CA" do
59
+ let(:root_ca) { Flores::PKI.generate("CN=root.localhost") }
60
+ let(:root_ca_certificate) { root_ca.first }
61
+ let(:root_ca_key) { root_ca.last }
62
+ let_tmp_file(:root_ca_certificate_file) { root_ca_certificate }
63
+ end
64
+
65
+ shared_context "Intermediate CA" do
66
+ let(:intermediate_ca) { Flores::PKI.create_intermediate_certificate("CN=intermediate.localhost", root_ca_certificate, root_ca_key) }
67
+ let(:intermediate_ca_certificate) { intermediate_ca.first }
68
+ let(:intermediate_ca_key) { intermediate_ca.last }
69
+ let_tmp_file(:intermediate_ca_certificate_file) { intermediate_ca_certificate }
70
+ let_tmp_file(:certificate_authorities_chain) { Flores::PKI.chain_certificates(root_ca_certificate, intermediate_ca_certificate) }
71
+ end
72
+
73
+ ############################################################
74
+ # Actuals tests
75
+ context "Plain TCP" do
76
+ include_examples "send events"
77
+ end
78
+
79
+ context "TLS" do
80
+ context "Server verification" do
81
+ let(:filebeat_config) do
82
+ super.merge({
83
+ "output" => {
84
+ "logstash" => {
85
+ "hosts" => ["#{host}:#{port}"],
86
+ "tls" => { "certificate_authorities" => certificate_authorities }
87
+ },
88
+ "logging" => { "level" => "debug" }
89
+ }})
90
+ end
91
+
92
+ let(:input_config) do
93
+ super.merge({
94
+ "ssl" => true,
95
+ "ssl_certificate" => certificate_file,
96
+ "ssl_key" => certificate_key_file
97
+ })
98
+ end
99
+
100
+ let(:certificate_authorities) { [certificate_file] }
101
+ let(:certificate_data) { Flores::PKI.generate }
102
+ let_tmp_file(:certificate_key_file) { certificate_data.last }
103
+ let_tmp_file(:certificate_file) { certificate_data.first }
104
+
105
+ context "self signed certificate" do
106
+ include_examples "send events"
107
+ end
108
+
109
+ context "CA root" do
110
+ include_context "Root CA"
111
+
112
+ context "directly signed client certificate" do
113
+ let(:certificate_authorities) { [root_ca_certificate_file] }
114
+ let(:certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", root_ca_certificate, root_ca_key) }
115
+
116
+ include_examples "send events"
117
+ end
118
+
119
+ context "intermediate CA signs client certificate" do
120
+ include_context "Intermediate CA"
121
+
122
+ let(:certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", intermediate_ca_certificate, intermediate_ca_key) }
123
+ let(:certificate_authorities) { [certificate_authorities_chain] }
124
+
125
+ include_examples "send events"
126
+ end
127
+ end
128
+
129
+ context "Client verification / Mutual validation" do
130
+ let(:filebeat_config) do
131
+ super.merge({
132
+ "output" => {
133
+ "logstash" => {
134
+ "hosts" => ["#{host}:#{port}"],
135
+ "tls" => {
136
+ "certificate_authorities" => certificate_authorities,
137
+ "certificate" => certificate_file,
138
+ "certificate_key" => certificate_key_file
139
+ }
140
+ },
141
+ "logging" => { "level" => "debug" }
142
+ }})
143
+ end
144
+
145
+ let(:input_config) do
146
+ super.merge({
147
+ "ssl" => true,
148
+ "ssl_certificate_authorities" => certificate_authorities,
149
+ "ssl_certificate" => server_certificate_file,
150
+ "ssl_key" => server_certificate_key_file,
151
+ "ssl_verify_mode" => "force_peer"
152
+ })
153
+ end
154
+
155
+ context "with a self signed certificate" do
156
+ let(:certificate_authorities) { [certificate_file] }
157
+ let(:certificate_data) { Flores::PKI.generate }
158
+ let_tmp_file(:certificate_key_file) { certificate_data.last }
159
+ let_tmp_file(:certificate_file) { certificate_data.first }
160
+ let_tmp_file(:server_certificate_file) { certificate_data.first }
161
+ let_tmp_file(:server_certificate_key_file) { certificate_data.last }
162
+
163
+ include_examples "send events"
164
+ end
165
+
166
+ context "CA root" do
167
+ include_context "Root CA"
168
+
169
+ let_tmp_file(:server_certificate_file) { server_certificate_data.first }
170
+ let_tmp_file(:server_certificate_key_file) { server_certificate_data.last }
171
+
172
+ context "directly signed client certificate" do
173
+ let(:certificate_authorities) { [root_ca_certificate_file] }
174
+ let(:certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", root_ca_certificate, root_ca_key) }
175
+ let(:server_certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", root_ca_certificate, root_ca_key) }
176
+
177
+ include_examples "send events"
178
+ end
179
+
180
+ ### DOESNT WORK
181
+ context "intermediate create server and client certificate" do
182
+ include_context "Intermediate CA"
183
+
184
+ let(:certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", intermediate_ca_certificate, intermediate_ca_key) }
185
+ let(:server_certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", intermediate_ca_certificate, intermediate_ca_key) }
186
+ let(:certificate_authorities) { [intermediate_ca_certificate_file] }
187
+
188
+ include_examples "send events"
189
+ end
190
+
191
+ context "and Secondary CA multiples clients" do
192
+ context "with CA in different files" do
193
+ let(:secondary_ca) { Flores::PKI.generate }
194
+ let(:secondary_ca_key) { secondary_ca.last }
195
+ let(:secondary_ca_certificate) { secondary_ca.first }
196
+ let_tmp_file(:secondary_ca_certificate_file) { secondary_ca.first }
197
+
198
+ let(:secondary_client_certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", secondary_ca_certificate, secondary_ca_key) }
199
+ let_tmp_file(:secondary_client_certificate_file) { secondary_client_certificate_data.first }
200
+ let_tmp_file(:secondary_client_certificate_key_file) { secondary_client_certificate_data.last }
201
+ let(:certificate_authorities) { [root_ca_certificate_file, secondary_ca_certificate_file] }
202
+ let(:certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", root_ca_certificate, root_ca_key) }
203
+
204
+ let(:server_certificate_data) { Flores::PKI.create_client_certicate("CN=localhost", root_ca_certificate, root_ca_key) }
205
+
206
+ context "client from primary CA" do
207
+ include_examples "send events"
208
+ end
209
+
210
+ context "client from secondary CA" do
211
+ let(:filebeat_config) do
212
+ super.merge({
213
+ "output" => {
214
+ "logstash" => {
215
+ "hosts" => ["#{host}:#{port}"],
216
+ "tls" => {
217
+ "certificate_authorities" => certificate_authorities,
218
+ "certificate" => secondary_client_certificate_file,
219
+ "certificate_key" => secondary_client_certificate_key_file
220
+ }
221
+ },
222
+ "logging" => { "level" => "debug" }
223
+ }})
224
+ end
225
+
226
+ include_examples "send events"
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end