fluent-plugin-syslog-p 1.0.0

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.
@@ -0,0 +1,18 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ # Copyright 2016-2019 t.e.morgan.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module SyslogTls
17
+ VERSION = '1.0.0'
18
+ end
@@ -0,0 +1,192 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ # Copyright 2016-2019 t.e.morgan.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'helper'
17
+ require 'ssl'
18
+ require 'date'
19
+ require 'minitest/mock'
20
+ require 'fluent/plugin/out_syslog_tls'
21
+ require 'fluent/test/driver/output'
22
+
23
+ class SyslogTlsOutputTest < Test::Unit::TestCase
24
+ include SSLTestHelper
25
+
26
+ def setup
27
+ Fluent::Test.setup
28
+ @driver = nil
29
+ end
30
+
31
+ def driver(conf='')
32
+ @driver ||= Fluent::Test::Driver::Output.new(Fluent::Plugin::SyslogTlsOutput).configure(conf)
33
+ end
34
+
35
+ def sample_record
36
+ {
37
+ "app_name" => "app",
38
+ "hostname" => "host",
39
+ "procid" => $$,
40
+ "msgid" => 1000,
41
+ "message" => "MESSAGE",
42
+ "severity" => "PANIC",
43
+ }
44
+ end
45
+
46
+ def mock_logger(token='TOKEN')
47
+ io = StringIO.new
48
+ io.set_encoding('utf-8')
49
+ ::SyslogTls::Logger.new(io, token)
50
+ end
51
+
52
+ def test_configure
53
+ config = %{
54
+ host syslog.collection.us1.sumologic.com
55
+ port 6514
56
+ client_cert
57
+ client_key
58
+ verify_cert_name true
59
+ token 1234567890
60
+ }
61
+ instance = driver(config).instance
62
+
63
+ assert_equal 'syslog.collection.us1.sumologic.com', instance.host
64
+ assert_equal '6514', instance.port
65
+ assert_equal '', instance.client_cert
66
+ assert_equal '', instance.client_key
67
+ assert_equal true, instance.verify_cert_name
68
+ assert_equal '1234567890', instance.token
69
+ end
70
+
71
+ def test_default_emit
72
+ config = %{
73
+ host syslog.collection.us1.sumologic.com
74
+ port 6514
75
+ client_cert
76
+ client_key
77
+ }
78
+ instance = driver(config).instance
79
+
80
+ time = Time.now
81
+ record = sample_record
82
+ logger = mock_logger(instance.token)
83
+
84
+ instance.stub(:new_logger, logger) do
85
+ instance.process('test', {time.to_i => record})
86
+ end
87
+
88
+ assert_equal "<134>1 #{time.to_datetime.rfc3339} - - - - - #{record.to_json.to_s}\n\n", logger.transport.string
89
+ end
90
+
91
+ def test_message_headers_mapping
92
+ config = %{
93
+ host syslog.collection.us1.sumologic.com
94
+ port 6514
95
+ client_cert
96
+ client_key
97
+ token 1234567890
98
+ hostname_key hostname
99
+ procid_key procid
100
+ app_name_key app_name
101
+ msgid_key msgid
102
+ }
103
+ instance = driver(config).instance
104
+
105
+ time = Time.now
106
+ record = sample_record
107
+ logger = mock_logger
108
+
109
+ instance.stub(:new_logger, logger) do
110
+ instance.process('test', {time.to_i => record})
111
+ end
112
+
113
+ assert_true logger.transport.string.start_with?("<134>1 #{time.to_datetime.rfc3339} host app #{$$} 1000 [TOKEN]")
114
+ end
115
+
116
+ def test_message_severity_mapping
117
+ config = %{
118
+ host syslog.collection.us1.sumologic.com
119
+ port 6514
120
+ client_cert
121
+ client_key
122
+ token 1234567890
123
+ severity_key severity
124
+ }
125
+ instance = driver(config).instance
126
+
127
+ time = Time.now
128
+ record = sample_record
129
+ logger = mock_logger
130
+
131
+ instance.stub(:new_logger, logger) do
132
+ instance.process('test', {time.to_i => record})
133
+ end
134
+
135
+ assert_true logger.transport.string.start_with?("<128>1")
136
+ end
137
+
138
+ def test_formatter
139
+ config = %{
140
+ host syslog.collection.us1.sumologic.com
141
+ port 6514
142
+ client_cert
143
+ client_key
144
+ token 1234567890
145
+ format out_file
146
+ localtime false
147
+ }
148
+ instance = driver(config).instance
149
+
150
+ time = Time.now
151
+ record = sample_record
152
+ logger = mock_logger
153
+
154
+ instance.stub(:new_logger, logger) do
155
+ instance.process('test', {time.to_i => record})
156
+ end
157
+
158
+ formatted_time = time.dup.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
159
+ assert_equal "<134>1 #{time.to_datetime.rfc3339} - - - - [TOKEN] #{formatted_time}\ttest\t#{record.to_json.to_s}\n\n", logger.transport.string
160
+ end
161
+
162
+ def test_ssl
163
+ time = Time.now
164
+ record = sample_record
165
+
166
+ server = ssl_server
167
+ st = Thread.new {
168
+ client = server.accept
169
+ assert_equal "<134>1 #{time.to_datetime.rfc3339} host app #{$$} 1000 [1234567890] #{record.to_json.to_s}\n", client.gets
170
+ client.close
171
+ }
172
+
173
+ config = %{
174
+ host localhost
175
+ port #{server.addr[1]}
176
+ client_cert
177
+ client_key
178
+ token 1234567890
179
+ hostname_key hostname
180
+ procid_key procid
181
+ app_name_key app_name
182
+ msgid_key msgid
183
+ }
184
+ instance = driver(config).instance
185
+
186
+ SyslogTls::SSLTransport.stub_any_instance(:get_ssl_connection, ssl_client) do
187
+ instance.process('test', {time.to_i => record})
188
+ end
189
+
190
+ st.join
191
+ end
192
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,28 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'coveralls'
16
+ require 'simplecov'
17
+
18
+ SimpleCov.start
19
+
20
+ Coveralls.wear! if ENV['TRAVIS']
21
+
22
+ require 'test/unit'
23
+ require 'fluent/test'
24
+ require 'minitest/pride'
25
+ require 'minitest/stub_any_instance'
26
+
27
+ require 'webmock/test_unit'
28
+ WebMock.disable_net_connect!
data/test/ssl.rb ADDED
@@ -0,0 +1,51 @@
1
+ require 'socket'
2
+ require 'openssl'
3
+
4
+ module SSLTestHelper
5
+ def ssl_server
6
+ @ssl_server ||= begin
7
+ tcp_server = TCPServer.new("localhost", 33000 + Random.rand(1000))
8
+ ssl_context = OpenSSL::SSL::SSLContext.new
9
+ ssl_context.cert = certificate
10
+ ssl_context.key = rsa_key
11
+ OpenSSL::SSL::SSLServer.new(tcp_server, ssl_context)
12
+ end
13
+ end
14
+
15
+ def ssl_client
16
+ tcp = TCPSocket.new("localhost", ssl_server.addr[1])
17
+ ctx = OpenSSL::SSL::SSLContext.new
18
+ ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)
19
+ ctx.cert = certificate
20
+ ctx.key = rsa_key
21
+ OpenSSL::SSL::SSLSocket.new(tcp, ctx)
22
+ end
23
+
24
+ def rsa_key
25
+ @rsa_key ||= OpenSSL::PKey::RSA.new(2048)
26
+ end
27
+
28
+ def certificate
29
+ @cert ||= begin
30
+ cert = OpenSSL::X509::Certificate.new
31
+ cert.subject = cert.issuer = OpenSSL::X509::Name.parse("/C=BE/O=Test/OU=Test/CN=Test")
32
+ cert.not_before = Time.now
33
+ cert.not_after = Time.now + 365 * 24 * 60 * 60
34
+ cert.public_key = rsa_key.public_key
35
+ cert.serial = 0x0
36
+ cert.version = 2
37
+
38
+ ef = OpenSSL::X509::ExtensionFactory.new
39
+ ef.subject_certificate = cert
40
+ ef.issuer_certificate = cert
41
+ cert.extensions = [
42
+ ef.create_extension("basicConstraints","CA:TRUE", true),
43
+ ef.create_extension("subjectKeyIdentifier", "hash"),
44
+ # ef.create_extension("keyUsage", "cRLSign,keyCertSign", true),
45
+ ]
46
+ cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
47
+ cert.sign(rsa_key, OpenSSL::Digest::SHA1.new)
48
+ cert
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,48 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ # Copyright 2016 t.e.morgan.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'helper'
17
+ require 'date'
18
+ require 'syslog_tls/logger'
19
+
20
+ class LoggerTest < Test::Unit::TestCase
21
+ def test_logger_defaults
22
+ io = StringIO.new
23
+ l = SyslogTls::Logger.new(io, "TOKEN")
24
+ time = Time.now
25
+ l.log(:WARN, "MESSAGE", time: time)
26
+ assert_equal "<132>1 #{time.to_datetime.rfc3339} - - - - [TOKEN] MESSAGE\n", io.string
27
+ end
28
+
29
+ def test_logger_default_headers
30
+ io = StringIO.new
31
+ l = SyslogTls::Logger.new(io, "TOKEN")
32
+ l.hostname("hostname")
33
+ l.app_name("appname")
34
+ l.procid($$)
35
+ l.facility("SYSLOG")
36
+ time = Time.now
37
+ l.log(:WARN, "MESSAGE", time: time)
38
+ assert_equal "<44>1 #{time.to_datetime.rfc3339} hostname appname #{$$} - [TOKEN] MESSAGE\n", io.string
39
+ end
40
+
41
+ def test_logger_closed
42
+ io = StringIO.new
43
+ l = SyslogTls::Logger.new(io, "TOKEN")
44
+ assert_false l.closed?
45
+ l.close
46
+ assert_true l.closed?
47
+ end
48
+ end
@@ -0,0 +1,150 @@
1
+ # Copyright 2016 Acquia, Inc.
2
+ # Copyright 2016 t.e.morgan.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'helper'
17
+ require 'date'
18
+ require 'syslog_tls/protocol'
19
+
20
+ class ProtocolTest < Test::Unit::TestCase
21
+ def test_header_defaults
22
+ h = SyslogTls::Header.new
23
+
24
+ # Check defaults
25
+ assert_equal 'INFO', h.severity
26
+ assert_equal 'LOCAL0', h.facility
27
+ assert_equal 1, h.version
28
+ assert_equal SyslogTls::NIL_VALUE, h.hostname
29
+ assert_equal SyslogTls::NIL_VALUE, h.app_name
30
+ assert_equal SyslogTls::NIL_VALUE, h.procid
31
+ assert_equal SyslogTls::NIL_VALUE, h.msgid
32
+
33
+ assert_equal "<#{h.pri}>1 #{h.timestamp.to_datetime.rfc3339} - - - -", h.to_s
34
+ end
35
+
36
+ def test_header_facility_setter
37
+ h = SyslogTls::Header.new
38
+ assert_raise do
39
+ h.facility = "NON_EXISTING"
40
+ end
41
+ SyslogTls::Header::FACILITIES.each do |facility, _|
42
+ assert_nothing_raised do
43
+ h.facility = facility
44
+ end
45
+ end
46
+ end
47
+
48
+ def test_header_severity_setter
49
+ h = SyslogTls::Header.new
50
+ assert_raise do
51
+ h.severity = "NON_EXISTING"
52
+ end
53
+ SyslogTls::Header::SEVERITIES.each do |severity, _|
54
+ assert_nothing_raised do
55
+ h.severity = severity
56
+ end
57
+ end
58
+ end
59
+
60
+ def test_header_timestamp_setter
61
+ h = SyslogTls::Header.new
62
+ assert_raise do
63
+ h.timestamp = Time.now.to_i
64
+ end
65
+ assert_nothing_raised do
66
+ h.timestamp = Time.now
67
+ end
68
+ end
69
+
70
+ def test_header_hostname
71
+ h = SyslogTls::Header.new
72
+ h.hostname = "hostname"
73
+ assert_equal "<#{h.pri}>1 #{h.timestamp.to_datetime.rfc3339} hostname - - -", h.to_s
74
+ end
75
+
76
+ def test_header_appname
77
+ h = SyslogTls::Header.new
78
+ h.app_name = "appname"
79
+ assert_equal "<#{h.pri}>1 #{h.timestamp.to_datetime.rfc3339} - appname - -", h.to_s
80
+ end
81
+
82
+ def test_header_procid
83
+ h = SyslogTls::Header.new
84
+ h.procid = $$
85
+ assert_equal "<#{h.pri}>1 #{h.timestamp.to_datetime.rfc3339} - - #{$$} -", h.to_s
86
+ end
87
+
88
+ def test_header_msgid
89
+ h = SyslogTls::Header.new
90
+ h.msgid = "msgid"
91
+ assert_equal "<#{h.pri}>1 #{h.timestamp.to_datetime.rfc3339} - - - msgid", h.to_s
92
+ end
93
+
94
+ def test_structured_data_defaults
95
+ id = "hash@IANA-ID"
96
+ sd = SyslogTls::StructuredData.new(id)
97
+ assert_equal "[#{id}]", sd.to_s
98
+ end
99
+
100
+ def test_structured_data_key
101
+ id = "hash@IANA-ID"
102
+ sd = SyslogTls::StructuredData.new(id)
103
+ sd.data["key"] = "val"
104
+ assert_equal "[#{id} key=\"val\"]", sd.to_s
105
+ end
106
+
107
+ def test_structured_data_escaping
108
+ id = "hash@IANA-ID"
109
+ sd = SyslogTls::StructuredData.new(id)
110
+ sd.data["key"] = '\]"'
111
+ assert_equal "[#{id} key=\"\\\\\\]\\\"\"]", sd.to_s
112
+ end
113
+
114
+ def test_messsage_defaults
115
+ m = SyslogTls::Message.new
116
+ assert_not_nil m.header
117
+ assert_true m.structured_data.is_a? Array
118
+ assert_equal 0, m.structured_data.length
119
+ assert_equal "", m.msg
120
+
121
+ assert_equal "<134>1 #{m.header.timestamp.to_datetime.rfc3339} - - - - -\n", m.to_s
122
+ end
123
+
124
+ def test_message_msg
125
+ m = SyslogTls::Message.new
126
+ m.msg = "TEST"
127
+ assert_equal "<134>1 #{m.header.timestamp.to_datetime.rfc3339} - - - - - TEST\n", m.to_s
128
+ end
129
+
130
+ def test_message_sd
131
+ m = SyslogTls::Message.new
132
+ m.structured_data << SyslogTls::StructuredData.new("TEST_ID")
133
+ assert_equal "<134>1 #{m.header.timestamp.to_datetime.rfc3339} - - - - [TEST_ID]\n", m.to_s
134
+ end
135
+
136
+ def test_message_multiple_sd
137
+ m = SyslogTls::Message.new
138
+ m.structured_data << SyslogTls::StructuredData.new("TEST_ID")
139
+ m.structured_data << SyslogTls::StructuredData.new("TEST_ID2")
140
+ assert_equal "<134>1 #{m.header.timestamp.to_datetime.rfc3339} - - - - [TEST_ID][TEST_ID2]\n", m.to_s
141
+ end
142
+
143
+ def test_message_multiple_sd_msg
144
+ m = SyslogTls::Message.new
145
+ m.structured_data << SyslogTls::StructuredData.new("TEST_ID")
146
+ m.structured_data << SyslogTls::StructuredData.new("TEST_ID2")
147
+ m.msg = "MSG"
148
+ assert_equal "<134>1 #{m.header.timestamp.to_datetime.rfc3339} - - - - [TEST_ID][TEST_ID2] MSG\n", m.to_s
149
+ end
150
+ end