fluentd 0.14.11 → 0.14.12
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -5
- data/ChangeLog +54 -2
- data/example/in_dummy_blocks.conf +17 -0
- data/example/in_forward_tls.conf +14 -0
- data/example/in_forward_workers.conf +21 -0
- data/example/logevents.conf +25 -0
- data/example/out_forward_heartbeat_none.conf +16 -0
- data/example/out_forward_tls.conf +18 -0
- data/example/suppress_config_dump.conf +7 -0
- data/lib/fluent/agent.rb +3 -32
- data/lib/fluent/clock.rb +62 -0
- data/lib/fluent/command/fluentd.rb +12 -0
- data/lib/fluent/compat/input.rb +10 -1
- data/lib/fluent/compat/output.rb +40 -1
- data/lib/fluent/config/configure_proxy.rb +30 -7
- data/lib/fluent/config/section.rb +4 -0
- data/lib/fluent/config/types.rb +2 -2
- data/lib/fluent/configurable.rb +31 -5
- data/lib/fluent/engine.rb +61 -12
- data/lib/fluent/event_router.rb +6 -0
- data/lib/fluent/load.rb +0 -1
- data/lib/fluent/log.rb +118 -42
- data/lib/fluent/match.rb +37 -0
- data/lib/fluent/plugin.rb +25 -3
- data/lib/fluent/plugin/base.rb +4 -0
- data/lib/fluent/plugin/buf_file.rb +38 -14
- data/lib/fluent/plugin/buffer.rb +20 -20
- data/lib/fluent/plugin/buffer/file_chunk.rb +2 -2
- data/lib/fluent/plugin/compressable.rb +1 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +3 -6
- data/lib/fluent/plugin/formatter_csv.rb +4 -1
- data/lib/fluent/plugin/formatter_hash.rb +5 -1
- data/lib/fluent/plugin/formatter_json.rb +10 -0
- data/lib/fluent/plugin/formatter_ltsv.rb +2 -1
- data/lib/fluent/plugin/in_dummy.rb +4 -0
- data/lib/fluent/plugin/in_exec.rb +4 -0
- data/lib/fluent/plugin/in_forward.rb +11 -3
- data/lib/fluent/plugin/in_gc_stat.rb +4 -0
- data/lib/fluent/plugin/in_http.rb +4 -0
- data/lib/fluent/plugin/in_monitor_agent.rb +29 -2
- data/lib/fluent/plugin/in_object_space.rb +4 -1
- data/lib/fluent/plugin/in_syslog.rb +4 -0
- data/lib/fluent/plugin/in_tail.rb +193 -116
- data/lib/fluent/plugin/in_tcp.rb +5 -1
- data/lib/fluent/plugin/in_udp.rb +4 -0
- data/lib/fluent/plugin/input.rb +4 -0
- data/lib/fluent/plugin/out_copy.rb +4 -0
- data/lib/fluent/plugin/out_exec.rb +4 -0
- data/lib/fluent/plugin/out_exec_filter.rb +4 -0
- data/lib/fluent/plugin/out_file.rb +70 -30
- data/lib/fluent/plugin/out_forward.rb +132 -28
- data/lib/fluent/plugin/out_null.rb +10 -0
- data/lib/fluent/plugin/out_relabel.rb +4 -0
- data/lib/fluent/plugin/out_roundrobin.rb +4 -0
- data/lib/fluent/plugin/out_secondary_file.rb +5 -0
- data/lib/fluent/plugin/out_stdout.rb +5 -0
- data/lib/fluent/plugin/output.rb +18 -9
- data/lib/fluent/plugin/storage_local.rb +25 -2
- data/lib/fluent/plugin_helper/cert_option.rb +159 -0
- data/lib/fluent/plugin_helper/child_process.rb +6 -6
- data/lib/fluent/plugin_helper/compat_parameters.rb +1 -1
- data/lib/fluent/plugin_helper/event_loop.rb +29 -4
- data/lib/fluent/plugin_helper/inject.rb +14 -1
- data/lib/fluent/plugin_helper/server.rb +275 -31
- data/lib/fluent/plugin_helper/socket.rb +144 -4
- data/lib/fluent/plugin_helper/socket_option.rb +2 -17
- data/lib/fluent/plugin_helper/storage.rb +7 -1
- data/lib/fluent/plugin_helper/thread.rb +16 -4
- data/lib/fluent/registry.rb +26 -9
- data/lib/fluent/root_agent.rb +7 -3
- data/lib/fluent/supervisor.rb +37 -15
- data/lib/fluent/system_config.rb +37 -10
- data/lib/fluent/test.rb +2 -0
- data/lib/fluent/test/driver/base.rb +24 -26
- data/lib/fluent/test/helpers.rb +21 -0
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_fluentd.rb +274 -4
- data/test/config/test_configurable.rb +154 -0
- data/test/config/test_configure_proxy.rb +180 -1
- data/test/config/test_system_config.rb +10 -0
- data/test/config/test_types.rb +1 -0
- data/test/plugin/test_base.rb +4 -0
- data/test/plugin/test_buf_file.rb +241 -9
- data/test/plugin/test_buffer.rb +11 -11
- data/test/plugin/test_buffer_file_chunk.rb +6 -6
- data/test/plugin/test_compressable.rb +3 -0
- data/test/plugin/test_filter.rb +4 -0
- data/test/plugin/test_filter_record_transformer.rb +20 -0
- data/test/plugin/test_formatter_csv.rb +9 -0
- data/test/plugin/test_formatter_hash.rb +35 -0
- data/test/plugin/test_formatter_json.rb +8 -0
- data/test/plugin/test_formatter_ltsv.rb +7 -0
- data/test/plugin/test_in_dummy.rb +7 -3
- data/test/plugin/test_in_monitor_agent.rb +43 -5
- data/test/plugin/test_in_tail.rb +97 -4
- data/test/plugin/test_input.rb +4 -0
- data/test/plugin/test_out_file.rb +46 -7
- data/test/plugin/test_out_forward.rb +59 -7
- data/test/plugin/test_output.rb +10 -4
- data/test/plugin/test_output_as_buffered.rb +37 -25
- data/test/plugin/test_output_as_buffered_compress.rb +1 -1
- data/test/plugin/test_output_as_buffered_retries.rb +6 -6
- data/test/plugin/test_output_as_buffered_secondary.rb +91 -31
- data/test/plugin/test_storage_local.rb +40 -1
- data/test/plugin_helper/test_child_process.rb +29 -28
- data/test/plugin_helper/test_compat_parameters.rb +1 -1
- data/test/plugin_helper/test_inject.rb +27 -9
- data/test/plugin_helper/test_server.rb +822 -50
- data/test/plugin_helper/test_storage.rb +11 -0
- data/test/plugin_helper/test_timer.rb +1 -0
- data/test/test_clock.rb +164 -0
- data/test/test_log.rb +146 -15
- data/test/test_plugin.rb +251 -0
- data/test/test_supervisor.rb +65 -57
- data/test/test_test_drivers.rb +2 -2
- metadata +18 -7
- data/lib/fluent/process.rb +0 -504
- data/test/test_process.rb +0 -48
@@ -36,7 +36,7 @@ module Fluent
|
|
36
36
|
"retry_limit" => "retry_max_times",
|
37
37
|
"max_retry_wait" => "retry_max_interval",
|
38
38
|
"buffer_chunk_limit" => "chunk_limit_size",
|
39
|
-
"buffer_queue_limit" => "
|
39
|
+
"buffer_queue_limit" => "queue_limit_length",
|
40
40
|
"buffer_queue_full_action" => "overflow_action",
|
41
41
|
"flush_at_shutdown" => "flush_at_shutdown",
|
42
42
|
}
|
@@ -16,6 +16,7 @@
|
|
16
16
|
|
17
17
|
require 'cool.io'
|
18
18
|
require 'fluent/plugin_helper/thread'
|
19
|
+
require 'fluent/clock'
|
19
20
|
|
20
21
|
module Fluent
|
21
22
|
module PluginHelper
|
@@ -31,7 +32,6 @@ module Fluent
|
|
31
32
|
|
32
33
|
EVENT_LOOP_RUN_DEFAULT_TIMEOUT = 0.5
|
33
34
|
EVENT_LOOP_SHUTDOWN_TIMEOUT = 5
|
34
|
-
EVENT_LOOP_CLOCK_ID = Process::CLOCK_MONOTONIC_RAW rescue Process::CLOCK_MONOTONIC
|
35
35
|
|
36
36
|
attr_reader :_event_loop # for tests
|
37
37
|
|
@@ -48,7 +48,14 @@ module Fluent
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def event_loop_wait_until_stop
|
51
|
-
|
51
|
+
timeout_at = Fluent::Clock.now + EVENT_LOOP_SHUTDOWN_TIMEOUT
|
52
|
+
sleep(0.1) while event_loop_running? && Fluent::Clock.now < timeout_at
|
53
|
+
if @_event_loop_running
|
54
|
+
puts "terminating event_loop forcedly"
|
55
|
+
caller.each{|bt| puts "\t#{bt}" }
|
56
|
+
@_event_loop.stop rescue nil
|
57
|
+
@_event_loop_running = true
|
58
|
+
end
|
52
59
|
end
|
53
60
|
|
54
61
|
def event_loop_running?
|
@@ -85,13 +92,31 @@ module Fluent
|
|
85
92
|
@_event_loop_mutex.synchronize do
|
86
93
|
@_event_loop_attached_watchers.reverse.each do |w|
|
87
94
|
if w.attached?
|
95
|
+
begin
|
96
|
+
w.detach
|
97
|
+
rescue => e
|
98
|
+
log.warn "unexpected error while detaching event loop watcher", error: e
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
super
|
105
|
+
end
|
106
|
+
|
107
|
+
def after_shutdown
|
108
|
+
timeout_at = Fluent::Clock.now + EVENT_LOOP_SHUTDOWN_TIMEOUT
|
109
|
+
@_event_loop_mutex.synchronize do
|
110
|
+
@_event_loop.watchers.reverse.each do |w|
|
111
|
+
begin
|
88
112
|
w.detach
|
113
|
+
rescue => e
|
114
|
+
log.warn "unexpected error while detaching event loop watcher", error: e
|
89
115
|
end
|
90
116
|
end
|
91
117
|
end
|
92
|
-
timeout_at = Process.clock_gettime(EVENT_LOOP_CLOCK_ID) + EVENT_LOOP_SHUTDOWN_TIMEOUT
|
93
118
|
while @_event_loop_running
|
94
|
-
if
|
119
|
+
if Fluent::Clock.now >= timeout_at
|
95
120
|
log.warn "event loop does NOT exit until hard timeout."
|
96
121
|
raise "event loop does NOT exit until hard timeout." if @under_plugin_development
|
97
122
|
break
|
@@ -29,6 +29,9 @@ module Fluent
|
|
29
29
|
if @_inject_hostname_key
|
30
30
|
r[@_inject_hostname_key] = @_inject_hostname
|
31
31
|
end
|
32
|
+
if @_inject_worker_id_key
|
33
|
+
r[@_inject_worker_id_key] = @_inject_worker_id
|
34
|
+
end
|
32
35
|
if @_inject_tag_key
|
33
36
|
r[@_inject_tag_key] = tag
|
34
37
|
end
|
@@ -48,6 +51,9 @@ module Fluent
|
|
48
51
|
if @_inject_hostname_key
|
49
52
|
r[@_inject_hostname_key] = @_inject_hostname
|
50
53
|
end
|
54
|
+
if @_inject_worker_id_key
|
55
|
+
r[@_inject_worker_id_key] = @_inject_worker_id
|
56
|
+
end
|
51
57
|
if @_inject_tag_key
|
52
58
|
r[@_inject_tag_key] = tag
|
53
59
|
end
|
@@ -65,6 +71,7 @@ module Fluent
|
|
65
71
|
config_section :inject, required: false, multi: false, param_name: :inject_config do
|
66
72
|
config_param :hostname_key, :string, default: nil
|
67
73
|
config_param :hostname, :string, default: nil
|
74
|
+
config_param :worker_id_key, :string, default: nil
|
68
75
|
config_param :tag_key, :string, default: nil
|
69
76
|
config_param :time_key, :string, default: nil
|
70
77
|
|
@@ -86,6 +93,8 @@ module Fluent
|
|
86
93
|
@_inject_enabled = false
|
87
94
|
@_inject_hostname_key = nil
|
88
95
|
@_inject_hostname = nil
|
96
|
+
@_inject_worker_id_key = nil
|
97
|
+
@_inject_worker_id = nil
|
89
98
|
@_inject_tag_key = nil
|
90
99
|
@_inject_time_key = nil
|
91
100
|
@_inject_time_formatter = nil
|
@@ -114,6 +123,10 @@ module Fluent
|
|
114
123
|
log.info "using hostname for specified field", host_key: @_inject_hostname_key, host_name: @_inject_hostname
|
115
124
|
end
|
116
125
|
end
|
126
|
+
@_inject_worker_id_key = @inject_config.worker_id_key
|
127
|
+
if @_inject_worker_id_key
|
128
|
+
@_inject_worker_id = fluentd_worker_id # get id here, because #with_worker_config method may be used only for #configure in tests
|
129
|
+
end
|
117
130
|
@_inject_tag_key = @inject_config.tag_key
|
118
131
|
@_inject_time_key = @inject_config.time_key
|
119
132
|
if @_inject_time_key
|
@@ -130,7 +143,7 @@ module Fluent
|
|
130
143
|
end
|
131
144
|
end
|
132
145
|
|
133
|
-
@_inject_enabled = @_inject_hostname_key || @_inject_tag_key || @_inject_time_key
|
146
|
+
@_inject_enabled = @_inject_hostname_key || @_inject_worker_id_key || @_inject_tag_key || @_inject_time_key
|
134
147
|
end
|
135
148
|
end
|
136
149
|
end
|
@@ -21,18 +21,22 @@ require 'cool.io'
|
|
21
21
|
require 'socket'
|
22
22
|
require 'ipaddr'
|
23
23
|
require 'fcntl'
|
24
|
+
require 'openssl'
|
24
25
|
|
25
26
|
require_relative 'socket_option'
|
27
|
+
require_relative 'cert_option'
|
26
28
|
|
27
29
|
module Fluent
|
28
30
|
module PluginHelper
|
29
31
|
module Server
|
30
32
|
include Fluent::PluginHelper::EventLoop
|
31
33
|
include Fluent::PluginHelper::SocketOption
|
34
|
+
include Fluent::PluginHelper::CertOption
|
32
35
|
|
33
36
|
# This plugin helper doesn't support these things for now:
|
34
|
-
# * SSL/TLS (TBD)
|
35
37
|
# * TCP/TLS keepalive
|
38
|
+
# * TLS session cache/tickets
|
39
|
+
# * unix domain sockets
|
36
40
|
|
37
41
|
# stop : [-]
|
38
42
|
# shutdown : detach server event handler from event loop (event_loop)
|
@@ -63,12 +67,16 @@ module Fluent
|
|
63
67
|
# conn.close
|
64
68
|
# end
|
65
69
|
# end
|
66
|
-
def server_create_connection(title, port, proto:
|
70
|
+
def server_create_connection(title, port, proto: nil, bind: '0.0.0.0', shared: true, backlog: nil, tls_options: nil, **socket_options, &block)
|
71
|
+
proto ||= (@transport_config && @transport_config.protocol == :tls) ? :tls : :tcp
|
72
|
+
|
67
73
|
raise ArgumentError, "BUG: title must be a symbol" unless title && title.is_a?(Symbol)
|
68
74
|
raise ArgumentError, "BUG: port must be an integer" unless port && port.is_a?(Integer)
|
69
75
|
raise ArgumentError, "BUG: invalid protocol name" unless PROTOCOLS.include?(proto)
|
70
76
|
raise ArgumentError, "BUG: cannot create connection for UDP" unless CONNECTION_PROTOCOLS.include?(proto)
|
71
77
|
|
78
|
+
raise ArgumentError, "BUG: tls_options is available only for tls" if tls_options && proto != :tls
|
79
|
+
|
72
80
|
raise ArgumentError, "BUG: block not specified which handles connection" unless block_given?
|
73
81
|
raise ArgumentError, "BUG: block must have just one argument" unless block.arity == 1
|
74
82
|
|
@@ -83,11 +91,14 @@ module Fluent
|
|
83
91
|
when :tcp
|
84
92
|
server = server_create_for_tcp_connection(shared, bind, port, backlog, socket_option_setter, &block)
|
85
93
|
when :tls
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
94
|
+
transport_config = if tls_options
|
95
|
+
server_create_transport_section_object(tls_options)
|
96
|
+
elsif @transport_config && @transport_config.protocol == :tls
|
97
|
+
@transport_config
|
98
|
+
else
|
99
|
+
raise ArgumentError, "BUG: TLS transport specified, but certification options are not specified"
|
100
|
+
end
|
101
|
+
server = server_create_for_tls_connection(shared, bind, port, transport_config, backlog, socket_option_setter, &block)
|
91
102
|
when :unix
|
92
103
|
raise "not implemented yet"
|
93
104
|
else
|
@@ -108,12 +119,15 @@ module Fluent
|
|
108
119
|
# sock.remote_port
|
109
120
|
# # ...
|
110
121
|
# end
|
111
|
-
def server_create(title, port, proto:
|
122
|
+
def server_create(title, port, proto: nil, bind: '0.0.0.0', shared: true, socket: nil, backlog: nil, tls_options: nil, max_bytes: nil, flags: 0, **socket_options, &callback)
|
123
|
+
proto ||= (@transport_config && @transport_config.protocol == :tls) ? :tls : :tcp
|
124
|
+
|
112
125
|
raise ArgumentError, "BUG: title must be a symbol" unless title && title.is_a?(Symbol)
|
113
126
|
raise ArgumentError, "BUG: port must be an integer" unless port && port.is_a?(Integer)
|
114
127
|
raise ArgumentError, "BUG: invalid protocol name" unless PROTOCOLS.include?(proto)
|
115
128
|
|
116
129
|
raise ArgumentError, "BUG: socket option is available only for udp" if socket && proto != :udp
|
130
|
+
raise ArgumentError, "BUG: tls_options is available only for tls" if tls_options && proto != :tls
|
117
131
|
|
118
132
|
raise ArgumentError, "BUG: block not specified which handles received data" unless block_given?
|
119
133
|
raise ArgumentError, "BUG: block must have 1 or 2 arguments" unless callback.arity == 1 || callback.arity == 2
|
@@ -141,7 +155,16 @@ module Fluent
|
|
141
155
|
conn.data(&callback)
|
142
156
|
end
|
143
157
|
when :tls
|
144
|
-
|
158
|
+
transport_config = if tls_options
|
159
|
+
server_create_transport_section_object(tls_options)
|
160
|
+
elsif @transport_config && @transport_config.protocol == :tls
|
161
|
+
@transport_config
|
162
|
+
else
|
163
|
+
raise ArgumentError, "BUG: TLS transport specified, but certification options are not specified"
|
164
|
+
end
|
165
|
+
server = server_create_for_tls_connection(shared, bind, port, transport_config, backlog, socket_option_setter) do |conn|
|
166
|
+
conn.data(&callback)
|
167
|
+
end
|
145
168
|
when :udp
|
146
169
|
raise ArgumentError, "BUG: max_bytes must be specified for UDP" unless max_bytes
|
147
170
|
if socket
|
@@ -198,6 +221,80 @@ module Fluent
|
|
198
221
|
server
|
199
222
|
end
|
200
223
|
|
224
|
+
def server_create_for_tls_connection(shared, bind, port, conf, backlog, socket_option_setter, &block)
|
225
|
+
context = cert_option_create_context(conf.version, conf.insecure, conf.ciphers, conf)
|
226
|
+
sock = server_create_tcp_socket(shared, bind, port)
|
227
|
+
socket_option_setter.call(sock)
|
228
|
+
close_callback = ->(conn){ @_server_mutex.synchronize{ @_server_connections.delete(conn) } }
|
229
|
+
server = Coolio::TCPServer.new(sock, nil, EventHandler::TLSServer, context, socket_option_setter, close_callback, @log, @under_plugin_development, block) do |conn|
|
230
|
+
@_server_mutex.synchronize do
|
231
|
+
@_server_connections << conn
|
232
|
+
end
|
233
|
+
end
|
234
|
+
server.listen(backlog) if backlog
|
235
|
+
server
|
236
|
+
end
|
237
|
+
|
238
|
+
SERVER_TRANSPORT_PARAMS = [
|
239
|
+
:protocol, :version, :ciphers, :insecure,
|
240
|
+
:cert_path, :private_key_path, :private_key_passphrase,
|
241
|
+
:ca_cert_path, :ca_private_key_path, :ca_private_key_passphrase,
|
242
|
+
:generate_private_key_length,
|
243
|
+
:generate_cert_country, :generate_cert_state, :generate_cert_state,
|
244
|
+
:generate_cert_locality, :generate_cert_common_name,
|
245
|
+
:generate_cert_expiration, :generate_cert_digest,
|
246
|
+
]
|
247
|
+
|
248
|
+
def server_create_transport_section_object(opts)
|
249
|
+
transport_section = configured_section_create(:transport)
|
250
|
+
SERVER_TRANSPORT_PARAMS.each do |param|
|
251
|
+
if opts.has_key?(param)
|
252
|
+
transport_section[param] = opts[param]
|
253
|
+
end
|
254
|
+
end
|
255
|
+
transport_section
|
256
|
+
end
|
257
|
+
|
258
|
+
module ServerTransportParams
|
259
|
+
TLS_DEFAULT_VERSION = :'TLSv1_2'
|
260
|
+
TLS_SUPPORTED_VERSIONS = [:'TLSv1_1', :'TLSv1_2']
|
261
|
+
### follow httpclient configuration by nahi
|
262
|
+
# OpenSSL 0.9.8 default: "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
|
263
|
+
CIPHERS_DEFAULT = "ALL:!aNULL:!eNULL:!SSLv2" # OpenSSL >1.0.0 default
|
264
|
+
|
265
|
+
include Fluent::Configurable
|
266
|
+
config_section :transport, required: false, multi: false, init: true, param_name: :transport_config do
|
267
|
+
config_argument :protocol, :enum, list: [:tcp, :tls], default: :tcp
|
268
|
+
config_param :version, :enum, list: TLS_SUPPORTED_VERSIONS, default: TLS_DEFAULT_VERSION
|
269
|
+
|
270
|
+
config_param :ciphers, :string, default: CIPHERS_DEFAULT
|
271
|
+
config_param :insecure, :bool, default: false
|
272
|
+
|
273
|
+
# Cert signed by public CA
|
274
|
+
config_param :cert_path, :string, default: nil
|
275
|
+
config_param :private_key_path, :string, default: nil
|
276
|
+
config_param :private_key_passphrase, :string, default: nil, secret: true
|
277
|
+
|
278
|
+
# Cert generated and signed by private CA Certificate
|
279
|
+
config_param :ca_cert_path, :string, default: nil
|
280
|
+
config_param :ca_private_key_path, :string, default: nil
|
281
|
+
config_param :ca_private_key_passphrase, :string, default: nil, secret: true
|
282
|
+
|
283
|
+
# Options for generating certs by private CA certs or self-signed
|
284
|
+
config_param :generate_private_key_length, :integer, default: 2048
|
285
|
+
config_param :generate_cert_country, :string, default: 'US'
|
286
|
+
config_param :generate_cert_state, :string, default: 'CA'
|
287
|
+
config_param :generate_cert_locality, :string, default: 'Mountain View'
|
288
|
+
config_param :generate_cert_common_name, :string, default: nil
|
289
|
+
config_param :generate_cert_expiration, :time, default: 10 * 365 * 86400 # 10years later
|
290
|
+
config_param :generate_cert_digest, :enum, list: [:sha1, :sha256, :sha384, :sha512], default: :sha256
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def self.included(mod)
|
295
|
+
mod.include ServerTransportParams
|
296
|
+
end
|
297
|
+
|
201
298
|
def initialize
|
202
299
|
super
|
203
300
|
@_servers = []
|
@@ -205,28 +302,33 @@ module Fluent
|
|
205
302
|
@_server_mutex = Mutex.new
|
206
303
|
end
|
207
304
|
|
208
|
-
def
|
209
|
-
|
210
|
-
|
305
|
+
def configure(conf)
|
306
|
+
super
|
307
|
+
|
308
|
+
if @transport_config
|
309
|
+
if @transport_config.protocol == :tls
|
310
|
+
cert_option_server_validate!(@transport_config)
|
311
|
+
end
|
211
312
|
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def stop
|
212
316
|
@_server_mutex.synchronize do
|
213
317
|
@_servers.each do |si|
|
214
318
|
si.server.detach if si.server.attached?
|
319
|
+
# to refuse more connections: (connected sockets are still alive here)
|
320
|
+
si.server.close rescue nil
|
215
321
|
end
|
216
322
|
end
|
217
323
|
|
218
324
|
super
|
219
325
|
end
|
220
326
|
|
221
|
-
def
|
327
|
+
def shutdown
|
222
328
|
@_server_connections.each do |conn|
|
223
329
|
conn.close rescue nil
|
224
330
|
end
|
225
|
-
|
226
|
-
@_servers.each do |si|
|
227
|
-
si.server.close rescue nil
|
228
|
-
end
|
229
|
-
end
|
331
|
+
|
230
332
|
super
|
231
333
|
end
|
232
334
|
|
@@ -235,10 +337,6 @@ module Fluent
|
|
235
337
|
super
|
236
338
|
end
|
237
339
|
|
238
|
-
def server_certopts_validate!(certopts)
|
239
|
-
raise "not implemented yet"
|
240
|
-
end
|
241
|
-
|
242
340
|
def server_socket_manager_client
|
243
341
|
socket_manager_path = ENV['SERVERENGINE_SOCKETMANAGER_PATH']
|
244
342
|
if Fluent.windows?
|
@@ -272,28 +370,25 @@ module Fluent
|
|
272
370
|
sock
|
273
371
|
end
|
274
372
|
|
275
|
-
def server_create_tls_socket(shared, bind, port)
|
276
|
-
raise "not implemented yet"
|
277
|
-
end
|
278
|
-
|
279
373
|
class CallbackSocket
|
280
374
|
def initialize(server_type, sock, enabled_events = [], close_socket: true)
|
281
375
|
@server_type = server_type
|
282
376
|
@sock = sock
|
377
|
+
@peeraddr = nil
|
283
378
|
@enabled_events = enabled_events
|
284
379
|
@close_socket = close_socket
|
285
380
|
end
|
286
381
|
|
287
382
|
def remote_addr
|
288
|
-
@
|
383
|
+
@peeraddr[3]
|
289
384
|
end
|
290
385
|
|
291
386
|
def remote_host
|
292
|
-
@
|
387
|
+
@peeraddr[2]
|
293
388
|
end
|
294
389
|
|
295
390
|
def remote_port
|
296
|
-
@
|
391
|
+
@peeraddr[1]
|
297
392
|
end
|
298
393
|
|
299
394
|
def send(data, flags = 0)
|
@@ -332,6 +427,18 @@ module Fluent
|
|
332
427
|
class TCPCallbackSocket < CallbackSocket
|
333
428
|
def initialize(sock)
|
334
429
|
super("tcp", sock, [:data, :write_complete, :close])
|
430
|
+
@peeraddr = @sock.peeraddr
|
431
|
+
end
|
432
|
+
|
433
|
+
def write(data)
|
434
|
+
@sock.write(data)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
class TLSCallbackSocket < CallbackSocket
|
439
|
+
def initialize(sock)
|
440
|
+
super("tls", sock, [:data, :write_complete, :close])
|
441
|
+
@peeraddr = @sock.to_io.peeraddr
|
335
442
|
end
|
336
443
|
|
337
444
|
def write(data)
|
@@ -435,6 +542,10 @@ module Fluent
|
|
435
542
|
@mutex = Mutex.new # to serialize #write and #close
|
436
543
|
end
|
437
544
|
|
545
|
+
def to_io
|
546
|
+
@_handler_socket
|
547
|
+
end
|
548
|
+
|
438
549
|
def data(&callback)
|
439
550
|
raise "data callback can be registered just once, but registered twice" if self.singleton_methods.include?(:on_read)
|
440
551
|
@data_callback = callback
|
@@ -464,7 +575,140 @@ module Fluent
|
|
464
575
|
def on_read_without_connection(data)
|
465
576
|
@data_callback.call(data)
|
466
577
|
rescue => e
|
467
|
-
@log.error "unexpected error on reading data", host: remote_host, port: remote_port, error: e
|
578
|
+
@log.error "unexpected error on reading data", host: @callback_connection.remote_host, port: @callback_connection.remote_port, error: e
|
579
|
+
@log.error_backtrace
|
580
|
+
close(true) rescue nil
|
581
|
+
raise if @under_plugin_development
|
582
|
+
end
|
583
|
+
|
584
|
+
def on_read_with_connection(data)
|
585
|
+
@data_callback.call(data, @callback_connection)
|
586
|
+
rescue => e
|
587
|
+
@log.error "unexpected error on reading data", host: @callback_connection.remote_host, port: @callback_connection.remote_port, error: e
|
588
|
+
@log.error_backtrace
|
589
|
+
close(true) rescue nil
|
590
|
+
raise if @under_plugin_development
|
591
|
+
end
|
592
|
+
|
593
|
+
def close
|
594
|
+
@mutex.synchronize do
|
595
|
+
return if @closing
|
596
|
+
@closing = true
|
597
|
+
@close_callback.call(self)
|
598
|
+
super
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
class TLSServer < Coolio::Socket
|
604
|
+
# It can't use Coolio::TCPSocket, because Coolio::TCPSocket checks that underlying socket (1st argument of super) is TCPSocket.
|
605
|
+
def initialize(sock, context, socket_option_setter, close_callback, log, under_plugin_development, connect_callback)
|
606
|
+
raise ArgumentError, "socket must be a TCPSocket: sock=#{sock}" unless sock.is_a?(TCPSocket)
|
607
|
+
|
608
|
+
socket_option_setter.call(sock)
|
609
|
+
@_handler_socket = OpenSSL::SSL::SSLSocket.new(sock, context)
|
610
|
+
@_handler_socket.sync_close = true
|
611
|
+
@_handler_write_buffer = ''.force_encoding('ascii-8bit')
|
612
|
+
@_handler_accepted = false
|
613
|
+
super(@_handler_socket)
|
614
|
+
|
615
|
+
@log = log
|
616
|
+
@under_plugin_development = under_plugin_development
|
617
|
+
|
618
|
+
@connect_callback = connect_callback
|
619
|
+
@data_callback = nil
|
620
|
+
@close_callback = close_callback
|
621
|
+
|
622
|
+
@callback_connection = nil
|
623
|
+
@closing = false
|
624
|
+
|
625
|
+
@mutex = Mutex.new # to serialize #write and #close
|
626
|
+
end
|
627
|
+
|
628
|
+
def to_io
|
629
|
+
@_handler_socket.to_io
|
630
|
+
end
|
631
|
+
|
632
|
+
def data(&callback)
|
633
|
+
raise "data callback can be registered just once, but registered twice" if self.singleton_methods.include?(:on_read)
|
634
|
+
@data_callback = callback
|
635
|
+
on_read_impl = case callback.arity
|
636
|
+
when 1 then :on_read_without_connection
|
637
|
+
when 2 then :on_read_with_connection
|
638
|
+
else
|
639
|
+
raise "BUG: callback block must have 1 or 2 arguments"
|
640
|
+
end
|
641
|
+
self.define_singleton_method(:on_read, method(on_read_impl))
|
642
|
+
end
|
643
|
+
|
644
|
+
def write(data)
|
645
|
+
@mutex.synchronize do
|
646
|
+
@_handler_write_buffer << data
|
647
|
+
schedule_write
|
648
|
+
data.bytesize
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
def try_tls_accept
|
653
|
+
return true if @_handler_accepted
|
654
|
+
|
655
|
+
begin
|
656
|
+
@_handler_socket.accept_nonblock # this method call actually try to do handshake via TLS
|
657
|
+
@_handler_accepted = true
|
658
|
+
|
659
|
+
@callback_connection = TLSCallbackSocket.new(self)
|
660
|
+
@connect_callback.call(@callback_connection)
|
661
|
+
unless @data_callback
|
662
|
+
raise "connection callback must call #data to set data callback"
|
663
|
+
end
|
664
|
+
return true
|
665
|
+
|
666
|
+
rescue IO::WaitReadable, IO::WaitWritable
|
667
|
+
# retry accept_nonblock: there aren't enough data in underlying socket buffer
|
668
|
+
rescue OpenSSL::SSL::SSLError => e
|
669
|
+
@log.trace "unexpected error before accepting TLS connection", error: e
|
670
|
+
close rescue nil
|
671
|
+
end
|
672
|
+
|
673
|
+
false
|
674
|
+
end
|
675
|
+
|
676
|
+
def on_connect
|
677
|
+
try_tls_accept
|
678
|
+
end
|
679
|
+
|
680
|
+
def on_readable
|
681
|
+
if try_tls_accept
|
682
|
+
super
|
683
|
+
end
|
684
|
+
rescue IO::WaitReadable, IO::WaitWritable
|
685
|
+
# ignore and return with doing nothing
|
686
|
+
end
|
687
|
+
|
688
|
+
def on_writable
|
689
|
+
begin
|
690
|
+
@mutex.synchronize do
|
691
|
+
written_bytes = @_handler_socket.write_nonblock(@_handler_write_buffer)
|
692
|
+
@_handler_write_buffer.slice!(0, written_bytes)
|
693
|
+
super
|
694
|
+
end
|
695
|
+
rescue IO::WaitWritable, IO::WaitReadable
|
696
|
+
return
|
697
|
+
rescue Errno::EINTR
|
698
|
+
return
|
699
|
+
rescue SystemCallError, IOError, SocketError
|
700
|
+
# SystemCallError catches Errno::EPIPE & Errno::ECONNRESET amongst others.
|
701
|
+
close rescue nil
|
702
|
+
return
|
703
|
+
rescue OpenSSL::SSL::SSLError => e
|
704
|
+
@log.debug "unexpected SSLError while writing data into socket connected via TLS", error: e
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
def on_read_without_connection(data)
|
709
|
+
@data_callback.call(data)
|
710
|
+
rescue => e
|
711
|
+
@log.error "unexpected error on reading data", host: @callback_connection.remote_host, port: @callback_connection.remote_port, error: e
|
468
712
|
@log.error_backtrace
|
469
713
|
close(true) rescue nil
|
470
714
|
raise if @under_plugin_development
|
@@ -473,7 +717,7 @@ module Fluent
|
|
473
717
|
def on_read_with_connection(data)
|
474
718
|
@data_callback.call(data, @callback_connection)
|
475
719
|
rescue => e
|
476
|
-
@log.error "unexpected error on reading data", host: remote_host, port: remote_port, error: e
|
720
|
+
@log.error "unexpected error on reading data", host: @callback_connection.remote_host, port: @callback_connection.remote_port, error: e
|
477
721
|
@log.error_backtrace
|
478
722
|
close(true) rescue nil
|
479
723
|
raise if @under_plugin_development
|