|
1 | 1 | from __future__ import absolute_import
|
2 | 2 |
|
3 |
| -from collections import defaultdict |
| 3 | +from collections import defaultdict, namedtuple |
4 | 4 | import copy
|
5 | 5 | import logging
|
6 | 6 | import socket
|
|
17 | 17 | from kafka.protocol.admin import (
|
18 | 18 | CreateTopicsRequest, DeleteTopicsRequest, DescribeConfigsRequest, AlterConfigsRequest, CreatePartitionsRequest,
|
19 | 19 | ListGroupsRequest, DescribeGroupsRequest, DescribeAclsRequest, CreateAclsRequest, DeleteAclsRequest)
|
| 20 | +from kafka.protocol.types import Array |
| 21 | +from kafka.coordinator.protocol import ConsumerProtocolMemberMetadata, ConsumerProtocolMemberAssignment, ConsumerProtocol |
20 | 22 | from kafka.protocol.commit import GroupCoordinatorRequest, OffsetFetchRequest
|
21 | 23 | from kafka.protocol.metadata import MetadataRequest
|
22 |
| -from kafka.structs import TopicPartition, OffsetAndMetadata |
| 24 | +from kafka.structs import TopicPartition, OffsetAndMetadata, MemberInformation, GroupInformation |
23 | 25 | from kafka.admin.acl_resource import ACLOperation, ACLPermissionType, ACLFilter, ACL, ResourcePattern, ResourceType, \
|
24 | 26 | ACLResourcePatternType
|
25 | 27 | from kafka.version import __version__
|
@@ -1000,22 +1002,47 @@ def _describe_consumer_groups_process_response(self, response):
|
1000 | 1002 | """Process a DescribeGroupsResponse into a group description."""
|
1001 | 1003 | if response.API_VERSION <= 3:
|
1002 | 1004 | assert len(response.groups) == 1
|
1003 |
| - # TODO need to implement converting the response tuple into |
1004 |
| - # a more accessible interface like a namedtuple and then stop |
1005 |
| - # hardcoding tuple indices here. Several Java examples, |
1006 |
| - # including KafkaAdminClient.java |
1007 |
| - group_description = response.groups[0] |
1008 |
| - error_code = group_description[0] |
| 1005 | + for response_field, response_name in zip(response.SCHEMA.fields, response.SCHEMA.names): |
| 1006 | + if type(response_field) == Array: |
| 1007 | + described_groups = response.__dict__[response_name] |
| 1008 | + described_groups_field_schema = response_field.array_of |
| 1009 | + for described_group in described_groups: |
| 1010 | + described_group_information_list = [] |
| 1011 | + is_consumer_protocol_type = False |
| 1012 | + for (described_group_information, group_information_name, group_information_field) in zip(described_group, described_groups_field_schema.names, described_groups_field_schema.fields): |
| 1013 | + if group_information_name == 'protocol_type': |
| 1014 | + protocol_type = described_group_information |
| 1015 | + is_consumer_protocol_type = (protocol_type == ConsumerProtocol.PROTOCOL_TYPE or not protocol_type) |
| 1016 | + if type(group_information_field) == Array: |
| 1017 | + member_information_list = [] |
| 1018 | + member_schema = group_information_field.array_of |
| 1019 | + for members in described_group_information: |
| 1020 | + member_information = [] |
| 1021 | + for (member, member_field, member_name) in zip(members, member_schema.fields, member_schema.names): |
| 1022 | + if member_name == 'member_metadata' and is_consumer_protocol_type: |
| 1023 | + member_information.append(ConsumerProtocolMemberMetadata.decode(member)) |
| 1024 | + elif member_name == 'member_assignment' and is_consumer_protocol_type: |
| 1025 | + member_information.append(ConsumerProtocolMemberAssignment.decode(member)) |
| 1026 | + else: |
| 1027 | + member_information.append(member) |
| 1028 | + else: |
| 1029 | + member_info_tuple = MemberInformation._make(member_information) |
| 1030 | + member_information_list.append(member_info_tuple) |
| 1031 | + else: |
| 1032 | + described_group_information_list.append(member_information_list) |
| 1033 | + else: |
| 1034 | + described_group_information_list.append(described_group_information) |
| 1035 | + else: |
| 1036 | + if response.API_VERSION <=2: |
| 1037 | + described_group_information_list.append([]) |
| 1038 | + group_description = GroupInformation._make(described_group_information_list) |
| 1039 | + error_code = group_description.error_code |
1009 | 1040 | error_type = Errors.for_code(error_code)
|
1010 | 1041 | # Java has the note: KAFKA-6789, we can retry based on the error code
|
1011 | 1042 | if error_type is not Errors.NoError:
|
1012 | 1043 | raise error_type(
|
1013 | 1044 | "DescribeGroupsResponse failed with response '{}'."
|
1014 | 1045 | .format(response))
|
1015 |
| - # TODO Java checks the group protocol type, and if consumer |
1016 |
| - # (ConsumerProtocol.PROTOCOL_TYPE) or empty string, it decodes |
1017 |
| - # the members' partition assignments... that hasn't yet been |
1018 |
| - # implemented here so just return the raw struct results |
1019 | 1046 | else:
|
1020 | 1047 | raise NotImplementedError(
|
1021 | 1048 | "Support for DescribeGroupsResponse_v{} has not yet been added to KafkaAdminClient."
|
|
0 commit comments