kafka-python 3.0.0__py3-none-any.whl
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.
- kafka/__init__.py +34 -0
- kafka/__main__.py +5 -0
- kafka/admin/__init__.py +29 -0
- kafka/admin/__main__.py +5 -0
- kafka/admin/_acls.py +355 -0
- kafka/admin/_cluster.py +359 -0
- kafka/admin/_configs.py +479 -0
- kafka/admin/_groups.py +754 -0
- kafka/admin/_partitions.py +595 -0
- kafka/admin/_topics.py +281 -0
- kafka/admin/_transactions.py +450 -0
- kafka/admin/_users.py +194 -0
- kafka/admin/client.py +373 -0
- kafka/benchmarks/__init__.py +0 -0
- kafka/benchmarks/consumer_performance.py +138 -0
- kafka/benchmarks/load_example.py +109 -0
- kafka/benchmarks/producer_encode_path.py +201 -0
- kafka/benchmarks/producer_performance.py +161 -0
- kafka/benchmarks/profile_protocol.py +138 -0
- kafka/benchmarks/protocol_old_vs_new.py +447 -0
- kafka/benchmarks/record_batch_compose.py +77 -0
- kafka/benchmarks/record_batch_read.py +82 -0
- kafka/benchmarks/varint_speed.py +426 -0
- kafka/cli/__init__.py +36 -0
- kafka/cli/admin/__init__.py +117 -0
- kafka/cli/admin/acls/__init__.py +9 -0
- kafka/cli/admin/acls/common.py +76 -0
- kafka/cli/admin/acls/create.py +19 -0
- kafka/cli/admin/acls/delete.py +23 -0
- kafka/cli/admin/acls/describe.py +16 -0
- kafka/cli/admin/cluster/__init__.py +14 -0
- kafka/cli/admin/cluster/describe.py +11 -0
- kafka/cli/admin/cluster/describe_quorum.py +11 -0
- kafka/cli/admin/cluster/features.py +52 -0
- kafka/cli/admin/cluster/log_dirs.py +43 -0
- kafka/cli/admin/cluster/versions.py +33 -0
- kafka/cli/admin/configs/__init__.py +10 -0
- kafka/cli/admin/configs/alter.py +43 -0
- kafka/cli/admin/configs/common.py +17 -0
- kafka/cli/admin/configs/describe.py +30 -0
- kafka/cli/admin/configs/list.py +16 -0
- kafka/cli/admin/configs/reset.py +20 -0
- kafka/cli/admin/groups/__init__.py +16 -0
- kafka/cli/admin/groups/alter_offsets.py +30 -0
- kafka/cli/admin/groups/delete.py +11 -0
- kafka/cli/admin/groups/delete_offsets.py +29 -0
- kafka/cli/admin/groups/describe.py +11 -0
- kafka/cli/admin/groups/list.py +28 -0
- kafka/cli/admin/groups/list_offsets.py +29 -0
- kafka/cli/admin/groups/remove_members.py +40 -0
- kafka/cli/admin/groups/reset_offsets.py +139 -0
- kafka/cli/admin/partitions/__init__.py +21 -0
- kafka/cli/admin/partitions/alter_reassignments.py +37 -0
- kafka/cli/admin/partitions/create.py +27 -0
- kafka/cli/admin/partitions/delete_records.py +31 -0
- kafka/cli/admin/partitions/describe.py +36 -0
- kafka/cli/admin/partitions/elect_leaders.py +53 -0
- kafka/cli/admin/partitions/list_offsets.py +88 -0
- kafka/cli/admin/partitions/list_reassignments.py +35 -0
- kafka/cli/admin/topics/__init__.py +10 -0
- kafka/cli/admin/topics/create.py +13 -0
- kafka/cli/admin/topics/delete.py +19 -0
- kafka/cli/admin/topics/describe.py +18 -0
- kafka/cli/admin/topics/list.py +11 -0
- kafka/cli/admin/transactions/__init__.py +17 -0
- kafka/cli/admin/transactions/abort.py +38 -0
- kafka/cli/admin/transactions/describe.py +24 -0
- kafka/cli/admin/transactions/describe_producers.py +29 -0
- kafka/cli/admin/transactions/find_hanging.py +26 -0
- kafka/cli/admin/transactions/list.py +37 -0
- kafka/cli/admin/users/__init__.py +8 -0
- kafka/cli/admin/users/alter_user_scram_credentials.py +34 -0
- kafka/cli/admin/users/describe_user_scram_credentials.py +15 -0
- kafka/cli/common.py +95 -0
- kafka/cli/consumer/__init__.py +63 -0
- kafka/cli/producer/__init__.py +57 -0
- kafka/cluster.py +824 -0
- kafka/codec.py +325 -0
- kafka/consumer/__init__.py +5 -0
- kafka/consumer/__main__.py +5 -0
- kafka/consumer/fetcher.py +2012 -0
- kafka/consumer/group.py +1347 -0
- kafka/consumer/subscription_state.py +897 -0
- kafka/coordinator/__init__.py +0 -0
- kafka/coordinator/assignors/__init__.py +0 -0
- kafka/coordinator/assignors/abstract.py +90 -0
- kafka/coordinator/assignors/cooperative_sticky.py +167 -0
- kafka/coordinator/assignors/range.py +81 -0
- kafka/coordinator/assignors/roundrobin.py +101 -0
- kafka/coordinator/assignors/sticky/StickyAssignorUserData.json +37 -0
- kafka/coordinator/assignors/sticky/__init__.py +0 -0
- kafka/coordinator/assignors/sticky/partition_movements.py +149 -0
- kafka/coordinator/assignors/sticky/sorted_set.py +63 -0
- kafka/coordinator/assignors/sticky/sticky_assignor.py +665 -0
- kafka/coordinator/assignors/sticky/user_data.py +8 -0
- kafka/coordinator/base.py +1215 -0
- kafka/coordinator/consumer.py +1224 -0
- kafka/coordinator/heartbeat.py +82 -0
- kafka/coordinator/subscription.py +34 -0
- kafka/errors.py +1004 -0
- kafka/future.py +166 -0
- kafka/metrics/__init__.py +13 -0
- kafka/metrics/compound_stat.py +33 -0
- kafka/metrics/dict_reporter.py +81 -0
- kafka/metrics/kafka_metric.py +36 -0
- kafka/metrics/measurable.py +27 -0
- kafka/metrics/measurable_stat.py +13 -0
- kafka/metrics/metric_config.py +33 -0
- kafka/metrics/metric_name.py +105 -0
- kafka/metrics/metrics.py +261 -0
- kafka/metrics/metrics_reporter.py +53 -0
- kafka/metrics/quota.py +41 -0
- kafka/metrics/stat.py +19 -0
- kafka/metrics/stats/__init__.py +15 -0
- kafka/metrics/stats/avg.py +24 -0
- kafka/metrics/stats/count.py +17 -0
- kafka/metrics/stats/histogram.py +99 -0
- kafka/metrics/stats/max_stat.py +17 -0
- kafka/metrics/stats/min_stat.py +19 -0
- kafka/metrics/stats/percentile.py +14 -0
- kafka/metrics/stats/percentiles.py +75 -0
- kafka/metrics/stats/rate.py +118 -0
- kafka/metrics/stats/sampled_stat.py +99 -0
- kafka/metrics/stats/sensor.py +136 -0
- kafka/metrics/stats/total.py +15 -0
- kafka/net/__init__.py +19 -0
- kafka/net/compat.py +165 -0
- kafka/net/connection.py +593 -0
- kafka/net/http_connect.py +144 -0
- kafka/net/inet.py +122 -0
- kafka/net/manager.py +451 -0
- kafka/net/metrics.py +149 -0
- kafka/net/sasl/__init__.py +32 -0
- kafka/net/sasl/abc.py +28 -0
- kafka/net/sasl/gssapi.py +95 -0
- kafka/net/sasl/msk.py +245 -0
- kafka/net/sasl/oauth.py +98 -0
- kafka/net/sasl/plain.py +42 -0
- kafka/net/sasl/scram.py +135 -0
- kafka/net/sasl/sspi.py +111 -0
- kafka/net/selector.py +644 -0
- kafka/net/socks5.py +262 -0
- kafka/net/transport.py +415 -0
- kafka/net/wakeup_notifier.py +72 -0
- kafka/partitioner/__init__.py +8 -0
- kafka/partitioner/abc.py +8 -0
- kafka/partitioner/default.py +89 -0
- kafka/partitioner/sticky.py +109 -0
- kafka/producer/__init__.py +5 -0
- kafka/producer/__main__.py +5 -0
- kafka/producer/future.py +101 -0
- kafka/producer/kafka.py +1123 -0
- kafka/producer/producer_batch.py +192 -0
- kafka/producer/record_accumulator.py +647 -0
- kafka/producer/sender.py +884 -0
- kafka/producer/transaction_manager.py +1326 -0
- kafka/protocol/__init__.py +0 -0
- kafka/protocol/admin/__init__.py +29 -0
- kafka/protocol/admin/acl.py +83 -0
- kafka/protocol/admin/acl.pyi +375 -0
- kafka/protocol/admin/client_quotas.py +14 -0
- kafka/protocol/admin/client_quotas.pyi +265 -0
- kafka/protocol/admin/cluster.py +31 -0
- kafka/protocol/admin/cluster.pyi +620 -0
- kafka/protocol/admin/configs.py +22 -0
- kafka/protocol/admin/configs.pyi +437 -0
- kafka/protocol/admin/groups.py +24 -0
- kafka/protocol/admin/groups.pyi +261 -0
- kafka/protocol/admin/topics.py +53 -0
- kafka/protocol/admin/topics.pyi +982 -0
- kafka/protocol/admin/transactions.py +18 -0
- kafka/protocol/admin/transactions.pyi +311 -0
- kafka/protocol/admin/users.py +14 -0
- kafka/protocol/admin/users.pyi +223 -0
- kafka/protocol/api_data.py +125 -0
- kafka/protocol/api_header.py +55 -0
- kafka/protocol/api_key.py +97 -0
- kafka/protocol/api_message.py +277 -0
- kafka/protocol/broker_version_data.py +246 -0
- kafka/protocol/consumer/__init__.py +13 -0
- kafka/protocol/consumer/fetch.py +16 -0
- kafka/protocol/consumer/fetch.pyi +298 -0
- kafka/protocol/consumer/group.py +38 -0
- kafka/protocol/consumer/group.pyi +824 -0
- kafka/protocol/consumer/metadata.py +30 -0
- kafka/protocol/consumer/metadata.pyi +89 -0
- kafka/protocol/consumer/offsets.py +75 -0
- kafka/protocol/consumer/offsets.pyi +288 -0
- kafka/protocol/data_container.py +166 -0
- kafka/protocol/frame.py +30 -0
- kafka/protocol/generate_stubs.py +468 -0
- kafka/protocol/metadata/__init__.py +10 -0
- kafka/protocol/metadata/api_versions.py +41 -0
- kafka/protocol/metadata/api_versions.pyi +128 -0
- kafka/protocol/metadata/find_coordinator.py +19 -0
- kafka/protocol/metadata/find_coordinator.pyi +105 -0
- kafka/protocol/metadata/metadata.py +34 -0
- kafka/protocol/metadata/metadata.pyi +160 -0
- kafka/protocol/old/__init__.py +0 -0
- kafka/protocol/old/abstract.py +17 -0
- kafka/protocol/old/add_offsets_to_txn.py +54 -0
- kafka/protocol/old/add_partitions_to_txn.py +71 -0
- kafka/protocol/old/admin.py +1086 -0
- kafka/protocol/old/api.py +205 -0
- kafka/protocol/old/api_versions.py +133 -0
- kafka/protocol/old/commit.py +355 -0
- kafka/protocol/old/consumer_protocol.py +36 -0
- kafka/protocol/old/end_txn.py +53 -0
- kafka/protocol/old/fetch.py +408 -0
- kafka/protocol/old/find_coordinator.py +72 -0
- kafka/protocol/old/group.py +451 -0
- kafka/protocol/old/init_producer_id.py +42 -0
- kafka/protocol/old/list_offsets.py +186 -0
- kafka/protocol/old/metadata.py +290 -0
- kafka/protocol/old/offset_for_leader_epoch.py +133 -0
- kafka/protocol/old/produce.py +247 -0
- kafka/protocol/old/sasl_authenticate.py +38 -0
- kafka/protocol/old/sasl_handshake.py +39 -0
- kafka/protocol/old/struct.py +87 -0
- kafka/protocol/old/txn_offset_commit.py +73 -0
- kafka/protocol/old/types.py +440 -0
- kafka/protocol/parser.py +191 -0
- kafka/protocol/producer/__init__.py +7 -0
- kafka/protocol/producer/produce.py +17 -0
- kafka/protocol/producer/produce.pyi +197 -0
- kafka/protocol/producer/transaction.py +30 -0
- kafka/protocol/producer/transaction.pyi +663 -0
- kafka/protocol/sasl.py +52 -0
- kafka/protocol/sasl.pyi +126 -0
- kafka/protocol/schemas/__init__.py +7 -0
- kafka/protocol/schemas/fields/__init__.py +7 -0
- kafka/protocol/schemas/fields/array.py +127 -0
- kafka/protocol/schemas/fields/base.py +156 -0
- kafka/protocol/schemas/fields/codecs/__init__.py +12 -0
- kafka/protocol/schemas/fields/codecs/encode_buffer.py +82 -0
- kafka/protocol/schemas/fields/codecs/tagged_fields.py +109 -0
- kafka/protocol/schemas/fields/codecs/types.py +505 -0
- kafka/protocol/schemas/fields/codegen.py +40 -0
- kafka/protocol/schemas/fields/simple.py +127 -0
- kafka/protocol/schemas/fields/struct.py +357 -0
- kafka/protocol/schemas/fields/struct_array.py +142 -0
- kafka/protocol/schemas/load_json.py +42 -0
- kafka/protocol/schemas/resources/AddOffsetsToTxnRequest.json +40 -0
- kafka/protocol/schemas/resources/AddOffsetsToTxnResponse.json +35 -0
- kafka/protocol/schemas/resources/AddPartitionsToTxnRequest.json +65 -0
- kafka/protocol/schemas/resources/AddPartitionsToTxnResponse.json +60 -0
- kafka/protocol/schemas/resources/AlterClientQuotasRequest.json +47 -0
- kafka/protocol/schemas/resources/AlterClientQuotasResponse.json +41 -0
- kafka/protocol/schemas/resources/AlterConfigsRequest.json +43 -0
- kafka/protocol/schemas/resources/AlterConfigsResponse.json +39 -0
- kafka/protocol/schemas/resources/AlterPartitionReassignmentsRequest.json +42 -0
- kafka/protocol/schemas/resources/AlterPartitionReassignmentsResponse.json +47 -0
- kafka/protocol/schemas/resources/AlterReplicaLogDirsRequest.json +41 -0
- kafka/protocol/schemas/resources/AlterReplicaLogDirsResponse.json +41 -0
- kafka/protocol/schemas/resources/AlterUserScramCredentialsRequest.json +45 -0
- kafka/protocol/schemas/resources/AlterUserScramCredentialsResponse.json +35 -0
- kafka/protocol/schemas/resources/ApiVersionsRequest.json +34 -0
- kafka/protocol/schemas/resources/ApiVersionsResponse.json +79 -0
- kafka/protocol/schemas/resources/ConsumerProtocolAssignment.json +42 -0
- kafka/protocol/schemas/resources/ConsumerProtocolSubscription.json +49 -0
- kafka/protocol/schemas/resources/CreateAclsRequest.json +46 -0
- kafka/protocol/schemas/resources/CreateAclsResponse.json +37 -0
- kafka/protocol/schemas/resources/CreatePartitionsRequest.json +47 -0
- kafka/protocol/schemas/resources/CreatePartitionsResponse.json +41 -0
- kafka/protocol/schemas/resources/CreateTopicsRequest.json +65 -0
- kafka/protocol/schemas/resources/CreateTopicsResponse.json +72 -0
- kafka/protocol/schemas/resources/DeleteAclsRequest.json +46 -0
- kafka/protocol/schemas/resources/DeleteAclsResponse.json +59 -0
- kafka/protocol/schemas/resources/DeleteGroupsRequest.json +30 -0
- kafka/protocol/schemas/resources/DeleteGroupsResponse.json +36 -0
- kafka/protocol/schemas/resources/DeleteRecordsRequest.json +42 -0
- kafka/protocol/schemas/resources/DeleteRecordsResponse.json +43 -0
- kafka/protocol/schemas/resources/DeleteTopicsRequest.json +43 -0
- kafka/protocol/schemas/resources/DeleteTopicsResponse.json +52 -0
- kafka/protocol/schemas/resources/DescribeAclsRequest.json +43 -0
- kafka/protocol/schemas/resources/DescribeAclsResponse.json +55 -0
- kafka/protocol/schemas/resources/DescribeClientQuotasRequest.json +37 -0
- kafka/protocol/schemas/resources/DescribeClientQuotasResponse.json +47 -0
- kafka/protocol/schemas/resources/DescribeClusterRequest.json +35 -0
- kafka/protocol/schemas/resources/DescribeClusterResponse.json +56 -0
- kafka/protocol/schemas/resources/DescribeConfigsRequest.json +42 -0
- kafka/protocol/schemas/resources/DescribeConfigsResponse.json +69 -0
- kafka/protocol/schemas/resources/DescribeGroupsRequest.json +38 -0
- kafka/protocol/schemas/resources/DescribeGroupsResponse.json +74 -0
- kafka/protocol/schemas/resources/DescribeLogDirsRequest.json +38 -0
- kafka/protocol/schemas/resources/DescribeLogDirsResponse.json +65 -0
- kafka/protocol/schemas/resources/DescribeProducersRequest.json +32 -0
- kafka/protocol/schemas/resources/DescribeProducersResponse.json +55 -0
- kafka/protocol/schemas/resources/DescribeQuorumRequest.json +39 -0
- kafka/protocol/schemas/resources/DescribeQuorumResponse.json +82 -0
- kafka/protocol/schemas/resources/DescribeTopicPartitionsRequest.json +40 -0
- kafka/protocol/schemas/resources/DescribeTopicPartitionsResponse.json +66 -0
- kafka/protocol/schemas/resources/DescribeTransactionsRequest.json +27 -0
- kafka/protocol/schemas/resources/DescribeTransactionsResponse.json +52 -0
- kafka/protocol/schemas/resources/DescribeUserScramCredentialsRequest.json +30 -0
- kafka/protocol/schemas/resources/DescribeUserScramCredentialsResponse.json +45 -0
- kafka/protocol/schemas/resources/ElectLeadersRequest.json +41 -0
- kafka/protocol/schemas/resources/ElectLeadersResponse.json +45 -0
- kafka/protocol/schemas/resources/EndTxnRequest.json +43 -0
- kafka/protocol/schemas/resources/EndTxnResponse.json +41 -0
- kafka/protocol/schemas/resources/FetchRequest.json +125 -0
- kafka/protocol/schemas/resources/FetchResponse.json +124 -0
- kafka/protocol/schemas/resources/FindCoordinatorRequest.json +43 -0
- kafka/protocol/schemas/resources/FindCoordinatorResponse.json +58 -0
- kafka/protocol/schemas/resources/HeartbeatRequest.json +39 -0
- kafka/protocol/schemas/resources/HeartbeatResponse.json +35 -0
- kafka/protocol/schemas/resources/IncrementalAlterConfigsRequest.json +44 -0
- kafka/protocol/schemas/resources/IncrementalAlterConfigsResponse.json +38 -0
- kafka/protocol/schemas/resources/InitProducerIdRequest.json +50 -0
- kafka/protocol/schemas/resources/InitProducerIdResponse.json +47 -0
- kafka/protocol/schemas/resources/JoinGroupRequest.json +63 -0
- kafka/protocol/schemas/resources/JoinGroupResponse.json +69 -0
- kafka/protocol/schemas/resources/LeaveGroupRequest.json +47 -0
- kafka/protocol/schemas/resources/LeaveGroupResponse.json +47 -0
- kafka/protocol/schemas/resources/ListConfigResourcesRequest.json +31 -0
- kafka/protocol/schemas/resources/ListConfigResourcesResponse.json +37 -0
- kafka/protocol/schemas/resources/ListGroupsRequest.json +36 -0
- kafka/protocol/schemas/resources/ListGroupsResponse.json +49 -0
- kafka/protocol/schemas/resources/ListOffsetsRequest.json +72 -0
- kafka/protocol/schemas/resources/ListOffsetsResponse.json +71 -0
- kafka/protocol/schemas/resources/ListPartitionReassignmentsRequest.json +34 -0
- kafka/protocol/schemas/resources/ListPartitionReassignmentsResponse.json +46 -0
- kafka/protocol/schemas/resources/ListTransactionsRequest.json +40 -0
- kafka/protocol/schemas/resources/ListTransactionsResponse.json +42 -0
- kafka/protocol/schemas/resources/MetadataRequest.json +56 -0
- kafka/protocol/schemas/resources/MetadataResponse.json +101 -0
- kafka/protocol/schemas/resources/OffsetCommitRequest.json +76 -0
- kafka/protocol/schemas/resources/OffsetCommitResponse.json +71 -0
- kafka/protocol/schemas/resources/OffsetDeleteRequest.json +39 -0
- kafka/protocol/schemas/resources/OffsetDeleteResponse.json +42 -0
- kafka/protocol/schemas/resources/OffsetFetchRequest.json +76 -0
- kafka/protocol/schemas/resources/OffsetFetchResponse.json +107 -0
- kafka/protocol/schemas/resources/OffsetForLeaderEpochRequest.json +52 -0
- kafka/protocol/schemas/resources/OffsetForLeaderEpochResponse.json +51 -0
- kafka/protocol/schemas/resources/ProduceRequest.json +73 -0
- kafka/protocol/schemas/resources/ProduceResponse.json +96 -0
- kafka/protocol/schemas/resources/RequestHeader.json +44 -0
- kafka/protocol/schemas/resources/ResponseHeader.json +26 -0
- kafka/protocol/schemas/resources/SaslAuthenticateRequest.json +29 -0
- kafka/protocol/schemas/resources/SaslAuthenticateResponse.json +34 -0
- kafka/protocol/schemas/resources/SaslHandshakeRequest.json +31 -0
- kafka/protocol/schemas/resources/SaslHandshakeResponse.json +32 -0
- kafka/protocol/schemas/resources/SyncGroupRequest.json +56 -0
- kafka/protocol/schemas/resources/SyncGroupResponse.json +46 -0
- kafka/protocol/schemas/resources/TxnOffsetCommitRequest.json +68 -0
- kafka/protocol/schemas/resources/TxnOffsetCommitResponse.json +47 -0
- kafka/protocol/schemas/resources/UpdateFeaturesRequest.json +43 -0
- kafka/protocol/schemas/resources/UpdateFeaturesResponse.json +39 -0
- kafka/protocol/schemas/resources/WriteTxnMarkersRequest.json +49 -0
- kafka/protocol/schemas/resources/WriteTxnMarkersResponse.json +45 -0
- kafka/protocol/schemas/resources/__init__.py +0 -0
- kafka/record/__init__.py +3 -0
- kafka/record/_crc32c.py +161 -0
- kafka/record/abc.py +144 -0
- kafka/record/default_records.py +782 -0
- kafka/record/legacy_records.py +587 -0
- kafka/record/memory_records.py +255 -0
- kafka/record/util.py +135 -0
- kafka/serializer/__init__.py +4 -0
- kafka/serializer/abstract.py +20 -0
- kafka/serializer/default.py +16 -0
- kafka/serializer/json.py +17 -0
- kafka/serializer/wrapper.py +21 -0
- kafka/structs.py +69 -0
- kafka/util.py +159 -0
- kafka/vendor/__init__.py +0 -0
- kafka/version.py +1 -0
- kafka_python-3.0.0.dist-info/METADATA +319 -0
- kafka_python-3.0.0.dist-info/RECORD +373 -0
- kafka_python-3.0.0.dist-info/WHEEL +5 -0
- kafka_python-3.0.0.dist-info/entry_points.txt +2 -0
- kafka_python-3.0.0.dist-info/licenses/LICENSE +202 -0
- kafka_python-3.0.0.dist-info/top_level.txt +1 -0
kafka/__init__.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
__title__ = 'kafka'
|
|
2
|
+
from kafka.version import __version__
|
|
3
|
+
__author__ = 'Dana Powers'
|
|
4
|
+
__license__ = 'Apache License 2.0'
|
|
5
|
+
__copyright__ = 'Copyright 2026 Dana Powers, David Arthur, and Contributors'
|
|
6
|
+
|
|
7
|
+
# Set default logging handler to avoid "No handler found" warnings.
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
from kafka.admin import KafkaAdminClient
|
|
14
|
+
from kafka.consumer import KafkaConsumer
|
|
15
|
+
from kafka.consumer.subscription_state import (
|
|
16
|
+
AsyncConsumerRebalanceListener, ConsumerRebalanceListener,
|
|
17
|
+
)
|
|
18
|
+
from kafka.producer import KafkaProducer
|
|
19
|
+
from kafka.serializer import DefaultSerializer, JsonSerializer, Serializer, Deserializer
|
|
20
|
+
from kafka.structs import (
|
|
21
|
+
ConsumerGroupMetadata, OffsetAndMetadata,
|
|
22
|
+
TopicPartition, TopicPartitionReplica,
|
|
23
|
+
)
|
|
24
|
+
from kafka.protocol.consumer import IsolationLevel, OffsetSpec
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
'KafkaAdminClient', 'KafkaConsumer', 'KafkaProducer',
|
|
29
|
+
'AsyncConsumerRebalanceListener', 'ConsumerRebalanceListener',
|
|
30
|
+
'DefaultSerializer', 'JsonSerializer', 'Serializer', 'Deserializer',
|
|
31
|
+
'ConsumerGroupMetadata', 'OffsetAndMetadata',
|
|
32
|
+
'TopicPartition', 'TopicPartitionReplica',
|
|
33
|
+
'IsolationLevel', 'OffsetSpec',
|
|
34
|
+
]
|
kafka/__main__.py
ADDED
kafka/admin/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from kafka.admin.client import KafkaAdminClient
|
|
2
|
+
from kafka.admin._acls import (
|
|
3
|
+
ACL, ACLFilter, ResourcePattern, ResourcePatternFilter, ACLOperation,
|
|
4
|
+
ResourceType, ACLPermissionType, ACLResourcePatternType)
|
|
5
|
+
from kafka.admin._cluster import UpdateFeatureType
|
|
6
|
+
from kafka.admin._configs import (
|
|
7
|
+
AlterConfigOp, ConfigFilterType, ConfigResource, ConfigResourceType,
|
|
8
|
+
ConfigType, ConfigSourceType)
|
|
9
|
+
from kafka.admin._groups import GroupState, GroupType, MemberToRemove
|
|
10
|
+
from kafka.admin._partitions import NewPartitions, OffsetSpec, OffsetTimestamp
|
|
11
|
+
from kafka.admin._topics import NewTopic
|
|
12
|
+
from kafka.admin._transactions import (
|
|
13
|
+
AbortTransactionSpec, PartitionProducerState, ProducerState,
|
|
14
|
+
TransactionDescription, TransactionListing, TransactionState)
|
|
15
|
+
from kafka.admin._users import (
|
|
16
|
+
ScramMechanism, UserScramCredentialDeletion, UserScramCredentialUpsertion)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
'KafkaAdminClient',
|
|
20
|
+
'ACL', 'ACLFilter', 'ACLOperation', 'ACLPermissionType', 'ACLResourcePatternType',
|
|
21
|
+
'ResourceType', 'ResourcePattern', 'ResourcePatternFilter',
|
|
22
|
+
'AlterConfigOp', 'ConfigResource', 'ConfigResourceType', 'ConfigType', 'ConfigSourceType',
|
|
23
|
+
'UpdateFeatureType',
|
|
24
|
+
'GroupState', 'GroupType', 'MemberToRemove',
|
|
25
|
+
'OffsetSpec', 'OffsetTimestamp', # NewTopic + NewPartitions are deprecated and not included in __all__
|
|
26
|
+
'AbortTransactionSpec', 'PartitionProducerState', 'ProducerState',
|
|
27
|
+
'TransactionDescription', 'TransactionListing', 'TransactionState',
|
|
28
|
+
'ScramMechanism', 'UserScramCredentialDeletion', 'UserScramCredentialUpsertion',
|
|
29
|
+
]
|
kafka/admin/__main__.py
ADDED
kafka/admin/_acls.py
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"""ACL management mixin for KafkaAdminClient.
|
|
2
|
+
|
|
3
|
+
Also defines ACL data types: ResourceType, ACLOperation, ACLPermissionType,
|
|
4
|
+
ACLResourcePatternType, ACLFilter, ACL, ResourcePatternFilter, ResourcePattern.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from enum import IntEnum
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
import kafka.errors as Errors
|
|
14
|
+
from kafka.errors import IllegalArgumentError
|
|
15
|
+
from kafka.protocol.admin import CreateAclsRequest, DeleteAclsRequest, DescribeAclsRequest
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from kafka.net.manager import KafkaConnectionManager
|
|
19
|
+
|
|
20
|
+
log = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ACLAdminMixin:
|
|
24
|
+
"""Mixin providing ACL management methods for KafkaAdminClient."""
|
|
25
|
+
_manager: KafkaConnectionManager
|
|
26
|
+
config: dict
|
|
27
|
+
|
|
28
|
+
# ACL Helper for Metadata / DescribeGroups
|
|
29
|
+
def _process_acl_operations(self, obj):
|
|
30
|
+
if obj.get('authorized_operations', None) is not None:
|
|
31
|
+
obj['authorized_operations'] = list(map(lambda acl: acl.name, valid_acl_operations(obj['authorized_operations'])))
|
|
32
|
+
return obj
|
|
33
|
+
|
|
34
|
+
def describe_acls(self, acl_filter):
|
|
35
|
+
"""Describe a set of ACLs
|
|
36
|
+
|
|
37
|
+
Used to return a set of ACLs matching the supplied ACLFilter.
|
|
38
|
+
The cluster must be configured with an authorizer for this to work, or
|
|
39
|
+
you will get a SecurityDisabledError
|
|
40
|
+
|
|
41
|
+
Arguments:
|
|
42
|
+
acl_filter: an ACLFilter object
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
tuple of a list of matching ACL objects and a KafkaError (NoError if successful)
|
|
46
|
+
"""
|
|
47
|
+
min_version = 3 if acl_filter.resource_pattern.resource_type == ResourceType.USER else 0
|
|
48
|
+
request = DescribeAclsRequest(
|
|
49
|
+
min_version=min_version,
|
|
50
|
+
resource_type_filter=acl_filter.resource_pattern.resource_type,
|
|
51
|
+
resource_name_filter=acl_filter.resource_pattern.resource_name,
|
|
52
|
+
pattern_type_filter=acl_filter.resource_pattern.pattern_type,
|
|
53
|
+
principal_filter=acl_filter.principal,
|
|
54
|
+
host_filter=acl_filter.host,
|
|
55
|
+
operation=acl_filter.operation,
|
|
56
|
+
permission_type=acl_filter.permission_type
|
|
57
|
+
)
|
|
58
|
+
response = self._manager.run(self._manager.send, request)
|
|
59
|
+
return self._convert_describe_acls_response_to_acls(response)
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def _convert_describe_acls_response_to_acls(describe_response):
|
|
63
|
+
"""Convert a DescribeAclsResponse into a list of ACL objects and a KafkaError.
|
|
64
|
+
|
|
65
|
+
Arguments:
|
|
66
|
+
describe_response: The response object from the DescribeAclsRequest.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
A tuple of (list_of_acl_objects, error) where error is an instance
|
|
70
|
+
of KafkaError (NoError if successful).
|
|
71
|
+
"""
|
|
72
|
+
error_type = Errors.for_code(describe_response.error_code)
|
|
73
|
+
if error_type is not Errors.NoError:
|
|
74
|
+
raise error_type(describe_response.error_message)
|
|
75
|
+
acl_list = []
|
|
76
|
+
for resource in describe_response.resources:
|
|
77
|
+
for acl in resource.acls:
|
|
78
|
+
acl_list.append(
|
|
79
|
+
ACL(
|
|
80
|
+
principal=acl.principal,
|
|
81
|
+
host=acl.host,
|
|
82
|
+
operation=ACLOperation(acl.operation),
|
|
83
|
+
permission_type=ACLPermissionType(acl.permission_type),
|
|
84
|
+
resource_pattern=ResourcePattern(
|
|
85
|
+
resource_type=ResourceType(resource.resource_type),
|
|
86
|
+
resource_name=resource.resource_name,
|
|
87
|
+
pattern_type=ACLResourcePatternType(resource.pattern_type))))
|
|
88
|
+
return acl_list, Errors.NoError
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def _convert_create_acls_resource_request(acl):
|
|
92
|
+
"""Convert an ACL object into the CreateAclsRequest format."""
|
|
93
|
+
_AclCreate = CreateAclsRequest.AclCreation
|
|
94
|
+
return _AclCreate(
|
|
95
|
+
resource_type=acl.resource_pattern.resource_type,
|
|
96
|
+
resource_name=acl.resource_pattern.resource_name,
|
|
97
|
+
resource_pattern_type=acl.resource_pattern.pattern_type,
|
|
98
|
+
principal=acl.principal,
|
|
99
|
+
host=acl.host,
|
|
100
|
+
operation=acl.operation,
|
|
101
|
+
permission_type=acl.permission_type
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def _convert_create_acls_response_to_acls(acls, create_response):
|
|
106
|
+
"""Parse a CreateAclsResponse, returning a dict of successes and failures."""
|
|
107
|
+
results = {'succeeded': [], 'failed': []}
|
|
108
|
+
for i, result in enumerate(create_response.results):
|
|
109
|
+
acl = acls[i]
|
|
110
|
+
if result.error_code == 0:
|
|
111
|
+
results['succeeded'].append(acl)
|
|
112
|
+
else:
|
|
113
|
+
results['failed'].append(Errors.for_code(result.error_code))
|
|
114
|
+
return results
|
|
115
|
+
|
|
116
|
+
def create_acls(self, acls):
|
|
117
|
+
"""Create a list of ACLs
|
|
118
|
+
|
|
119
|
+
This endpoint only accepts a list of concrete ACL objects, no ACLFilters.
|
|
120
|
+
Throws TopicAlreadyExistsError if topic is already present.
|
|
121
|
+
|
|
122
|
+
Arguments:
|
|
123
|
+
acls: a list of ACL objects
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
dict of successes and failures
|
|
127
|
+
"""
|
|
128
|
+
for acl in acls:
|
|
129
|
+
if not isinstance(acl, ACL):
|
|
130
|
+
raise IllegalArgumentError("acls must contain ACL objects")
|
|
131
|
+
|
|
132
|
+
creations = [self._convert_create_acls_resource_request(acl) for acl in acls]
|
|
133
|
+
min_version = 3 if any(creation.resource_type == ResourceType.USER for creation in creations) else 0
|
|
134
|
+
request = CreateAclsRequest(creations=creations, min_version=min_version)
|
|
135
|
+
response = self._manager.run(self._manager.send, request)
|
|
136
|
+
return self._convert_create_acls_response_to_acls(acls, response)
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _convert_delete_acls_resource_request(acl):
|
|
140
|
+
"""Convert an ACLFilter object into the DeleteAclsRequest format."""
|
|
141
|
+
_AclsFilter = DeleteAclsRequest.DeleteAclsFilter
|
|
142
|
+
return _AclsFilter(
|
|
143
|
+
resource_type_filter=acl.resource_pattern.resource_type,
|
|
144
|
+
resource_name_filter=acl.resource_pattern.resource_name,
|
|
145
|
+
pattern_type_filter=acl.resource_pattern.pattern_type,
|
|
146
|
+
principal_filter=acl.principal,
|
|
147
|
+
host_filter=acl.host,
|
|
148
|
+
operation=acl.operation,
|
|
149
|
+
permission_type=acl.permission_type
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
@staticmethod
|
|
153
|
+
def _convert_delete_acls_response_to_matching_acls(acl_filters, delete_response):
|
|
154
|
+
"""Parse a DeleteAclsResponse, returning a list of (filter, matched ACLs, error) tuples."""
|
|
155
|
+
results = []
|
|
156
|
+
for i, result in enumerate(delete_response.filter_results):
|
|
157
|
+
acl_filter = acl_filters[i]
|
|
158
|
+
error_type = Errors.for_code(result.error_code)
|
|
159
|
+
matching_acls = []
|
|
160
|
+
for acl in result.matching_acls:
|
|
161
|
+
error = Errors.for_code(acl.error_code)
|
|
162
|
+
matching_acls.append(
|
|
163
|
+
ACL(
|
|
164
|
+
principal=acl.principal,
|
|
165
|
+
host=acl.host,
|
|
166
|
+
operation=ACLOperation(acl.operation),
|
|
167
|
+
permission_type=ACLPermissionType(acl.permission_type),
|
|
168
|
+
resource_pattern=ResourcePattern(
|
|
169
|
+
resource_type=ResourceType(acl.resource_type),
|
|
170
|
+
resource_name=acl.resource_name,
|
|
171
|
+
pattern_type=ACLResourcePatternType(acl.pattern_type))))
|
|
172
|
+
results.append((acl_filter, matching_acls, error_type))
|
|
173
|
+
return results
|
|
174
|
+
|
|
175
|
+
def delete_acls(self, acl_filters):
|
|
176
|
+
"""Delete a set of ACLs
|
|
177
|
+
|
|
178
|
+
Deletes all ACLs matching the list of input ACLFilter
|
|
179
|
+
|
|
180
|
+
Arguments:
|
|
181
|
+
acl_filters: a list of ACLFilter
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
a list of 3-tuples corresponding to the list of input filters.
|
|
185
|
+
The tuples hold (the input ACLFilter, list of affected ACLs, KafkaError instance)
|
|
186
|
+
"""
|
|
187
|
+
for acl in acl_filters:
|
|
188
|
+
if not isinstance(acl, ACLFilter):
|
|
189
|
+
raise IllegalArgumentError("acl_filters must contain ACLFilter type objects")
|
|
190
|
+
|
|
191
|
+
filters = [self._convert_delete_acls_resource_request(acl) for acl in acl_filters]
|
|
192
|
+
min_version = 3 if any(_filter.resource_type_filter == ResourceType.USER for _filter in filters) else 0
|
|
193
|
+
request = DeleteAclsRequest(filters=filters, min_version=min_version)
|
|
194
|
+
response = self._manager.run(self._manager.send, request)
|
|
195
|
+
return self._convert_delete_acls_response_to_matching_acls(acl_filters, response)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# ---------------------------------------------------------------------------
|
|
199
|
+
# ACL data types
|
|
200
|
+
# ---------------------------------------------------------------------------
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class ResourceType(IntEnum):
|
|
204
|
+
"""Type of kafka resource to set ACL for.
|
|
205
|
+
|
|
206
|
+
The ANY value is only valid in a filter context.
|
|
207
|
+
"""
|
|
208
|
+
UNKNOWN = 0
|
|
209
|
+
ANY = 1
|
|
210
|
+
TOPIC = 2
|
|
211
|
+
GROUP = 3
|
|
212
|
+
CLUSTER = 4
|
|
213
|
+
TRANSACTIONAL_ID = 5
|
|
214
|
+
DELEGATION_TOKEN = 6
|
|
215
|
+
USER = 7
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class ACLOperation(IntEnum):
|
|
219
|
+
"""Type of operation.
|
|
220
|
+
|
|
221
|
+
The ANY value is only valid in a filter context.
|
|
222
|
+
"""
|
|
223
|
+
UNKNOWN = 0
|
|
224
|
+
ANY = 1
|
|
225
|
+
ALL = 2
|
|
226
|
+
READ = 3
|
|
227
|
+
WRITE = 4
|
|
228
|
+
CREATE = 5
|
|
229
|
+
DELETE = 6
|
|
230
|
+
ALTER = 7
|
|
231
|
+
DESCRIBE = 8
|
|
232
|
+
CLUSTER_ACTION = 9
|
|
233
|
+
DESCRIBE_CONFIGS = 10
|
|
234
|
+
ALTER_CONFIGS = 11
|
|
235
|
+
IDEMPOTENT_WRITE = 12
|
|
236
|
+
CREATE_TOKENS = 13
|
|
237
|
+
DESCRIBE_TOKENS = 14
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class ACLPermissionType(IntEnum):
|
|
241
|
+
"""An enumerated type of permissions.
|
|
242
|
+
|
|
243
|
+
The ANY value is only valid in a filter context.
|
|
244
|
+
"""
|
|
245
|
+
UNKNOWN = 0
|
|
246
|
+
ANY = 1
|
|
247
|
+
DENY = 2
|
|
248
|
+
ALLOW = 3
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class ACLResourcePatternType(IntEnum):
|
|
252
|
+
"""An enumerated type of resource patterns.
|
|
253
|
+
|
|
254
|
+
More details on the pattern types and how they work
|
|
255
|
+
can be found in KIP-290 (Support for prefixed ACLs).
|
|
256
|
+
"""
|
|
257
|
+
UNKNOWN = 0
|
|
258
|
+
ANY = 1
|
|
259
|
+
MATCH = 2
|
|
260
|
+
LITERAL = 3
|
|
261
|
+
PREFIXED = 4
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class ResourcePatternFilter:
|
|
265
|
+
def __init__(self, resource_type, resource_name, pattern_type):
|
|
266
|
+
self.resource_type = resource_type
|
|
267
|
+
self.resource_name = resource_name
|
|
268
|
+
self.pattern_type = pattern_type
|
|
269
|
+
self.validate()
|
|
270
|
+
|
|
271
|
+
def validate(self):
|
|
272
|
+
if not isinstance(self.resource_type, ResourceType):
|
|
273
|
+
raise IllegalArgumentError("resource_type must be a ResourceType object")
|
|
274
|
+
if not isinstance(self.pattern_type, ACLResourcePatternType):
|
|
275
|
+
raise IllegalArgumentError("pattern_type must be an ACLResourcePatternType object")
|
|
276
|
+
|
|
277
|
+
def __repr__(self):
|
|
278
|
+
return "<ResourcePattern type={}, name={}, pattern={}>".format(
|
|
279
|
+
self.resource_type.name, self.resource_name, self.pattern_type.name)
|
|
280
|
+
|
|
281
|
+
def __eq__(self, other):
|
|
282
|
+
return all((
|
|
283
|
+
self.resource_type == other.resource_type,
|
|
284
|
+
self.resource_name == other.resource_name,
|
|
285
|
+
self.pattern_type == other.pattern_type,
|
|
286
|
+
))
|
|
287
|
+
|
|
288
|
+
def __hash__(self):
|
|
289
|
+
return hash((self.resource_type, self.resource_name, self.pattern_type))
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class ResourcePattern(ResourcePatternFilter):
|
|
293
|
+
"""A resource pattern to apply the ACL to."""
|
|
294
|
+
def __init__(self, resource_type, resource_name, pattern_type=ACLResourcePatternType.LITERAL):
|
|
295
|
+
super().__init__(resource_type, resource_name, pattern_type)
|
|
296
|
+
self.validate()
|
|
297
|
+
|
|
298
|
+
def validate(self):
|
|
299
|
+
if self.resource_type == ResourceType.ANY:
|
|
300
|
+
raise IllegalArgumentError("resource_type cannot be ANY")
|
|
301
|
+
if self.pattern_type in [ACLResourcePatternType.ANY, ACLResourcePatternType.MATCH]:
|
|
302
|
+
raise IllegalArgumentError(
|
|
303
|
+
"pattern_type cannot be {} on a concrete ResourcePattern".format(self.pattern_type.name))
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class ACLFilter:
|
|
307
|
+
"""Represents a filter to use with describing and deleting ACLs."""
|
|
308
|
+
def __init__(self, principal, host, operation, permission_type, resource_pattern):
|
|
309
|
+
self.principal = principal
|
|
310
|
+
self.host = host
|
|
311
|
+
self.operation = operation
|
|
312
|
+
self.permission_type = permission_type
|
|
313
|
+
self.resource_pattern = resource_pattern
|
|
314
|
+
self.validate()
|
|
315
|
+
|
|
316
|
+
def validate(self):
|
|
317
|
+
if not isinstance(self.operation, ACLOperation):
|
|
318
|
+
raise IllegalArgumentError("operation must be an ACLOperation object, and cannot be ANY")
|
|
319
|
+
if not isinstance(self.permission_type, ACLPermissionType):
|
|
320
|
+
raise IllegalArgumentError("permission_type must be an ACLPermissionType object, and cannot be ANY")
|
|
321
|
+
if not isinstance(self.resource_pattern, ResourcePatternFilter):
|
|
322
|
+
raise IllegalArgumentError("resource_pattern must be a ResourcePatternFilter object")
|
|
323
|
+
|
|
324
|
+
def __repr__(self):
|
|
325
|
+
return "<ACL principal={principal}, resource={resource}, operation={operation}, type={type}, host={host}>".format(
|
|
326
|
+
principal=self.principal, host=self.host, operation=self.operation.name,
|
|
327
|
+
type=self.permission_type.name, resource=self.resource_pattern)
|
|
328
|
+
|
|
329
|
+
def __eq__(self, other):
|
|
330
|
+
return all((
|
|
331
|
+
self.principal == other.principal, self.host == other.host,
|
|
332
|
+
self.operation == other.operation, self.permission_type == other.permission_type,
|
|
333
|
+
self.resource_pattern == other.resource_pattern))
|
|
334
|
+
|
|
335
|
+
def __hash__(self):
|
|
336
|
+
return hash((self.principal, self.host, self.operation, self.permission_type, self.resource_pattern))
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class ACL(ACLFilter):
|
|
340
|
+
"""Represents a concrete ACL for a specific ResourcePattern."""
|
|
341
|
+
def __init__(self, principal, host, operation, permission_type, resource_pattern):
|
|
342
|
+
super().__init__(principal, host, operation, permission_type, resource_pattern)
|
|
343
|
+
self.validate()
|
|
344
|
+
|
|
345
|
+
def validate(self):
|
|
346
|
+
if self.operation == ACLOperation.ANY:
|
|
347
|
+
raise IllegalArgumentError("operation cannot be ANY")
|
|
348
|
+
if self.permission_type == ACLPermissionType.ANY:
|
|
349
|
+
raise IllegalArgumentError("permission_type cannot be ANY")
|
|
350
|
+
if not isinstance(self.resource_pattern, ResourcePattern):
|
|
351
|
+
raise IllegalArgumentError("resource_pattern must be a ResourcePattern object")
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def valid_acl_operations(int_vals):
|
|
355
|
+
return set([ACLOperation(v) for v in int_vals if v not in (0, 1, 2)])
|