rdkafka 0.12.0 → 0.15.1

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 (86) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/.github/workflows/ci.yml +57 -0
  5. data/.gitignore +4 -0
  6. data/.rspec +1 -0
  7. data/.ruby-gemset +1 -0
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +155 -93
  10. data/Gemfile +2 -0
  11. data/{LICENSE → MIT-LICENSE} +2 -1
  12. data/README.md +76 -29
  13. data/Rakefile +2 -0
  14. data/certs/cert_chain.pem +26 -0
  15. data/docker-compose.yml +18 -15
  16. data/ext/README.md +1 -1
  17. data/ext/Rakefile +46 -27
  18. data/lib/rdkafka/abstract_handle.rb +41 -25
  19. data/lib/rdkafka/admin/acl_binding_result.rb +51 -0
  20. data/lib/rdkafka/admin/create_acl_handle.rb +28 -0
  21. data/lib/rdkafka/admin/create_acl_report.rb +24 -0
  22. data/lib/rdkafka/admin/create_partitions_handle.rb +27 -0
  23. data/lib/rdkafka/admin/create_partitions_report.rb +6 -0
  24. data/lib/rdkafka/admin/create_topic_handle.rb +2 -0
  25. data/lib/rdkafka/admin/create_topic_report.rb +2 -0
  26. data/lib/rdkafka/admin/delete_acl_handle.rb +30 -0
  27. data/lib/rdkafka/admin/delete_acl_report.rb +23 -0
  28. data/lib/rdkafka/admin/delete_groups_handle.rb +28 -0
  29. data/lib/rdkafka/admin/delete_groups_report.rb +24 -0
  30. data/lib/rdkafka/admin/delete_topic_handle.rb +2 -0
  31. data/lib/rdkafka/admin/delete_topic_report.rb +2 -0
  32. data/lib/rdkafka/admin/describe_acl_handle.rb +30 -0
  33. data/lib/rdkafka/admin/describe_acl_report.rb +23 -0
  34. data/lib/rdkafka/admin.rb +494 -35
  35. data/lib/rdkafka/bindings.rb +180 -41
  36. data/lib/rdkafka/callbacks.rb +202 -1
  37. data/lib/rdkafka/config.rb +62 -25
  38. data/lib/rdkafka/consumer/headers.rb +24 -9
  39. data/lib/rdkafka/consumer/message.rb +3 -1
  40. data/lib/rdkafka/consumer/partition.rb +2 -0
  41. data/lib/rdkafka/consumer/topic_partition_list.rb +13 -8
  42. data/lib/rdkafka/consumer.rb +243 -111
  43. data/lib/rdkafka/error.rb +15 -0
  44. data/lib/rdkafka/helpers/time.rb +14 -0
  45. data/lib/rdkafka/metadata.rb +25 -2
  46. data/lib/rdkafka/native_kafka.rb +120 -0
  47. data/lib/rdkafka/producer/delivery_handle.rb +16 -2
  48. data/lib/rdkafka/producer/delivery_report.rb +22 -2
  49. data/lib/rdkafka/producer.rb +151 -21
  50. data/lib/rdkafka/version.rb +5 -3
  51. data/lib/rdkafka.rb +24 -2
  52. data/rdkafka.gemspec +21 -5
  53. data/renovate.json +6 -0
  54. data/spec/rdkafka/abstract_handle_spec.rb +1 -1
  55. data/spec/rdkafka/admin/create_acl_handle_spec.rb +56 -0
  56. data/spec/rdkafka/admin/create_acl_report_spec.rb +18 -0
  57. data/spec/rdkafka/admin/create_topic_handle_spec.rb +1 -1
  58. data/spec/rdkafka/admin/create_topic_report_spec.rb +1 -1
  59. data/spec/rdkafka/admin/delete_acl_handle_spec.rb +85 -0
  60. data/spec/rdkafka/admin/delete_acl_report_spec.rb +72 -0
  61. data/spec/rdkafka/admin/delete_topic_handle_spec.rb +1 -1
  62. data/spec/rdkafka/admin/delete_topic_report_spec.rb +1 -1
  63. data/spec/rdkafka/admin/describe_acl_handle_spec.rb +85 -0
  64. data/spec/rdkafka/admin/describe_acl_report_spec.rb +73 -0
  65. data/spec/rdkafka/admin_spec.rb +209 -5
  66. data/spec/rdkafka/bindings_spec.rb +2 -1
  67. data/spec/rdkafka/callbacks_spec.rb +1 -1
  68. data/spec/rdkafka/config_spec.rb +24 -3
  69. data/spec/rdkafka/consumer/headers_spec.rb +60 -0
  70. data/spec/rdkafka/consumer/message_spec.rb +1 -1
  71. data/spec/rdkafka/consumer/partition_spec.rb +1 -1
  72. data/spec/rdkafka/consumer/topic_partition_list_spec.rb +20 -1
  73. data/spec/rdkafka/consumer_spec.rb +352 -61
  74. data/spec/rdkafka/error_spec.rb +1 -1
  75. data/spec/rdkafka/metadata_spec.rb +4 -3
  76. data/spec/rdkafka/{producer/client_spec.rb → native_kafka_spec.rb} +13 -35
  77. data/spec/rdkafka/producer/delivery_handle_spec.rb +4 -1
  78. data/spec/rdkafka/producer/delivery_report_spec.rb +11 -3
  79. data/spec/rdkafka/producer_spec.rb +234 -22
  80. data/spec/spec_helper.rb +20 -2
  81. data.tar.gz.sig +0 -0
  82. metadata +81 -17
  83. metadata.gz.sig +0 -0
  84. data/.semaphore/semaphore.yml +0 -23
  85. data/bin/console +0 -11
  86. data/lib/rdkafka/producer/client.rb +0 -47
data/lib/rdkafka/admin.rb CHANGED
@@ -1,43 +1,54 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rdkafka
2
4
  class Admin
3
5
  # @private
4
6
  def initialize(native_kafka)
5
7
  @native_kafka = native_kafka
6
- @closing = false
7
-
8
- # Start thread to poll client for callbacks
9
- @polling_thread = Thread.new do
10
- loop do
11
- Rdkafka::Bindings.rd_kafka_poll(@native_kafka, 250)
12
- # Exit thread if closing and the poll queue is empty
13
- if @closing && Rdkafka::Bindings.rd_kafka_outq_len(@native_kafka) == 0
14
- break
15
- end
16
- end
8
+
9
+ # Makes sure, that native kafka gets closed before it gets GCed by Ruby
10
+ ObjectSpace.define_finalizer(self, native_kafka.finalizer)
11
+ end
12
+
13
+ def finalizer
14
+ ->(_) { close }
15
+ end
16
+
17
+ # Performs the metadata request using admin
18
+ #
19
+ # @param topic_name [String, nil] metadat about particular topic or all if nil
20
+ # @param timeout_ms [Integer] metadata request timeout
21
+ # @return [Metadata] requested metadata
22
+ def metadata(topic_name = nil, timeout_ms = 2_000)
23
+ closed_admin_check(__method__)
24
+
25
+ @native_kafka.with_inner do |inner|
26
+ Metadata.new(inner, topic_name, timeout_ms)
17
27
  end
18
- @polling_thread.abort_on_exception = true
19
28
  end
20
29
 
21
30
  # Close this admin instance
22
31
  def close
23
- return unless @native_kafka
24
-
25
- # Indicate to polling thread that we're closing
26
- @closing = true
27
- # Wait for the polling thread to finish up
28
- @polling_thread.join
29
- Rdkafka::Bindings.rd_kafka_destroy(@native_kafka)
30
- @native_kafka = nil
32
+ return if closed?
33
+ ObjectSpace.undefine_finalizer(self)
34
+ @native_kafka.close
35
+ end
36
+
37
+ # Whether this admin has closed
38
+ def closed?
39
+ @native_kafka.closed?
31
40
  end
32
41
 
33
42
  # Create a topic with the given partition count and replication factor
34
43
  #
44
+ # @return [CreateTopicHandle] Create topic handle that can be used to wait for the result of
45
+ # creating the topic
46
+ #
35
47
  # @raise [ConfigError] When the partition count or replication factor are out of valid range
36
48
  # @raise [RdkafkaError] When the topic name is invalid or the topic already exists
37
49
  # @raise [RdkafkaError] When the topic configuration is invalid
38
- #
39
- # @return [CreateTopicHandle] Create topic handle that can be used to wait for the result of creating the topic
40
50
  def create_topic(topic_name, partition_count, replication_factor, topic_config={})
51
+ closed_admin_check(__method__)
41
52
 
42
53
  # Create a rd_kafka_NewTopic_t representing the new topic
43
54
  error_buffer = FFI::MemoryPointer.from_string(" " * 256)
@@ -68,7 +79,9 @@ module Rdkafka
68
79
  topics_array_ptr.write_array_of_pointer(pointer_array)
69
80
 
70
81
  # Get a pointer to the queue that our request will be enqueued on
71
- queue_ptr = Rdkafka::Bindings.rd_kafka_queue_get_background(@native_kafka)
82
+ queue_ptr = @native_kafka.with_inner do |inner|
83
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
84
+ end
72
85
  if queue_ptr.null?
73
86
  Rdkafka::Bindings.rd_kafka_NewTopic_destroy(new_topic_ptr)
74
87
  raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
@@ -79,17 +92,21 @@ module Rdkafka
79
92
  create_topic_handle[:pending] = true
80
93
  create_topic_handle[:response] = -1
81
94
  CreateTopicHandle.register(create_topic_handle)
82
- admin_options_ptr = Rdkafka::Bindings.rd_kafka_AdminOptions_new(@native_kafka, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATETOPICS)
95
+ admin_options_ptr = @native_kafka.with_inner do |inner|
96
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATETOPICS)
97
+ end
83
98
  Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, create_topic_handle.to_ptr)
84
99
 
85
100
  begin
86
- Rdkafka::Bindings.rd_kafka_CreateTopics(
87
- @native_kafka,
101
+ @native_kafka.with_inner do |inner|
102
+ Rdkafka::Bindings.rd_kafka_CreateTopics(
103
+ inner,
88
104
  topics_array_ptr,
89
105
  1,
90
106
  admin_options_ptr,
91
107
  queue_ptr
92
- )
108
+ )
109
+ end
93
110
  rescue Exception
94
111
  CreateTopicHandle.remove(create_topic_handle.to_ptr.address)
95
112
  raise
@@ -102,12 +119,66 @@ module Rdkafka
102
119
  create_topic_handle
103
120
  end
104
121
 
105
- # Delete the named topic
122
+ def delete_group(group_id)
123
+ closed_admin_check(__method__)
124
+
125
+ # Create a rd_kafka_DeleteGroup_t representing the new topic
126
+ delete_groups_ptr = Rdkafka::Bindings.rd_kafka_DeleteGroup_new(
127
+ FFI::MemoryPointer.from_string(group_id)
128
+ )
129
+
130
+ pointer_array = [delete_groups_ptr]
131
+ groups_array_ptr = FFI::MemoryPointer.new(:pointer)
132
+ groups_array_ptr.write_array_of_pointer(pointer_array)
133
+
134
+ # Get a pointer to the queue that our request will be enqueued on
135
+ queue_ptr = @native_kafka.with_inner do |inner|
136
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
137
+ end
138
+ if queue_ptr.null?
139
+ Rdkafka::Bindings.rd_kafka_DeleteTopic_destroy(delete_topic_ptr)
140
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
141
+ end
142
+
143
+ # Create and register the handle we will return to the caller
144
+ delete_groups_handle = DeleteGroupsHandle.new
145
+ delete_groups_handle[:pending] = true
146
+ delete_groups_handle[:response] = -1
147
+ DeleteGroupsHandle.register(delete_groups_handle)
148
+ admin_options_ptr = @native_kafka.with_inner do |inner|
149
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETETOPICS)
150
+ end
151
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, delete_groups_handle.to_ptr)
152
+
153
+ begin
154
+ @native_kafka.with_inner do |inner|
155
+ Rdkafka::Bindings.rd_kafka_DeleteGroups(
156
+ inner,
157
+ groups_array_ptr,
158
+ 1,
159
+ admin_options_ptr,
160
+ queue_ptr
161
+ )
162
+ end
163
+ rescue Exception
164
+ DeleteGroupsHandle.remove(delete_groups_handle.to_ptr.address)
165
+ raise
166
+ ensure
167
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
168
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
169
+ Rdkafka::Bindings.rd_kafka_DeleteGroup_destroy(delete_groups_ptr)
170
+ end
171
+
172
+ delete_groups_handle
173
+ end
174
+
175
+ # Deletes the named topic
106
176
  #
177
+ # @return [DeleteTopicHandle] Delete topic handle that can be used to wait for the result of
178
+ # deleting the topic
107
179
  # @raise [RdkafkaError] When the topic name is invalid or the topic does not exist
108
- #
109
- # @return [DeleteTopicHandle] Delete topic handle that can be used to wait for the result of deleting the topic
110
180
  def delete_topic(topic_name)
181
+ closed_admin_check(__method__)
111
182
 
112
183
  # Create a rd_kafka_DeleteTopic_t representing the topic to be deleted
113
184
  delete_topic_ptr = Rdkafka::Bindings.rd_kafka_DeleteTopic_new(FFI::MemoryPointer.from_string(topic_name))
@@ -118,7 +189,9 @@ module Rdkafka
118
189
  topics_array_ptr.write_array_of_pointer(pointer_array)
119
190
 
120
191
  # Get a pointer to the queue that our request will be enqueued on
121
- queue_ptr = Rdkafka::Bindings.rd_kafka_queue_get_background(@native_kafka)
192
+ queue_ptr = @native_kafka.with_inner do |inner|
193
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
194
+ end
122
195
  if queue_ptr.null?
123
196
  Rdkafka::Bindings.rd_kafka_DeleteTopic_destroy(delete_topic_ptr)
124
197
  raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
@@ -129,17 +202,21 @@ module Rdkafka
129
202
  delete_topic_handle[:pending] = true
130
203
  delete_topic_handle[:response] = -1
131
204
  DeleteTopicHandle.register(delete_topic_handle)
132
- admin_options_ptr = Rdkafka::Bindings.rd_kafka_AdminOptions_new(@native_kafka, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETETOPICS)
205
+ admin_options_ptr = @native_kafka.with_inner do |inner|
206
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETETOPICS)
207
+ end
133
208
  Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, delete_topic_handle.to_ptr)
134
209
 
135
210
  begin
136
- Rdkafka::Bindings.rd_kafka_DeleteTopics(
137
- @native_kafka,
211
+ @native_kafka.with_inner do |inner|
212
+ Rdkafka::Bindings.rd_kafka_DeleteTopics(
213
+ inner,
138
214
  topics_array_ptr,
139
215
  1,
140
216
  admin_options_ptr,
141
217
  queue_ptr
142
- )
218
+ )
219
+ end
143
220
  rescue Exception
144
221
  DeleteTopicHandle.remove(delete_topic_handle.to_ptr.address)
145
222
  raise
@@ -151,5 +228,387 @@ module Rdkafka
151
228
 
152
229
  delete_topic_handle
153
230
  end
231
+
232
+ # Creates extra partitions for a given topic
233
+ #
234
+ # @param topic_name [String]
235
+ # @param partition_count [Integer] how many partitions we want to end up with for given topic
236
+ #
237
+ # @raise [ConfigError] When the partition count or replication factor are out of valid range
238
+ # @raise [RdkafkaError] When the topic name is invalid or the topic already exists
239
+ # @raise [RdkafkaError] When the topic configuration is invalid
240
+ #
241
+ # @return [CreateTopicHandle] Create topic handle that can be used to wait for the result of creating the topic
242
+ def create_partitions(topic_name, partition_count)
243
+ closed_admin_check(__method__)
244
+
245
+ @native_kafka.with_inner do |inner|
246
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
247
+ new_partitions_ptr = Rdkafka::Bindings.rd_kafka_NewPartitions_new(
248
+ FFI::MemoryPointer.from_string(topic_name),
249
+ partition_count,
250
+ error_buffer,
251
+ 256
252
+ )
253
+ if new_partitions_ptr.null?
254
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
255
+ end
256
+
257
+ pointer_array = [new_partitions_ptr]
258
+ topics_array_ptr = FFI::MemoryPointer.new(:pointer)
259
+ topics_array_ptr.write_array_of_pointer(pointer_array)
260
+
261
+ # Get a pointer to the queue that our request will be enqueued on
262
+ queue_ptr = Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
263
+ if queue_ptr.null?
264
+ Rdkafka::Bindings.rd_kafka_NewPartitions_destroy(new_partitions_ptr)
265
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
266
+ end
267
+
268
+ # Create and register the handle we will return to the caller
269
+ create_partitions_handle = CreatePartitionsHandle.new
270
+ create_partitions_handle[:pending] = true
271
+ create_partitions_handle[:response] = -1
272
+ CreatePartitionsHandle.register(create_partitions_handle)
273
+ admin_options_ptr = Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEPARTITIONS)
274
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, create_partitions_handle.to_ptr)
275
+
276
+ begin
277
+ Rdkafka::Bindings.rd_kafka_CreatePartitions(
278
+ inner,
279
+ topics_array_ptr,
280
+ 1,
281
+ admin_options_ptr,
282
+ queue_ptr
283
+ )
284
+ rescue Exception
285
+ CreatePartitionsHandle.remove(create_partitions_handle.to_ptr.address)
286
+ raise
287
+ ensure
288
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
289
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
290
+ Rdkafka::Bindings.rd_kafka_NewPartitions_destroy(new_partitions_ptr)
291
+ end
292
+
293
+ create_partitions_handle
294
+ end
295
+ end
296
+
297
+ # Create acl
298
+ # @param resource_type - values of type rd_kafka_ResourceType_t
299
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
300
+ # valid values are:
301
+ # RD_KAFKA_RESOURCE_TOPIC = 2
302
+ # RD_KAFKA_RESOURCE_GROUP = 3
303
+ # RD_KAFKA_RESOURCE_BROKER = 4
304
+ # @param resource_pattern_type - values of type rd_kafka_ResourcePatternType_t
305
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
306
+ # valid values are:
307
+ # RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
308
+ # RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
309
+ # RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
310
+ # @param operation - values of type rd_kafka_AclOperation_t
311
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8403
312
+ # valid values are:
313
+ # RD_KAFKA_ACL_OPERATION_ALL = 2
314
+ # RD_KAFKA_ACL_OPERATION_READ = 3
315
+ # RD_KAFKA_ACL_OPERATION_WRITE = 4
316
+ # RD_KAFKA_ACL_OPERATION_CREATE = 5
317
+ # RD_KAFKA_ACL_OPERATION_DELETE = 6
318
+ # RD_KAFKA_ACL_OPERATION_ALTER = 7
319
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE = 8
320
+ # RD_KAFKA_ACL_OPERATION_CLUSTER_ACTION = 9
321
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE_CONFIGS = 10
322
+ # RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
323
+ # RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
324
+ # @param permission_type - values of type rd_kafka_AclPermissionType_t
325
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8435
326
+ # valid values are:
327
+ # RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
328
+ # RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
329
+ #
330
+ # @return [CreateAclHandle] Create acl handle that can be used to wait for the result of creating the acl
331
+ #
332
+ # @raise [RdkafkaError]
333
+ def create_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
334
+ closed_admin_check(__method__)
335
+
336
+ # Create a rd_kafka_AclBinding_t representing the new acl
337
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
338
+ new_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBinding_new(
339
+ resource_type,
340
+ FFI::MemoryPointer.from_string(resource_name),
341
+ resource_pattern_type,
342
+ FFI::MemoryPointer.from_string(principal),
343
+ FFI::MemoryPointer.from_string(host),
344
+ operation,
345
+ permission_type,
346
+ error_buffer,
347
+ 256
348
+ )
349
+ if new_acl_ptr.null?
350
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
351
+ end
352
+
353
+ # Note that rd_kafka_CreateAcls can create more than one acl at a time
354
+ pointer_array = [new_acl_ptr]
355
+ acls_array_ptr = FFI::MemoryPointer.new(:pointer)
356
+ acls_array_ptr.write_array_of_pointer(pointer_array)
357
+
358
+ # Get a pointer to the queue that our request will be enqueued on
359
+ queue_ptr = @native_kafka.with_inner do |inner|
360
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
361
+ end
362
+
363
+ if queue_ptr.null?
364
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(new_acl_ptr)
365
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
366
+ end
367
+
368
+ # Create and register the handle that we will return to the caller
369
+ create_acl_handle = CreateAclHandle.new
370
+ create_acl_handle[:pending] = true
371
+ create_acl_handle[:response] = -1
372
+ CreateAclHandle.register(create_acl_handle)
373
+
374
+ admin_options_ptr = @native_kafka.with_inner do |inner|
375
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEACLS)
376
+ end
377
+
378
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, create_acl_handle.to_ptr)
379
+
380
+ begin
381
+ @native_kafka.with_inner do |inner|
382
+ Rdkafka::Bindings.rd_kafka_CreateAcls(
383
+ inner,
384
+ acls_array_ptr,
385
+ 1,
386
+ admin_options_ptr,
387
+ queue_ptr
388
+ )
389
+ end
390
+ rescue Exception
391
+ CreateAclHandle.remove(create_acl_handle.to_ptr.address)
392
+ raise
393
+ ensure
394
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
395
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
396
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(new_acl_ptr)
397
+ end
398
+
399
+ create_acl_handle
400
+ end
401
+
402
+ # Delete acl
403
+ #
404
+ # @param resource_type - values of type rd_kafka_ResourceType_t
405
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
406
+ # valid values are:
407
+ # RD_KAFKA_RESOURCE_TOPIC = 2
408
+ # RD_KAFKA_RESOURCE_GROUP = 3
409
+ # RD_KAFKA_RESOURCE_BROKER = 4
410
+ # @param resource_pattern_type - values of type rd_kafka_ResourcePatternType_t
411
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
412
+ # valid values are:
413
+ # RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
414
+ # RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
415
+ # RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
416
+ # @param operation - values of type rd_kafka_AclOperation_t
417
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8403
418
+ # valid values are:
419
+ # RD_KAFKA_ACL_OPERATION_ALL = 2
420
+ # RD_KAFKA_ACL_OPERATION_READ = 3
421
+ # RD_KAFKA_ACL_OPERATION_WRITE = 4
422
+ # RD_KAFKA_ACL_OPERATION_CREATE = 5
423
+ # RD_KAFKA_ACL_OPERATION_DELETE = 6
424
+ # RD_KAFKA_ACL_OPERATION_ALTER = 7
425
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE = 8
426
+ # RD_KAFKA_ACL_OPERATION_CLUSTER_ACTION = 9
427
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE_CONFIGS = 10
428
+ # RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
429
+ # RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
430
+ # @param permission_type - values of type rd_kafka_AclPermissionType_t
431
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8435
432
+ # valid values are:
433
+ # RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
434
+ # RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
435
+ # @return [DeleteAclHandle] Delete acl handle that can be used to wait for the result of deleting the acl
436
+ #
437
+ # @raise [RdkafkaError]
438
+ def delete_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
439
+ closed_admin_check(__method__)
440
+
441
+ # Create a rd_kafka_AclBinding_t representing the acl to be deleted
442
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
443
+
444
+ delete_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBindingFilter_new(
445
+ resource_type,
446
+ resource_name ? FFI::MemoryPointer.from_string(resource_name) : nil,
447
+ resource_pattern_type,
448
+ principal ? FFI::MemoryPointer.from_string(principal) : nil,
449
+ host ? FFI::MemoryPointer.from_string(host) : nil,
450
+ operation,
451
+ permission_type,
452
+ error_buffer,
453
+ 256
454
+ )
455
+
456
+ if delete_acl_ptr.null?
457
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
458
+ end
459
+
460
+ # Note that rd_kafka_DeleteAcls can delete more than one acl at a time
461
+ pointer_array = [delete_acl_ptr]
462
+ acls_array_ptr = FFI::MemoryPointer.new(:pointer)
463
+ acls_array_ptr.write_array_of_pointer(pointer_array)
464
+
465
+ # Get a pointer to the queue that our request will be enqueued on
466
+ queue_ptr = @native_kafka.with_inner do |inner|
467
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
468
+ end
469
+
470
+ if queue_ptr.null?
471
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(new_acl_ptr)
472
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
473
+ end
474
+
475
+ # Create and register the handle that we will return to the caller
476
+ delete_acl_handle = DeleteAclHandle.new
477
+ delete_acl_handle[:pending] = true
478
+ delete_acl_handle[:response] = -1
479
+ DeleteAclHandle.register(delete_acl_handle)
480
+
481
+ admin_options_ptr = @native_kafka.with_inner do |inner|
482
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETEACLS)
483
+ end
484
+
485
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, delete_acl_handle.to_ptr)
486
+
487
+ begin
488
+ @native_kafka.with_inner do |inner|
489
+ Rdkafka::Bindings.rd_kafka_DeleteAcls(
490
+ inner,
491
+ acls_array_ptr,
492
+ 1,
493
+ admin_options_ptr,
494
+ queue_ptr
495
+ )
496
+ end
497
+ rescue Exception
498
+ DeleteAclHandle.remove(delete_acl_handle.to_ptr.address)
499
+ raise
500
+ ensure
501
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
502
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
503
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(delete_acl_ptr)
504
+ end
505
+
506
+ delete_acl_handle
507
+ end
508
+
509
+ # Describe acls
510
+ #
511
+ # @param resource_type - values of type rd_kafka_ResourceType_t
512
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
513
+ # valid values are:
514
+ # RD_KAFKA_RESOURCE_TOPIC = 2
515
+ # RD_KAFKA_RESOURCE_GROUP = 3
516
+ # RD_KAFKA_RESOURCE_BROKER = 4
517
+ # @param resource_pattern_type - values of type rd_kafka_ResourcePatternType_t
518
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
519
+ # valid values are:
520
+ # RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
521
+ # RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
522
+ # RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
523
+ # @param operation - values of type rd_kafka_AclOperation_t
524
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8403
525
+ # valid values are:
526
+ # RD_KAFKA_ACL_OPERATION_ALL = 2
527
+ # RD_KAFKA_ACL_OPERATION_READ = 3
528
+ # RD_KAFKA_ACL_OPERATION_WRITE = 4
529
+ # RD_KAFKA_ACL_OPERATION_CREATE = 5
530
+ # RD_KAFKA_ACL_OPERATION_DELETE = 6
531
+ # RD_KAFKA_ACL_OPERATION_ALTER = 7
532
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE = 8
533
+ # RD_KAFKA_ACL_OPERATION_CLUSTER_ACTION = 9
534
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE_CONFIGS = 10
535
+ # RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
536
+ # RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
537
+ # @param permission_type - values of type rd_kafka_AclPermissionType_t
538
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8435
539
+ # valid values are:
540
+ # RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
541
+ # RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
542
+ # @return [DescribeAclHandle] Describe acl handle that can be used to wait for the result of fetching acls
543
+ #
544
+ # @raise [RdkafkaError]
545
+ def describe_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
546
+ closed_admin_check(__method__)
547
+
548
+ # Create a rd_kafka_AclBinding_t with the filters to fetch existing acls
549
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
550
+ describe_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBindingFilter_new(
551
+ resource_type,
552
+ resource_name ? FFI::MemoryPointer.from_string(resource_name) : nil,
553
+ resource_pattern_type,
554
+ principal ? FFI::MemoryPointer.from_string(principal) : nil,
555
+ host ? FFI::MemoryPointer.from_string(host) : nil,
556
+ operation,
557
+ permission_type,
558
+ error_buffer,
559
+ 256
560
+ )
561
+ if describe_acl_ptr.null?
562
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
563
+ end
564
+
565
+ # Get a pointer to the queue that our request will be enqueued on
566
+ queue_ptr = @native_kafka.with_inner do |inner|
567
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
568
+ end
569
+
570
+ if queue_ptr.null?
571
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(new_acl_ptr)
572
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
573
+ end
574
+
575
+ # Create and register the handle that we will return to the caller
576
+ describe_acl_handle = DescribeAclHandle.new
577
+ describe_acl_handle[:pending] = true
578
+ describe_acl_handle[:response] = -1
579
+ DescribeAclHandle.register(describe_acl_handle)
580
+
581
+ admin_options_ptr = @native_kafka.with_inner do |inner|
582
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DESCRIBEACLS)
583
+ end
584
+
585
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, describe_acl_handle.to_ptr)
586
+
587
+ begin
588
+ @native_kafka.with_inner do |inner|
589
+ Rdkafka::Bindings.rd_kafka_DescribeAcls(
590
+ inner,
591
+ describe_acl_ptr,
592
+ admin_options_ptr,
593
+ queue_ptr
594
+ )
595
+ end
596
+ rescue Exception
597
+ DescribeAclHandle.remove(describe_acl_handle.to_ptr.address)
598
+ raise
599
+ ensure
600
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
601
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
602
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(describe_acl_ptr)
603
+ end
604
+
605
+ describe_acl_handle
606
+ end
607
+
608
+ private
609
+
610
+ def closed_admin_check(method)
611
+ raise Rdkafka::ClosedAdminError.new(method) if closed?
612
+ end
154
613
  end
155
614
  end