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/admin/_cluster.py
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"""Cluster metadata mixin for KafkaAdminClient."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from enum import IntEnum
|
|
7
|
+
import logging
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
import uuid
|
|
10
|
+
|
|
11
|
+
import kafka.errors as Errors
|
|
12
|
+
from kafka.protocol.api_key import ApiKey
|
|
13
|
+
from kafka.protocol.metadata import ApiVersionsRequest, MetadataRequest
|
|
14
|
+
from kafka.protocol.admin import (
|
|
15
|
+
AlterReplicaLogDirsRequest,
|
|
16
|
+
DescribeClusterRequest,
|
|
17
|
+
DescribeLogDirsRequest,
|
|
18
|
+
DescribeQuorumRequest,
|
|
19
|
+
UpdateFeaturesRequest,
|
|
20
|
+
)
|
|
21
|
+
from kafka.structs import TopicPartitionReplica
|
|
22
|
+
from kafka.util import EnumHelper
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from kafka.net.manager import KafkaConnectionManager
|
|
26
|
+
|
|
27
|
+
log = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ClusterAdminMixin:
|
|
31
|
+
"""Mixin providing cluster management methods for KafkaAdminClient."""
|
|
32
|
+
_manager: KafkaConnectionManager
|
|
33
|
+
|
|
34
|
+
async def _get_cluster_metadata(self, topics):
|
|
35
|
+
"""topics = [] for no topics, None for all. Items may be topic-name
|
|
36
|
+
strings or :class:`uuid.UUID` topic ids (KIP-516, requires broker
|
|
37
|
+
>= 2.8 / MetadataRequest v12+)."""
|
|
38
|
+
_Topic = MetadataRequest.MetadataRequestTopic
|
|
39
|
+
if topics is None:
|
|
40
|
+
request_topics = None
|
|
41
|
+
else:
|
|
42
|
+
request_topics = [
|
|
43
|
+
_Topic(name=None, topic_id=t) if isinstance(t, uuid.UUID)
|
|
44
|
+
else _Topic(name=t)
|
|
45
|
+
for t in topics
|
|
46
|
+
]
|
|
47
|
+
request = MetadataRequest(
|
|
48
|
+
topics=request_topics,
|
|
49
|
+
allow_auto_topic_creation=False,
|
|
50
|
+
include_cluster_authorized_operations=True,
|
|
51
|
+
include_topic_authorized_operations=True,
|
|
52
|
+
)
|
|
53
|
+
response = await self._manager.send(request)
|
|
54
|
+
metadata = response.to_dict()
|
|
55
|
+
self._process_acl_operations(metadata)
|
|
56
|
+
for topic in metadata['topics']:
|
|
57
|
+
self._process_acl_operations(topic)
|
|
58
|
+
return metadata
|
|
59
|
+
|
|
60
|
+
async def _describe_cluster(self):
|
|
61
|
+
try:
|
|
62
|
+
request = DescribeClusterRequest(
|
|
63
|
+
include_cluster_authorized_operations=True,
|
|
64
|
+
include_fenced_brokers=True,
|
|
65
|
+
)
|
|
66
|
+
response = await self._manager.send(request)
|
|
67
|
+
error_type = Errors.for_code(response.error_code)
|
|
68
|
+
if error_type is not Errors.NoError:
|
|
69
|
+
raise error_type(response.error_message)
|
|
70
|
+
metadata = response.to_dict()
|
|
71
|
+
metadata.pop('error_code')
|
|
72
|
+
metadata.pop('error_message')
|
|
73
|
+
metadata.pop('endpoint_type')
|
|
74
|
+
metadata.pop('throttle_time_ms', None)
|
|
75
|
+
self._process_acl_operations(metadata)
|
|
76
|
+
return metadata
|
|
77
|
+
|
|
78
|
+
except Errors.IncompatibleBrokerVersion:
|
|
79
|
+
# On older brokers fallback to MetadataRequest w/o topics
|
|
80
|
+
metadata = await self._get_cluster_metadata([])
|
|
81
|
+
metadata.pop('topics')
|
|
82
|
+
metadata.pop('throttle_time_ms', None)
|
|
83
|
+
for broker in metadata['brokers']:
|
|
84
|
+
broker['broker_id'] = broker.pop('node_id')
|
|
85
|
+
return metadata
|
|
86
|
+
|
|
87
|
+
def describe_cluster(self):
|
|
88
|
+
"""Fetch cluster-wide metadata such as the list of brokers, the controller ID,
|
|
89
|
+
and the cluster ID.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
A dict with cluster-wide metadata, excluding topic details.
|
|
93
|
+
"""
|
|
94
|
+
return self._manager.run(self._describe_cluster)
|
|
95
|
+
|
|
96
|
+
async def _async_describe_log_dirs(self, topic_partitions=(), brokers=None):
|
|
97
|
+
request = DescribeLogDirsRequest(topics=topic_partitions)
|
|
98
|
+
responses = []
|
|
99
|
+
if brokers is None:
|
|
100
|
+
brokers = [broker.node_id for broker in self._manager.cluster.brokers()]
|
|
101
|
+
for node_id in brokers:
|
|
102
|
+
response = await self._manager.send(request, node_id=node_id)
|
|
103
|
+
responses.append({"broker": node_id, "log_dirs": [result.to_dict() for result in response.results]})
|
|
104
|
+
return responses
|
|
105
|
+
|
|
106
|
+
def describe_log_dirs(self, topic_partitions=None, brokers=None):
|
|
107
|
+
"""Fetch broker log directory and topic/partition stats
|
|
108
|
+
|
|
109
|
+
Keyword Arguments:
|
|
110
|
+
topic_partitions (dict, list, optional):
|
|
111
|
+
Either: dict of {topic_name: [partition ids]}.
|
|
112
|
+
Or: list of [topic_name], to query all partitions for topic.
|
|
113
|
+
Or: None, to query all topics / all partitions.
|
|
114
|
+
Default: None
|
|
115
|
+
brokers (list, optional): List of [node_id] for brokers to query.
|
|
116
|
+
If None, query is sent to all brokers. Default: None
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
list of dicts, containing per-broker log-dir data
|
|
120
|
+
"""
|
|
121
|
+
topic_partitions = self._get_topic_partitions(topic_partitions)
|
|
122
|
+
return self._manager.run(self._async_describe_log_dirs, topic_partitions, brokers)
|
|
123
|
+
|
|
124
|
+
@staticmethod
|
|
125
|
+
def _alter_replica_log_dirs_requests(replica_assignments):
|
|
126
|
+
_Dir = AlterReplicaLogDirsRequest.AlterReplicaLogDir
|
|
127
|
+
_Topic = _Dir.AlterReplicaLogDirTopic
|
|
128
|
+
broker_to_dirs = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
|
|
129
|
+
for tpr, log_dir in replica_assignments.items():
|
|
130
|
+
if not isinstance(tpr, TopicPartitionReplica):
|
|
131
|
+
tpr = TopicPartitionReplica(*tpr)
|
|
132
|
+
broker_to_dirs[tpr.broker_id][log_dir][tpr.topic].append(tpr.partition)
|
|
133
|
+
return {
|
|
134
|
+
broker_id: AlterReplicaLogDirsRequest(dirs=[
|
|
135
|
+
_Dir(path=path, topics=[
|
|
136
|
+
_Topic(name=topic, partitions=parts)
|
|
137
|
+
for topic, parts in topics.items()
|
|
138
|
+
])
|
|
139
|
+
for path, topics in dirs.items()
|
|
140
|
+
])
|
|
141
|
+
for broker_id, dirs in broker_to_dirs.items()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async def _async_alter_replica_log_dirs(self, replica_assignments):
|
|
145
|
+
if not replica_assignments:
|
|
146
|
+
return {}
|
|
147
|
+
broker_requests = self._alter_replica_log_dirs_requests(replica_assignments)
|
|
148
|
+
result = {}
|
|
149
|
+
for broker_id, request in broker_requests.items():
|
|
150
|
+
response = await self._manager.send(request, node_id=broker_id)
|
|
151
|
+
for topic in response.results:
|
|
152
|
+
for partition in topic.partitions:
|
|
153
|
+
tpr = TopicPartitionReplica(
|
|
154
|
+
topic=topic.topic_name,
|
|
155
|
+
partition=partition.partition_index,
|
|
156
|
+
broker_id=broker_id)
|
|
157
|
+
result[tpr] = Errors.for_code(partition.error_code)
|
|
158
|
+
return result
|
|
159
|
+
|
|
160
|
+
def alter_replica_log_dirs(self, replica_assignments):
|
|
161
|
+
"""Move replicas between log directories on their hosting brokers.
|
|
162
|
+
|
|
163
|
+
Each entry instructs the targeted broker to move (or place) the
|
|
164
|
+
replica for a given partition into the specified absolute log
|
|
165
|
+
directory path. Requests are sent to each broker in parallel; a
|
|
166
|
+
broker will only act on replicas it currently hosts.
|
|
167
|
+
|
|
168
|
+
Arguments:
|
|
169
|
+
replica_assignments: A dict mapping
|
|
170
|
+
:class:`~kafka.TopicPartitionReplica` (``topic``,
|
|
171
|
+
``partition``, ``broker_id``) to the destination log
|
|
172
|
+
directory path (absolute string). Tuples of
|
|
173
|
+
``(topic, partition, broker_id)`` are also accepted.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
dict mapping :class:`~kafka.TopicPartitionReplica` to the
|
|
177
|
+
corresponding error class (``kafka.errors.NoError`` on success).
|
|
178
|
+
"""
|
|
179
|
+
return self._manager.run(self._async_alter_replica_log_dirs, replica_assignments)
|
|
180
|
+
|
|
181
|
+
async def _async_describe_quorum(self, topic, partition):
|
|
182
|
+
_Topic = DescribeQuorumRequest.TopicData
|
|
183
|
+
_Partition = _Topic.PartitionData
|
|
184
|
+
request = DescribeQuorumRequest(topics=[
|
|
185
|
+
_Topic(topic_name=topic, partitions=[_Partition(partition_index=partition)])
|
|
186
|
+
])
|
|
187
|
+
response = await self._manager.send(request)
|
|
188
|
+
top_error = Errors.for_code(response.error_code)
|
|
189
|
+
if top_error is not Errors.NoError:
|
|
190
|
+
raise top_error(response.error_message or '')
|
|
191
|
+
result = response.to_dict()
|
|
192
|
+
result.pop('throttle_time_ms', None)
|
|
193
|
+
result.pop('error_code', None)
|
|
194
|
+
result.pop('error_message', None)
|
|
195
|
+
for topic in result['topics']:
|
|
196
|
+
for partition in topic['partitions']:
|
|
197
|
+
error = Errors.for_code(partition.pop('error_code'))(partition.pop('error_message'))
|
|
198
|
+
if not isinstance(error, Errors.NoError):
|
|
199
|
+
partition['error'] = str(error)
|
|
200
|
+
else:
|
|
201
|
+
partition['error'] = None
|
|
202
|
+
return result
|
|
203
|
+
|
|
204
|
+
def describe_metadata_quorum(self):
|
|
205
|
+
"""Describe the KRaft quorum state for the cluster metadata log.
|
|
206
|
+
|
|
207
|
+
Returns quorum info for the ``__cluster_metadata`` topic
|
|
208
|
+
(partition 0), including the current leader, leader epoch, high
|
|
209
|
+
watermark, voters, and observers. On broker version >= 3.8 (KIP-853),
|
|
210
|
+
the response also reports controller node endpoints in ``nodes``.
|
|
211
|
+
Requires a KRaft cluster.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
dict matching the DescribeQuorumResponse shape.
|
|
215
|
+
"""
|
|
216
|
+
return self._manager.run(self._async_describe_quorum, '__cluster_metadata', 0)
|
|
217
|
+
|
|
218
|
+
async def _async_get_broker_version_data(self, broker_id):
|
|
219
|
+
conn = await self._manager.get_connection(broker_id)
|
|
220
|
+
return conn.broker_version_data
|
|
221
|
+
|
|
222
|
+
def get_broker_version_data(self, broker_id):
|
|
223
|
+
"""Return BrokerVersionData for a specific broker"""
|
|
224
|
+
return self._manager.run(self._async_get_broker_version_data, broker_id)
|
|
225
|
+
|
|
226
|
+
def api_versions(self):
|
|
227
|
+
api_versions = self._manager.broker_version_data.api_versions
|
|
228
|
+
return {ApiKey(k): v for k, v in api_versions.items()}
|
|
229
|
+
|
|
230
|
+
async def _async_describe_features(self, send_request_to_controller=False):
|
|
231
|
+
request = ApiVersionsRequest(
|
|
232
|
+
client_software_name=self._manager.config['client_software_name'],
|
|
233
|
+
client_software_version=self._manager.config['client_software_version'],
|
|
234
|
+
min_version=3,
|
|
235
|
+
)
|
|
236
|
+
if send_request_to_controller:
|
|
237
|
+
response = await self._send_request_to_controller(request)
|
|
238
|
+
else:
|
|
239
|
+
response = await self._manager.send(request)
|
|
240
|
+
error_type = Errors.for_code(response.error_code)
|
|
241
|
+
if error_type is not Errors.NoError:
|
|
242
|
+
raise error_type(f"ApiVersionsRequest failed: {response}")
|
|
243
|
+
result = defaultdict(dict)
|
|
244
|
+
epoch = response.finalized_features_epoch
|
|
245
|
+
if epoch is None or epoch < 0:
|
|
246
|
+
epoch = None
|
|
247
|
+
for feature in (response.supported_features or []):
|
|
248
|
+
result[feature.name]['supported'] = (feature.min_version, feature.max_version)
|
|
249
|
+
for feature in (response.finalized_features or []):
|
|
250
|
+
result[feature.name]['finalized'] = (feature.min_version_level, feature.max_version_level)
|
|
251
|
+
result[feature.name]['finalized_epoch'] = epoch
|
|
252
|
+
return dict(result)
|
|
253
|
+
|
|
254
|
+
def describe_features(self, send_request_to_controller=False):
|
|
255
|
+
"""Fetch the cluster's supported and finalized feature flags.
|
|
256
|
+
|
|
257
|
+
Features are broker-level capabilities (e.g. ``metadata.version``)
|
|
258
|
+
that can be finalized cluster-wide via ``update_features`` (KIP-584).
|
|
259
|
+
Requires broker >= 2.4.
|
|
260
|
+
|
|
261
|
+
Keyword Arguments:
|
|
262
|
+
send_request_to_controller (bool, optional): If True, route the
|
|
263
|
+
request to the active controller. By default the request is
|
|
264
|
+
sent to any available broker. Default: False.
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
dict with keys:
|
|
268
|
+
- ``supported_features``: dict of
|
|
269
|
+
``{feature_name: (min_version, max_version)}``
|
|
270
|
+
- ``finalized_features``: dict of
|
|
271
|
+
``{feature_name: (min_version_level, max_version_level)}``
|
|
272
|
+
- ``finalized_features_epoch``: int, or None if unknown
|
|
273
|
+
(broker did not report an epoch, or reported -1)
|
|
274
|
+
"""
|
|
275
|
+
return self._manager.run(self._async_describe_features, send_request_to_controller)
|
|
276
|
+
|
|
277
|
+
@staticmethod
|
|
278
|
+
def _build_feature_updates(feature_updates):
|
|
279
|
+
if not isinstance(feature_updates, dict):
|
|
280
|
+
raise TypeError('feature_updates must be a dict of '
|
|
281
|
+
'{feature_name: (max_version_level, upgrade_type)} '
|
|
282
|
+
'or {feature_name: max_version_level}')
|
|
283
|
+
_FeatureUpdateKey = UpdateFeaturesRequest.FeatureUpdateKey
|
|
284
|
+
updates = []
|
|
285
|
+
for feature, spec in feature_updates.items():
|
|
286
|
+
if isinstance(spec, tuple):
|
|
287
|
+
upgrade_type, max_version_level = spec
|
|
288
|
+
else:
|
|
289
|
+
upgrade_type = UpdateFeatureType.UPGRADE
|
|
290
|
+
max_version_level = spec
|
|
291
|
+
upgrade_code = UpdateFeatureType.value_for(upgrade_type)
|
|
292
|
+
downgrade = upgrade_code in (
|
|
293
|
+
UpdateFeatureType.SAFE_DOWNGRADE.value,
|
|
294
|
+
UpdateFeatureType.UNSAFE_DOWNGRADE.value)
|
|
295
|
+
updates.append(_FeatureUpdateKey(
|
|
296
|
+
feature=feature,
|
|
297
|
+
max_version_level=int(max_version_level),
|
|
298
|
+
allow_downgrade=downgrade,
|
|
299
|
+
upgrade_type=upgrade_code))
|
|
300
|
+
return updates
|
|
301
|
+
|
|
302
|
+
async def _async_update_features(self, feature_updates, validate_only=False, timeout_ms=60000):
|
|
303
|
+
min_version = 1 if validate_only else 0
|
|
304
|
+
request = UpdateFeaturesRequest(
|
|
305
|
+
timeout_ms=timeout_ms,
|
|
306
|
+
feature_updates=self._build_feature_updates(feature_updates),
|
|
307
|
+
validate_only=validate_only,
|
|
308
|
+
min_version=min_version,
|
|
309
|
+
)
|
|
310
|
+
response = await self._send_request_to_controller(
|
|
311
|
+
request,
|
|
312
|
+
get_errors_fn=lambda r: [Errors.for_code(r.error_code)],
|
|
313
|
+
)
|
|
314
|
+
ret = {}
|
|
315
|
+
for result in response.results or []:
|
|
316
|
+
if result.error_code == 0:
|
|
317
|
+
ret[result.feature] = 'OK'
|
|
318
|
+
else:
|
|
319
|
+
ret[result.feature] = str(Errors.for_code(result.error_code)(result.error_message))
|
|
320
|
+
# v2+ responses omit per-feature results; top-level error is already
|
|
321
|
+
# raised by _send_request_to_controller, so any feature we asked about
|
|
322
|
+
# succeeded.
|
|
323
|
+
for feature in feature_updates:
|
|
324
|
+
ret.setdefault(feature, 'OK')
|
|
325
|
+
return ret
|
|
326
|
+
|
|
327
|
+
def update_features(self, feature_updates, validate_only=False, timeout_ms=60000):
|
|
328
|
+
"""Update cluster-wide finalized feature flags.
|
|
329
|
+
|
|
330
|
+
Finalize cluster-wide feature capabilities (e.g. ``metadata.version``).
|
|
331
|
+
The request is always routed to the active controller. See KIP-584.
|
|
332
|
+
Requires broker >= 2.7.
|
|
333
|
+
|
|
334
|
+
Arguments:
|
|
335
|
+
feature_updates: A dict of
|
|
336
|
+
``{feature_name: (upgrade_type, max_version_level)}`` or
|
|
337
|
+
``{feature_name: max_version_level}`` (implicit UPGRADE).
|
|
338
|
+
``upgrade_type`` may be a :class:`UpdateFeatureType`,
|
|
339
|
+
its name, or int value. A ``max_version_level < 1`` requests
|
|
340
|
+
deletion of the finalized feature.
|
|
341
|
+
|
|
342
|
+
Keyword Arguments:
|
|
343
|
+
validate_only (bool, optional): If True, validate the request but
|
|
344
|
+
do not apply it. Default: False.
|
|
345
|
+
timeout_ms (int, optional): Broker-side timeout in milliseconds.
|
|
346
|
+
Default: 60000.
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
dict of {feature_name: 'OK' | error message}
|
|
350
|
+
"""
|
|
351
|
+
return self._manager.run(self._async_update_features,
|
|
352
|
+
feature_updates, validate_only, timeout_ms)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
class UpdateFeatureType(EnumHelper, IntEnum):
|
|
356
|
+
UNKNOWN = 0
|
|
357
|
+
UPGRADE = 1
|
|
358
|
+
SAFE_DOWNGRADE = 2
|
|
359
|
+
UNSAFE_DOWNGRADE = 3
|