racecar 0.5.0.beta2 → 2.2.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.
- checksums.yaml +5 -5
- data/.circleci/config.yml +56 -0
- data/.github/workflows/ci.yml +61 -0
- data/.gitignore +0 -1
- data/CHANGELOG.md +48 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +69 -0
- data/README.md +56 -59
- data/Rakefile +2 -0
- data/docker-compose.yml +32 -0
- data/examples/batch_consumer.rb +2 -0
- data/examples/cat_consumer.rb +2 -0
- data/examples/producing_consumer.rb +2 -0
- data/exe/racecar +36 -13
- data/lib/ensure_hash_compact.rb +12 -0
- data/lib/generators/racecar/consumer_generator.rb +2 -0
- data/lib/generators/racecar/install_generator.rb +2 -0
- data/lib/racecar.rb +20 -14
- data/lib/racecar/cli.rb +25 -22
- data/lib/racecar/config.rb +109 -45
- data/lib/racecar/consumer.rb +52 -11
- data/lib/racecar/consumer_set.rb +239 -0
- data/lib/racecar/ctl.rb +8 -8
- data/lib/racecar/daemon.rb +2 -0
- data/lib/racecar/datadog.rb +247 -0
- data/lib/racecar/instrumenter.rb +28 -0
- data/lib/racecar/message.rb +30 -0
- data/lib/racecar/null_instrumenter.rb +10 -0
- data/lib/racecar/pause.rb +59 -0
- data/lib/racecar/rails_config_file_loader.rb +2 -0
- data/lib/racecar/runner.rb +222 -113
- data/lib/racecar/version.rb +3 -1
- data/racecar.gemspec +7 -3
- metadata +91 -13
data/Rakefile
CHANGED
data/docker-compose.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
version: '2'
|
2
|
+
services:
|
3
|
+
zookeeper:
|
4
|
+
image: confluentinc/cp-zookeeper:5.5.1
|
5
|
+
hostname: zookeeper
|
6
|
+
container_name: zookeeper
|
7
|
+
ports:
|
8
|
+
- "2181:2181"
|
9
|
+
environment:
|
10
|
+
ZOOKEEPER_CLIENT_PORT: 2181
|
11
|
+
ZOOKEEPER_TICK_TIME: 2000
|
12
|
+
|
13
|
+
broker:
|
14
|
+
image: confluentinc/cp-kafka:5.5.1
|
15
|
+
hostname: broker
|
16
|
+
container_name: broker
|
17
|
+
depends_on:
|
18
|
+
- zookeeper
|
19
|
+
ports:
|
20
|
+
- "29092:29092"
|
21
|
+
- "9092:9092"
|
22
|
+
- "9101:9101"
|
23
|
+
environment:
|
24
|
+
KAFKA_BROKER_ID: 1
|
25
|
+
KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
|
26
|
+
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
|
27
|
+
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://localhost:9092
|
28
|
+
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
29
|
+
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
|
30
|
+
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
|
31
|
+
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
|
32
|
+
KAFKA_JMX_PORT: 9101
|
data/examples/batch_consumer.rb
CHANGED
data/examples/cat_consumer.rb
CHANGED
data/exe/racecar
CHANGED
@@ -3,19 +3,42 @@
|
|
3
3
|
require "racecar"
|
4
4
|
require "racecar/cli"
|
5
5
|
|
6
|
-
|
6
|
+
module Racecar
|
7
|
+
class << self
|
8
|
+
def start(argv)
|
9
|
+
Cli.main(argv)
|
10
|
+
rescue SignalException => e
|
11
|
+
# We might receive SIGTERM before our signal handler is installed.
|
12
|
+
if Signal.signame(e.signo) == "TERM"
|
13
|
+
exit(0)
|
14
|
+
else
|
15
|
+
raise
|
16
|
+
end
|
17
|
+
rescue SystemExit
|
18
|
+
raise
|
19
|
+
rescue Exception => e
|
20
|
+
$stderr.puts "=> Crashed: #{exception_with_causes(e)}\n#{e.backtrace.join("\n")}"
|
7
21
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
22
|
+
Racecar.config.error_handler.call(e)
|
23
|
+
|
24
|
+
exit(1)
|
25
|
+
else
|
26
|
+
exit(0)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def exception_with_causes(e)
|
32
|
+
result = +"#{e.class}: #{e}"
|
33
|
+
if e.cause
|
34
|
+
result << "\n"
|
35
|
+
result << "--- Caused by: ---\n"
|
36
|
+
result << exception_with_causes(e.cause)
|
37
|
+
end
|
38
|
+
result
|
39
|
+
end
|
16
40
|
end
|
17
|
-
rescue
|
18
|
-
exit(1)
|
19
|
-
else
|
20
|
-
exit(0)
|
21
41
|
end
|
42
|
+
|
43
|
+
# Start your engines!
|
44
|
+
Racecar.start(ARGV)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# only needed when ruby < 2.4 and not using active support
|
4
|
+
|
5
|
+
unless {}.respond_to? :compact
|
6
|
+
# https://github.com/rails/rails/blob/fc5dd0b85189811062c85520fd70de8389b55aeb/activesupport/lib/active_support/core_ext/hash/compact.rb
|
7
|
+
class Hash
|
8
|
+
def compact
|
9
|
+
select { |_, value| !value.nil? }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/racecar.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "logger"
|
2
4
|
|
5
|
+
require "racecar/instrumenter"
|
6
|
+
require "racecar/null_instrumenter"
|
3
7
|
require "racecar/consumer"
|
8
|
+
require "racecar/consumer_set"
|
4
9
|
require "racecar/runner"
|
5
10
|
require "racecar/config"
|
11
|
+
require "racecar/version"
|
12
|
+
require "ensure_hash_compact"
|
6
13
|
|
7
14
|
module Racecar
|
8
|
-
# Ignores all instrumentation events.
|
9
|
-
class NullInstrumenter
|
10
|
-
def self.instrument(*)
|
11
|
-
yield if block_given?
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
15
|
class Error < StandardError
|
16
16
|
end
|
17
17
|
|
@@ -22,6 +22,10 @@ module Racecar
|
|
22
22
|
@config ||= Config.new
|
23
23
|
end
|
24
24
|
|
25
|
+
def self.config=(config)
|
26
|
+
@config = config
|
27
|
+
end
|
28
|
+
|
25
29
|
def self.configure
|
26
30
|
yield config
|
27
31
|
end
|
@@ -35,13 +39,15 @@ module Racecar
|
|
35
39
|
end
|
36
40
|
|
37
41
|
def self.instrumenter
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
@instrumenter ||= begin
|
43
|
+
default_payload = { client_id: config.client_id, group_id: config.group_id }
|
44
|
+
|
45
|
+
Instrumenter.new(default_payload).tap do |instrumenter|
|
46
|
+
if instrumenter.backend == NullInstrumenter
|
47
|
+
logger.warn "ActiveSupport::Notifications not available, instrumentation is disabled"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
45
51
|
end
|
46
52
|
|
47
53
|
def self.run(processor)
|
data/lib/racecar/cli.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "optparse"
|
2
4
|
require "logger"
|
3
5
|
require "fileutils"
|
@@ -6,8 +8,10 @@ require "racecar/daemon"
|
|
6
8
|
|
7
9
|
module Racecar
|
8
10
|
class Cli
|
9
|
-
|
10
|
-
|
11
|
+
class << self
|
12
|
+
def main(args)
|
13
|
+
new(args).run
|
14
|
+
end
|
11
15
|
end
|
12
16
|
|
13
17
|
def initialize(args)
|
@@ -16,17 +20,13 @@ module Racecar
|
|
16
20
|
@consumer_name = args.first or raise Racecar::Error, "no consumer specified"
|
17
21
|
end
|
18
22
|
|
19
|
-
def config
|
20
|
-
Racecar.config
|
21
|
-
end
|
22
|
-
|
23
23
|
def run
|
24
24
|
$stderr.puts "=> Starting Racecar consumer #{consumer_name}..."
|
25
25
|
|
26
|
-
RailsConfigFileLoader.load!
|
26
|
+
RailsConfigFileLoader.load! unless config.without_rails?
|
27
27
|
|
28
28
|
if File.exist?("config/racecar.rb")
|
29
|
-
require "config/racecar"
|
29
|
+
require "./config/racecar"
|
30
30
|
end
|
31
31
|
|
32
32
|
# Find the consumer class by name.
|
@@ -61,18 +61,16 @@ module Racecar
|
|
61
61
|
processor = consumer_class.new
|
62
62
|
|
63
63
|
Racecar.run(processor)
|
64
|
-
rescue => e
|
65
|
-
$stderr.puts "=> Crashed: #{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
66
|
-
|
67
|
-
config.error_handler.call(e)
|
68
|
-
|
69
|
-
raise
|
70
64
|
end
|
71
65
|
|
72
66
|
private
|
73
67
|
|
74
68
|
attr_reader :consumer_name
|
75
69
|
|
70
|
+
def config
|
71
|
+
Racecar.config
|
72
|
+
end
|
73
|
+
|
76
74
|
def daemonize!
|
77
75
|
daemon = Daemon.new(File.expand_path(config.pidfile))
|
78
76
|
|
@@ -94,10 +92,14 @@ module Racecar
|
|
94
92
|
end
|
95
93
|
|
96
94
|
def build_parser
|
95
|
+
load_path_modified = false
|
96
|
+
|
97
97
|
OptionParser.new do |opts|
|
98
98
|
opts.banner = "Usage: racecar MyConsumer [options]"
|
99
99
|
|
100
100
|
opts.on("-r", "--require STRING", "Require a library before starting the consumer") do |lib|
|
101
|
+
$LOAD_PATH.unshift(Dir.pwd) unless load_path_modified
|
102
|
+
load_path_modified = true
|
101
103
|
require lib
|
102
104
|
end
|
103
105
|
|
@@ -106,13 +108,13 @@ module Racecar
|
|
106
108
|
end
|
107
109
|
|
108
110
|
Racecar::Config.variables.each do |variable|
|
109
|
-
opt_name = "
|
111
|
+
opt_name = +"--#{variable.name.to_s.gsub('_', '-')}"
|
110
112
|
opt_name << " #{variable.type.upcase}" unless variable.boolean?
|
111
113
|
|
112
114
|
desc = variable.description || "N/A"
|
113
115
|
|
114
116
|
if variable.default
|
115
|
-
desc
|
117
|
+
desc += " (default: #{variable.default.inspect})"
|
116
118
|
end
|
117
119
|
|
118
120
|
opts.on(opt_name, desc) do |value|
|
@@ -140,13 +142,14 @@ module Racecar
|
|
140
142
|
end
|
141
143
|
|
142
144
|
def configure_datadog
|
143
|
-
|
145
|
+
require_relative './datadog'
|
144
146
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
147
|
+
Datadog.configure do |datadog|
|
148
|
+
datadog.host = config.datadog_host unless config.datadog_host.nil?
|
149
|
+
datadog.port = config.datadog_port unless config.datadog_port.nil?
|
150
|
+
datadog.namespace = config.datadog_namespace unless config.datadog_namespace.nil?
|
151
|
+
datadog.tags = config.datadog_tags unless config.datadog_tags.nil?
|
152
|
+
end
|
150
153
|
end
|
151
154
|
end
|
152
155
|
end
|
data/lib/racecar/config.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "king_konf"
|
2
4
|
|
3
5
|
module Racecar
|
@@ -13,17 +15,26 @@ module Racecar
|
|
13
15
|
desc "How frequently to commit offset positions"
|
14
16
|
float :offset_commit_interval, default: 10
|
15
17
|
|
16
|
-
desc "How many messages to process before forcing a checkpoint"
|
17
|
-
integer :offset_commit_threshold, default: 0
|
18
|
-
|
19
18
|
desc "How often to send a heartbeat message to Kafka"
|
20
19
|
float :heartbeat_interval, default: 10
|
21
20
|
|
22
|
-
desc "
|
23
|
-
integer :
|
21
|
+
desc "The minimum number of messages in the local consumer queue"
|
22
|
+
integer :min_message_queue_size, default: 2000
|
23
|
+
|
24
|
+
desc "Kafka consumer configuration options, separated with '=' -- https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md"
|
25
|
+
list :consumer, default: []
|
26
|
+
|
27
|
+
desc "Kafka producer configuration options, separated with '=' -- https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md"
|
28
|
+
list :producer, default: []
|
29
|
+
|
30
|
+
desc "The maxium number of messages that get consumed within one batch"
|
31
|
+
integer :fetch_messages, default: 1000
|
32
|
+
|
33
|
+
desc "Minimum number of bytes the broker responds with"
|
34
|
+
integer :fetch_min_bytes, default: 1
|
24
35
|
|
25
|
-
desc "
|
26
|
-
|
36
|
+
desc "Automatically store offset of last message provided to application"
|
37
|
+
boolean :synchronous_commits, default: false
|
27
38
|
|
28
39
|
desc "How long to pause a partition for if the consumer raises an exception while processing a message -- set to -1 to pause indefinitely"
|
29
40
|
float :pause_timeout, default: 10
|
@@ -37,16 +48,16 @@ module Racecar
|
|
37
48
|
desc "The idle timeout after which a consumer is kicked out of the group"
|
38
49
|
float :session_timeout, default: 30
|
39
50
|
|
40
|
-
desc "
|
41
|
-
|
51
|
+
desc "The maximum time between two message fetches before the consumer is kicked out of the group (in seconds)"
|
52
|
+
integer :max_poll_interval, default: 5*60
|
42
53
|
|
43
54
|
desc "How long to wait when trying to communicate with a Kafka broker"
|
44
55
|
float :socket_timeout, default: 30
|
45
56
|
|
46
|
-
desc "How long to allow the Kafka brokers to wait before returning messages"
|
57
|
+
desc "How long to allow the Kafka brokers to wait before returning messages (in seconds)"
|
47
58
|
float :max_wait_time, default: 1
|
48
59
|
|
49
|
-
desc "
|
60
|
+
desc "Maximum amount of data the broker shall return for a Fetch request"
|
50
61
|
integer :max_bytes, default: 10485760
|
51
62
|
|
52
63
|
desc "A prefix used when generating consumer group names"
|
@@ -61,44 +72,53 @@ module Racecar
|
|
61
72
|
desc "The log level for the Racecar logs"
|
62
73
|
string :log_level, default: "info"
|
63
74
|
|
64
|
-
desc "
|
65
|
-
|
75
|
+
desc "Protocol used to communicate with brokers"
|
76
|
+
symbol :security_protocol, allowed_values: %i{plaintext ssl sasl_plaintext sasl_ssl}
|
66
77
|
|
67
|
-
desc "
|
68
|
-
string :
|
78
|
+
desc "File or directory path to CA certificate(s) for verifying the broker's key"
|
79
|
+
string :ssl_ca_location
|
69
80
|
|
70
|
-
desc "
|
71
|
-
string :
|
81
|
+
desc "Path to CRL for verifying broker's certificate validity"
|
82
|
+
string :ssl_crl_location
|
72
83
|
|
73
|
-
desc "
|
74
|
-
string :
|
84
|
+
desc "Path to client's keystore (PKCS#12) used for authentication"
|
85
|
+
string :ssl_keystore_location
|
75
86
|
|
76
|
-
desc "
|
77
|
-
|
87
|
+
desc "Client's keystore (PKCS#12) password"
|
88
|
+
string :ssl_keystore_password
|
78
89
|
|
79
|
-
desc "
|
80
|
-
string :
|
90
|
+
desc "Path to the certificate used for authentication"
|
91
|
+
string :ssl_certificate_location
|
81
92
|
|
82
|
-
desc "
|
83
|
-
string :
|
93
|
+
desc "Path to client's certificate used for authentication"
|
94
|
+
string :ssl_key_location
|
84
95
|
|
85
|
-
desc "
|
86
|
-
string :
|
96
|
+
desc "Client's certificate password"
|
97
|
+
string :ssl_key_password
|
87
98
|
|
88
|
-
desc "
|
89
|
-
string :
|
99
|
+
desc "SASL mechanism to use for authentication"
|
100
|
+
string :sasl_mechanism, allowed_values: %w{GSSAPI PLAIN SCRAM-SHA-256 SCRAM-SHA-512}
|
90
101
|
|
91
|
-
desc "
|
92
|
-
string :
|
102
|
+
desc "Kerberos principal name that Kafka runs as, not including /hostname@REALM"
|
103
|
+
string :sasl_kerberos_service_name
|
93
104
|
|
94
|
-
desc "
|
95
|
-
string :
|
105
|
+
desc "This client's Kerberos principal name"
|
106
|
+
string :sasl_kerberos_principal
|
96
107
|
|
97
|
-
desc "
|
98
|
-
string :
|
108
|
+
desc "Full kerberos kinit command string, %{config.prop.name} is replaced by corresponding config object value, %{broker.name} returns the broker's hostname"
|
109
|
+
string :sasl_kerberos_kinit_cmd
|
99
110
|
|
100
|
-
desc "
|
101
|
-
string :
|
111
|
+
desc "Path to Kerberos keytab file. Uses system default if not set"
|
112
|
+
string :sasl_kerberos_keytab
|
113
|
+
|
114
|
+
desc "Minimum time in milliseconds between key refresh attempts"
|
115
|
+
integer :sasl_kerberos_min_time_before_relogin
|
116
|
+
|
117
|
+
desc "SASL username for use with the PLAIN and SASL-SCRAM-.. mechanism"
|
118
|
+
string :sasl_username
|
119
|
+
|
120
|
+
desc "SASL password for use with the PLAIN and SASL-SCRAM-.. mechanism"
|
121
|
+
string :sasl_password
|
102
122
|
|
103
123
|
desc "Whether to use SASL over SSL."
|
104
124
|
boolean :sasl_over_ssl, default: true
|
@@ -110,7 +130,7 @@ module Racecar
|
|
110
130
|
boolean :daemonize, default: false
|
111
131
|
|
112
132
|
desc "The codec used to compress messages with"
|
113
|
-
symbol :producer_compression_codec
|
133
|
+
symbol :producer_compression_codec, allowed_values: %i{none lz4 snappy gzip}
|
114
134
|
|
115
135
|
desc "Enable Datadog metrics"
|
116
136
|
boolean :datadog_enabled, default: false
|
@@ -127,11 +147,21 @@ module Racecar
|
|
127
147
|
desc "Tags that should always be set on Datadog metrics"
|
128
148
|
list :datadog_tags
|
129
149
|
|
150
|
+
desc "Whether to check the server certificate is valid for the hostname"
|
151
|
+
boolean :ssl_verify_hostname, default: true
|
152
|
+
|
153
|
+
desc "Whether to boot Rails when starting the consumer"
|
154
|
+
boolean :without_rails, default: false
|
155
|
+
|
130
156
|
# The error handler must be set directly on the object.
|
131
157
|
attr_reader :error_handler
|
132
158
|
|
133
159
|
attr_accessor :subscriptions, :logger
|
134
160
|
|
161
|
+
def max_wait_time_ms
|
162
|
+
max_wait_time * 1000
|
163
|
+
end
|
164
|
+
|
135
165
|
def initialize(env: ENV)
|
136
166
|
super(env: env)
|
137
167
|
@error_handler = proc {}
|
@@ -155,10 +185,6 @@ module Racecar
|
|
155
185
|
raise ConfigError, "`socket_timeout` must be longer than `max_wait_time`"
|
156
186
|
end
|
157
187
|
|
158
|
-
if connect_timeout <= max_wait_time
|
159
|
-
raise ConfigError, "`connect_timeout` must be longer than `max_wait_time`"
|
160
|
-
end
|
161
|
-
|
162
188
|
if max_pause_timeout && !pause_with_exponential_backoff?
|
163
189
|
raise ConfigError, "`max_pause_timeout` only makes sense when `pause_with_exponential_backoff` is enabled"
|
164
190
|
end
|
@@ -172,17 +198,55 @@ module Racecar
|
|
172
198
|
group_id_prefix,
|
173
199
|
|
174
200
|
# MyFunnyConsumer => my-funny-consumer
|
175
|
-
consumer_class.name.gsub(/[a-z][A-Z]/) {|str| str[0]
|
176
|
-
].compact.join
|
201
|
+
consumer_class.name.gsub(/[a-z][A-Z]/) { |str| "#{str[0]}-#{str[1]}" }.downcase,
|
202
|
+
].compact.join
|
177
203
|
|
178
204
|
self.subscriptions = consumer_class.subscriptions
|
179
205
|
self.max_wait_time = consumer_class.max_wait_time || self.max_wait_time
|
180
|
-
self.offset_retention_time = consumer_class.offset_retention_time || self.offset_retention_time
|
181
206
|
self.pidfile ||= "#{group_id}.pid"
|
182
207
|
end
|
183
208
|
|
184
209
|
def on_error(&handler)
|
185
210
|
@error_handler = handler
|
186
211
|
end
|
212
|
+
|
213
|
+
def rdkafka_consumer
|
214
|
+
consumer_config = consumer.map do |param|
|
215
|
+
param.split("=", 2).map(&:strip)
|
216
|
+
end.to_h
|
217
|
+
consumer_config.merge!(rdkafka_security_config)
|
218
|
+
consumer_config
|
219
|
+
end
|
220
|
+
|
221
|
+
def rdkafka_producer
|
222
|
+
producer_config = producer.map do |param|
|
223
|
+
param.split("=", 2).map(&:strip)
|
224
|
+
end.to_h
|
225
|
+
producer_config.merge!(rdkafka_security_config)
|
226
|
+
producer_config
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
def rdkafka_security_config
|
232
|
+
{
|
233
|
+
"security.protocol" => security_protocol,
|
234
|
+
"ssl.ca.location" => ssl_ca_location,
|
235
|
+
"ssl.crl.location" => ssl_crl_location,
|
236
|
+
"ssl.keystore.location" => ssl_keystore_location,
|
237
|
+
"ssl.keystore.password" => ssl_keystore_password,
|
238
|
+
"ssl.certificate.location" => ssl_certificate_location,
|
239
|
+
"ssl.key.location" => ssl_key_location,
|
240
|
+
"ssl.key.password" => ssl_key_password,
|
241
|
+
"sasl.mechanism" => sasl_mechanism,
|
242
|
+
"sasl.kerberos.service.name" => sasl_kerberos_service_name,
|
243
|
+
"sasl.kerberos.principal" => sasl_kerberos_principal,
|
244
|
+
"sasl.kerberos.kinit.cmd" => sasl_kerberos_kinit_cmd,
|
245
|
+
"sasl.kerberos.keytab" => sasl_kerberos_keytab,
|
246
|
+
"sasl.kerberos.min.time.before.relogin" => sasl_kerberos_min_time_before_relogin,
|
247
|
+
"sasl.username" => sasl_username,
|
248
|
+
"sasl.password" => sasl_password,
|
249
|
+
}.compact
|
250
|
+
end
|
187
251
|
end
|
188
252
|
end
|