mirror of
https://github.com/hanzoai/traces.git
synced 2026-10-30 18:20:41 +00:00
c855109044
Bumps [github.com/twmb/franz-go/pkg/kadm](https://github.com/twmb/franz-go) from 1.16.0 to 1.17.1. - [Changelog](https://github.com/twmb/franz-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/twmb/franz-go/compare/v1.16.0...v1.17.1) --- updated-dependencies: - dependency-name: github.com/twmb/franz-go/pkg/kadm dependency-version: 1.17.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
593 lines
17 KiB
Go
593 lines
17 KiB
Go
package kadm
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
|
|
"github.com/twmb/franz-go/pkg/kerr"
|
|
"github.com/twmb/franz-go/pkg/kmsg"
|
|
)
|
|
|
|
// AlterReplicaLogDirsReq is the input for a request to alter replica log
|
|
// directories. The key is the directory that all topics and partitions in
|
|
// the topic set will move to.
|
|
type AlterReplicaLogDirsReq map[string]TopicsSet
|
|
|
|
// Add merges the input topic set into the given directory.
|
|
func (r *AlterReplicaLogDirsReq) Add(d string, s TopicsSet) {
|
|
if *r == nil {
|
|
*r = make(map[string]TopicsSet)
|
|
}
|
|
existing := (*r)[d]
|
|
if existing == nil {
|
|
existing = make(TopicsSet)
|
|
(*r)[d] = existing
|
|
}
|
|
existing.Merge(s)
|
|
}
|
|
|
|
func (r AlterReplicaLogDirsReq) req() *kmsg.AlterReplicaLogDirsRequest {
|
|
req := kmsg.NewPtrAlterReplicaLogDirsRequest()
|
|
for dir, ts := range r {
|
|
rd := kmsg.NewAlterReplicaLogDirsRequestDir()
|
|
rd.Dir = dir
|
|
for t, ps := range ts {
|
|
rt := kmsg.NewAlterReplicaLogDirsRequestDirTopic()
|
|
rt.Topic = t
|
|
for p := range ps {
|
|
rt.Partitions = append(rt.Partitions, p)
|
|
}
|
|
rd.Topics = append(rd.Topics, rt)
|
|
}
|
|
req.Dirs = append(req.Dirs, rd)
|
|
}
|
|
return req
|
|
}
|
|
|
|
func (r AlterReplicaLogDirsReq) dirfor(t string, p int32) string {
|
|
for d, dts := range r {
|
|
if dts == nil {
|
|
continue
|
|
}
|
|
dtps, ok := dts[t] // does this dir contain this topic?
|
|
if !ok {
|
|
continue
|
|
}
|
|
if _, ok = dtps[p]; !ok { // does this topic in this dir contain this partition?
|
|
continue
|
|
}
|
|
return d // yes
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// AlterAllReplicaLogDirsResponses contains per-broker responses to altered
|
|
// partition directories.
|
|
type AlterAllReplicaLogDirsResponses map[int32]AlterReplicaLogDirsResponses
|
|
|
|
// Sorted returns the responses sorted by broker, topic, and partition.
|
|
func (rs AlterAllReplicaLogDirsResponses) Sorted() []AlterReplicaLogDirsResponse {
|
|
var all []AlterReplicaLogDirsResponse
|
|
rs.Each(func(r AlterReplicaLogDirsResponse) {
|
|
all = append(all, r)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool { return all[i].Less(all[j]) })
|
|
return all
|
|
}
|
|
|
|
// Each calls fn for every response.
|
|
func (rs AlterAllReplicaLogDirsResponses) Each(fn func(AlterReplicaLogDirsResponse)) {
|
|
for _, ts := range rs {
|
|
ts.Each(fn)
|
|
}
|
|
}
|
|
|
|
// AlterReplicaLogDirsResponses contains responses to altered partition
|
|
// directories for a single broker.
|
|
type AlterReplicaLogDirsResponses map[string]map[int32]AlterReplicaLogDirsResponse
|
|
|
|
// Sorted returns the responses sorted by topic and partition.
|
|
func (rs AlterReplicaLogDirsResponses) Sorted() []AlterReplicaLogDirsResponse {
|
|
var all []AlterReplicaLogDirsResponse
|
|
rs.Each(func(r AlterReplicaLogDirsResponse) {
|
|
all = append(all, r)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool { return all[i].Less(all[j]) })
|
|
return all
|
|
}
|
|
|
|
// Each calls fn for every response.
|
|
func (rs AlterReplicaLogDirsResponses) Each(fn func(AlterReplicaLogDirsResponse)) {
|
|
for _, ps := range rs {
|
|
for _, r := range ps {
|
|
fn(r)
|
|
}
|
|
}
|
|
}
|
|
|
|
// AlterReplicaLogDirsResponse contains a the response for an individual
|
|
// altered partition directory.
|
|
type AlterReplicaLogDirsResponse struct {
|
|
Broker int32 // Broker is the broker this response came from.
|
|
Dir string // Dir is the directory this partition was requested to be moved to.
|
|
Topic string // Topic is the topic for this partition.
|
|
Partition int32 // Partition is the partition that was moved.
|
|
Err error // Err is non-nil if this move had an error.
|
|
}
|
|
|
|
// Less returns if the response is less than the other by broker, dir, topic,
|
|
// and partition.
|
|
func (a AlterReplicaLogDirsResponse) Less(other AlterReplicaLogDirsResponse) bool {
|
|
if a.Broker < other.Broker {
|
|
return true
|
|
}
|
|
if a.Broker > other.Broker {
|
|
return false
|
|
}
|
|
if a.Dir < other.Dir {
|
|
return true
|
|
}
|
|
if a.Dir > other.Dir {
|
|
return false
|
|
}
|
|
if a.Topic < other.Topic {
|
|
return true
|
|
}
|
|
if a.Topic > other.Topic {
|
|
return false
|
|
}
|
|
return a.Partition < other.Partition
|
|
}
|
|
|
|
func newAlterLogDirsResp(node int32, req AlterReplicaLogDirsReq, resp *kmsg.AlterReplicaLogDirsResponse) AlterReplicaLogDirsResponses {
|
|
a := make(AlterReplicaLogDirsResponses)
|
|
for _, kt := range resp.Topics {
|
|
ps := make(map[int32]AlterReplicaLogDirsResponse)
|
|
a[kt.Topic] = ps
|
|
for _, kp := range kt.Partitions {
|
|
ps[kp.Partition] = AlterReplicaLogDirsResponse{
|
|
Broker: node,
|
|
Dir: req.dirfor(kt.Topic, kp.Partition),
|
|
Topic: kt.Topic,
|
|
Partition: kp.Partition,
|
|
Err: kerr.ErrorForCode(kp.ErrorCode),
|
|
}
|
|
}
|
|
}
|
|
return a
|
|
}
|
|
|
|
// AlterAllReplicaLogDirs alters the log directories for the input topic
|
|
// partitions, moving each partition to the requested directory. This function
|
|
// moves all replicas on any broker.
|
|
//
|
|
// This may return *ShardErrors.
|
|
func (cl *Client) AlterAllReplicaLogDirs(ctx context.Context, alter AlterReplicaLogDirsReq) (AlterAllReplicaLogDirsResponses, error) {
|
|
if len(alter) == 0 {
|
|
return make(AlterAllReplicaLogDirsResponses), nil
|
|
}
|
|
req := alter.req()
|
|
shards := cl.cl.RequestSharded(ctx, req)
|
|
resps := make(AlterAllReplicaLogDirsResponses)
|
|
return resps, shardErrEachBroker(req, shards, func(b BrokerDetail, kr kmsg.Response) error {
|
|
resp := kr.(*kmsg.AlterReplicaLogDirsResponse)
|
|
resps[b.NodeID] = newAlterLogDirsResp(b.NodeID, alter, resp) // one node ID, no need to unique-check
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// AlterBrokerReplicaLogDirs alters the log directories for the input topic on the
|
|
// given broker, moving each partition to the requested directory.
|
|
func (cl *Client) AlterBrokerReplicaLogDirs(ctx context.Context, broker int32, alter AlterReplicaLogDirsReq) (AlterReplicaLogDirsResponses, error) {
|
|
if len(alter) == 0 {
|
|
return make(AlterReplicaLogDirsResponses), nil
|
|
}
|
|
b := cl.cl.Broker(int(broker))
|
|
kresp, err := b.RetriableRequest(ctx, alter.req())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp := kresp.(*kmsg.AlterReplicaLogDirsResponse)
|
|
return newAlterLogDirsResp(broker, alter, resp), nil
|
|
}
|
|
|
|
func describeLogDirsReq(s TopicsSet) *kmsg.DescribeLogDirsRequest {
|
|
req := kmsg.NewPtrDescribeLogDirsRequest()
|
|
for t, ps := range s {
|
|
rt := kmsg.NewDescribeLogDirsRequestTopic()
|
|
rt.Topic = t
|
|
for p := range ps {
|
|
rt.Partitions = append(rt.Partitions, p)
|
|
}
|
|
req.Topics = append(req.Topics, rt)
|
|
}
|
|
return req
|
|
}
|
|
|
|
// DescribedAllLogDirs contains per-broker responses to described log
|
|
// directories.
|
|
type DescribedAllLogDirs map[int32]DescribedLogDirs
|
|
|
|
// Sorted returns each log directory sorted by broker, then by directory.
|
|
func (ds DescribedAllLogDirs) Sorted() []DescribedLogDir {
|
|
var all []DescribedLogDir
|
|
ds.Each(func(d DescribedLogDir) {
|
|
all = append(all, d)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool {
|
|
l, r := all[i], all[j]
|
|
return l.Broker < r.Broker || l.Broker == r.Broker && l.Dir < r.Dir
|
|
})
|
|
return all
|
|
}
|
|
|
|
// Each calls fn for every described log dir in all responses.
|
|
func (ds DescribedAllLogDirs) Each(fn func(DescribedLogDir)) {
|
|
for _, bds := range ds {
|
|
bds.Each(fn)
|
|
}
|
|
}
|
|
|
|
// DescribedLogDirs contains per-directory responses to described log
|
|
// directories for a single broker.
|
|
type DescribedLogDirs map[string]DescribedLogDir
|
|
|
|
// Lookup returns the described partition if it exists.
|
|
func (ds DescribedLogDirs) Lookup(d, t string, p int32) (DescribedLogDirPartition, bool) {
|
|
dir, exists := ds[d]
|
|
if !exists {
|
|
return DescribedLogDirPartition{}, false
|
|
}
|
|
ps, exists := dir.Topics[t]
|
|
if !exists {
|
|
return DescribedLogDirPartition{}, false
|
|
}
|
|
dp, exists := ps[p]
|
|
if !exists {
|
|
return DescribedLogDirPartition{}, false
|
|
}
|
|
return dp, true
|
|
}
|
|
|
|
// LookupPartition returns the described partition if it exists in any
|
|
// directory. Brokers should only have one replica of a partition, so this
|
|
// should always find at most one partition.
|
|
func (ds DescribedLogDirs) LookupPartition(t string, p int32) (DescribedLogDirPartition, bool) {
|
|
for _, dir := range ds {
|
|
ps, exists := dir.Topics[t]
|
|
if !exists {
|
|
continue
|
|
}
|
|
dp, exists := ps[p]
|
|
if !exists {
|
|
continue
|
|
}
|
|
return dp, true
|
|
}
|
|
return DescribedLogDirPartition{}, false
|
|
}
|
|
|
|
// Size returns the total size of all directories.
|
|
func (ds DescribedLogDirs) Size() int64 {
|
|
var tot int64
|
|
ds.EachPartition(func(d DescribedLogDirPartition) {
|
|
tot += d.Size
|
|
})
|
|
return tot
|
|
}
|
|
|
|
// Error iterates over all directories and returns the first error encountered,
|
|
// if any. This can be used to check if describing was entirely successful or
|
|
// not.
|
|
func (ds DescribedLogDirs) Error() error {
|
|
for _, d := range ds {
|
|
if d.Err != nil {
|
|
return d.Err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Ok returns true if there are no errors. This is a shortcut for ds.Error() ==
|
|
// nil.
|
|
func (ds DescribedLogDirs) Ok() bool {
|
|
return ds.Error() == nil
|
|
}
|
|
|
|
// Sorted returns all directories sorted by dir.
|
|
func (ds DescribedLogDirs) Sorted() []DescribedLogDir {
|
|
var all []DescribedLogDir
|
|
ds.Each(func(d DescribedLogDir) {
|
|
all = append(all, d)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool {
|
|
l, r := all[i], all[j]
|
|
return l.Broker < r.Broker || l.Broker == r.Broker && l.Dir < r.Dir
|
|
})
|
|
return all
|
|
}
|
|
|
|
// SortedPartitions returns all partitions sorted by dir, then topic, then
|
|
// partition.
|
|
func (ds DescribedLogDirs) SortedPartitions() []DescribedLogDirPartition {
|
|
var all []DescribedLogDirPartition
|
|
ds.EachPartition(func(d DescribedLogDirPartition) {
|
|
all = append(all, d)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool { return all[i].Less(all[j]) })
|
|
return all
|
|
}
|
|
|
|
// SortedBySize returns all directories sorted from smallest total directory
|
|
// size to largest.
|
|
func (ds DescribedLogDirs) SortedBySize() []DescribedLogDir {
|
|
var all []DescribedLogDir
|
|
ds.Each(func(d DescribedLogDir) {
|
|
all = append(all, d)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool {
|
|
l, r := all[i], all[j]
|
|
ls, rs := l.Size(), r.Size()
|
|
return ls < rs || ls == rs &&
|
|
(l.Broker < r.Broker || l.Broker == r.Broker &&
|
|
l.Dir < r.Dir)
|
|
})
|
|
return all
|
|
}
|
|
|
|
// SortedPartitionsBySize returns all partitions across all directories sorted
|
|
// by smallest to largest, falling back to by broker, dir, topic, and
|
|
// partition.
|
|
func (ds DescribedLogDirs) SortedPartitionsBySize() []DescribedLogDirPartition {
|
|
var all []DescribedLogDirPartition
|
|
ds.EachPartition(func(d DescribedLogDirPartition) {
|
|
all = append(all, d)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool { return all[i].LessBySize(all[j]) })
|
|
return all
|
|
}
|
|
|
|
// SmallestPartitionBySize returns the smallest partition by directory size, or
|
|
// no partition if there are no partitions.
|
|
func (ds DescribedLogDirs) SmallestPartitionBySize() (DescribedLogDirPartition, bool) {
|
|
sorted := ds.SortedPartitionsBySize()
|
|
if len(sorted) == 0 {
|
|
return DescribedLogDirPartition{}, false
|
|
}
|
|
return sorted[0], true
|
|
}
|
|
|
|
// LargestPartitionBySize returns the largest partition by directory size, or
|
|
// no partition if there are no partitions.
|
|
func (ds DescribedLogDirs) LargestPartitionBySize() (DescribedLogDirPartition, bool) {
|
|
sorted := ds.SortedPartitionsBySize()
|
|
if len(sorted) == 0 {
|
|
return DescribedLogDirPartition{}, false
|
|
}
|
|
return sorted[len(sorted)-1], true
|
|
}
|
|
|
|
// Each calls fn for each log directory.
|
|
func (ds DescribedLogDirs) Each(fn func(DescribedLogDir)) {
|
|
for _, d := range ds {
|
|
fn(d)
|
|
}
|
|
}
|
|
|
|
// EachPartition calls fn for each partition in any directory.
|
|
func (ds DescribedLogDirs) EachPartition(fn func(d DescribedLogDirPartition)) {
|
|
for _, d := range ds {
|
|
d.Topics.Each(fn)
|
|
}
|
|
}
|
|
|
|
// EachError calls fn for every directory that has a non-nil error.
|
|
func (ds DescribedLogDirs) EachError(fn func(DescribedLogDir)) {
|
|
for _, d := range ds {
|
|
if d.Err != nil {
|
|
fn(d)
|
|
}
|
|
}
|
|
}
|
|
|
|
// DescribedLogDir is a described log directory.
|
|
type DescribedLogDir struct {
|
|
Broker int32 // Broker is the broker being described.
|
|
Dir string // Dir is the described directory.
|
|
Topics DescribedLogDirTopics // Partitions are the partitions in this directory.
|
|
Err error // Err is non-nil if this directory could not be described.
|
|
}
|
|
|
|
// Size returns the total size of all partitions in this directory. This is
|
|
// a shortcut for .Topics.Size().
|
|
func (ds DescribedLogDir) Size() int64 {
|
|
return ds.Topics.Size()
|
|
}
|
|
|
|
// DescribedLogDirTopics contains per-partition described log directories.
|
|
type DescribedLogDirTopics map[string]map[int32]DescribedLogDirPartition
|
|
|
|
// Lookup returns the described partition if it exists.
|
|
func (ds DescribedLogDirTopics) Lookup(t string, p int32) (DescribedLogDirPartition, bool) {
|
|
ps, exists := ds[t]
|
|
if !exists {
|
|
return DescribedLogDirPartition{}, false
|
|
}
|
|
d, exists := ps[p]
|
|
return d, exists
|
|
}
|
|
|
|
// Size returns the total size of all partitions in this directory.
|
|
func (ds DescribedLogDirTopics) Size() int64 {
|
|
var tot int64
|
|
ds.Each(func(d DescribedLogDirPartition) {
|
|
tot += d.Size
|
|
})
|
|
return tot
|
|
}
|
|
|
|
// Sorted returns all partitions sorted by topic then partition.
|
|
func (ds DescribedLogDirTopics) Sorted() []DescribedLogDirPartition {
|
|
var all []DescribedLogDirPartition
|
|
ds.Each(func(d DescribedLogDirPartition) {
|
|
all = append(all, d)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool { return all[i].Less(all[j]) })
|
|
return all
|
|
}
|
|
|
|
// SortedBySize returns all partitions sorted by smallest size to largest. If
|
|
// partitions are of equal size, the sorting is topic then partition.
|
|
func (ds DescribedLogDirTopics) SortedBySize() []DescribedLogDirPartition {
|
|
var all []DescribedLogDirPartition
|
|
ds.Each(func(d DescribedLogDirPartition) {
|
|
all = append(all, d)
|
|
})
|
|
sort.Slice(all, func(i, j int) bool { return all[i].LessBySize(all[j]) })
|
|
return all
|
|
}
|
|
|
|
// Each calls fn for every partition.
|
|
func (ds DescribedLogDirTopics) Each(fn func(p DescribedLogDirPartition)) {
|
|
for _, ps := range ds {
|
|
for _, d := range ps {
|
|
fn(d)
|
|
}
|
|
}
|
|
}
|
|
|
|
// DescribedLogDirPartition is the information for a single partitions described
|
|
// log directory.
|
|
type DescribedLogDirPartition struct {
|
|
Broker int32 // Broker is the broker this partition is on.
|
|
Dir string // Dir is the directory this partition lives in.
|
|
Topic string // Topic is the topic for this partition.
|
|
Partition int32 // Partition is this partition.
|
|
Size int64 // Size is the total size of the log segments of this partition, in bytes.
|
|
|
|
// OffsetLag is how far behind the log end offset this partition is.
|
|
// The math is:
|
|
//
|
|
// if IsFuture {
|
|
// logEndOffset - futureLogEndOffset
|
|
// } else {
|
|
// max(highWaterMark - logEndOffset)
|
|
// }
|
|
//
|
|
OffsetLag int64
|
|
// IsFuture is true if this replica was created by an
|
|
// AlterReplicaLogDirsRequest and will replace the current log of the
|
|
// replica in the future.
|
|
IsFuture bool
|
|
}
|
|
|
|
// Less returns if one dir partition is less than the other, by dir, topic,
|
|
// partition, and size.
|
|
func (p DescribedLogDirPartition) Less(other DescribedLogDirPartition) bool {
|
|
if p.Broker < other.Broker {
|
|
return true
|
|
}
|
|
if p.Broker > other.Broker {
|
|
return false
|
|
}
|
|
if p.Dir < other.Dir {
|
|
return true
|
|
}
|
|
if p.Dir > other.Dir {
|
|
return false
|
|
}
|
|
if p.Topic < other.Topic {
|
|
return true
|
|
}
|
|
if p.Topic > other.Topic {
|
|
return false
|
|
}
|
|
if p.Partition < other.Partition {
|
|
return true
|
|
}
|
|
if p.Partition > other.Partition {
|
|
return false
|
|
}
|
|
return p.Size < other.Size
|
|
}
|
|
|
|
// LessBySize returns if one dir partition is less than the other by size,
|
|
// otherwise by normal Less semantics.
|
|
func (p DescribedLogDirPartition) LessBySize(other DescribedLogDirPartition) bool {
|
|
if p.Size < other.Size {
|
|
return true
|
|
}
|
|
return p.Less(other)
|
|
}
|
|
|
|
func newDescribeLogDirsResp(node int32, resp *kmsg.DescribeLogDirsResponse) DescribedLogDirs {
|
|
ds := make(DescribedLogDirs)
|
|
for _, rd := range resp.Dirs {
|
|
d := DescribedLogDir{
|
|
Broker: node,
|
|
Dir: rd.Dir,
|
|
Topics: make(DescribedLogDirTopics),
|
|
Err: kerr.ErrorForCode(rd.ErrorCode),
|
|
}
|
|
for _, rt := range rd.Topics {
|
|
t := make(map[int32]DescribedLogDirPartition)
|
|
d.Topics[rt.Topic] = t
|
|
for _, rp := range rt.Partitions {
|
|
t[rp.Partition] = DescribedLogDirPartition{
|
|
Broker: node,
|
|
Dir: rd.Dir,
|
|
Topic: rt.Topic,
|
|
Partition: rp.Partition,
|
|
Size: rp.Size,
|
|
OffsetLag: rp.OffsetLag,
|
|
IsFuture: rp.IsFuture,
|
|
}
|
|
}
|
|
}
|
|
ds[rd.Dir] = d
|
|
}
|
|
return ds
|
|
}
|
|
|
|
// DescribeAllLogDirs describes the log directories for every input topic
|
|
// partition on every broker. If the input set is nil, this describes all log
|
|
// directories.
|
|
//
|
|
// This may return *ShardErrors.
|
|
func (cl *Client) DescribeAllLogDirs(ctx context.Context, s TopicsSet) (DescribedAllLogDirs, error) {
|
|
req := describeLogDirsReq(s)
|
|
shards := cl.cl.RequestSharded(ctx, req)
|
|
resps := make(DescribedAllLogDirs)
|
|
return resps, shardErrEachBroker(req, shards, func(b BrokerDetail, kr kmsg.Response) error {
|
|
resp := kr.(*kmsg.DescribeLogDirsResponse)
|
|
if err := maybeAuthErr(resp.ErrorCode); err != nil {
|
|
return err
|
|
}
|
|
if err := kerr.ErrorForCode(resp.ErrorCode); err != nil {
|
|
return err
|
|
}
|
|
resps[b.NodeID] = newDescribeLogDirsResp(b.NodeID, resp) // one node ID, no need to unique-check
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// DescribeBrokerLogDirs describes the log directories for the input topic
|
|
// partitions on the given broker. If the input set is nil, this describes all
|
|
// log directories.
|
|
func (cl *Client) DescribeBrokerLogDirs(ctx context.Context, broker int32, s TopicsSet) (DescribedLogDirs, error) {
|
|
req := describeLogDirsReq(s)
|
|
b := cl.cl.Broker(int(broker))
|
|
kresp, err := b.RetriableRequest(ctx, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp := kresp.(*kmsg.DescribeLogDirsResponse)
|
|
if err := maybeAuthErr(resp.ErrorCode); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := kerr.ErrorForCode(resp.ErrorCode); err != nil {
|
|
return nil, err
|
|
}
|
|
return newDescribeLogDirsResp(broker, resp), nil
|
|
}
|