From 529b639f6672e3072ac143991d9c9bdbda927e63 Mon Sep 17 00:00:00 2001 From: Dirk Wilden Date: Tue, 16 Jan 2024 16:16:07 +0100 Subject: [PATCH] use single parameter to control print-configs fix default naming --- CHANGELOG.md | 3 ++ cmd/describe/describe-topic.go | 3 +- cmd/describe/describe-topic_test.go | 68 +++++++++++++++++++++++++++++ internal/topic/topic-operation.go | 47 ++++++++++++-------- 4 files changed, 102 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e739acb2..540d6dd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- [#184](https://github.com/deviceinsight/kafkactl/pull/184) Added option to show default configs when describing topics + ## 3.5.1 - 2023-11-10 ## 3.5.0 - 2023-11-10 diff --git a/cmd/describe/describe-topic.go b/cmd/describe/describe-topic.go index f23cac2f..c95007e1 100644 --- a/cmd/describe/describe-topic.go +++ b/cmd/describe/describe-topic.go @@ -26,9 +26,8 @@ func newDescribeTopicCmd() *cobra.Command { } cmdDescribeTopic.Flags().StringVarP(&flags.OutputFormat, "output", "o", flags.OutputFormat, "output format. One of: json|yaml|wide") - cmdDescribeTopic.Flags().BoolVarP(&flags.PrintConfigs, "print-configs", "c", true, "print configs") + cmdDescribeTopic.Flags().StringVarP((*string)(&flags.PrintConfigs), "print-configs", "c", "no_defaults", "print configs. One of none|no_defaults|all") cmdDescribeTopic.Flags().BoolVarP(&flags.SkipEmptyPartitions, "skip-empty", "s", false, "show only partitions that have a messages") - cmdDescribeTopic.Flags().BoolVarP(&flags.IncludeDefaults, "include-defaults", "i", false, "include default configs") return cmdDescribeTopic } diff --git a/cmd/describe/describe-topic_test.go b/cmd/describe/describe-topic_test.go index 285e0854..bcba19b3 100644 --- a/cmd/describe/describe-topic_test.go +++ b/cmd/describe/describe-topic_test.go @@ -4,9 +4,69 @@ import ( "strings" "testing" + "github.com/deviceinsight/kafkactl/internal" + "github.com/deviceinsight/kafkactl/internal/topic" + "github.com/deviceinsight/kafkactl/testutil" ) +func TestDescribeTopicConfigsIntegration(t *testing.T) { + + testutil.StartIntegrationTest(t) + + prefix := "describe-t-configs-" + + topicName1 := testutil.CreateTopic(t, prefix, "--config", "retention.ms=3600000") + + kafkaCtl := testutil.CreateKafkaCtlCommand() + kafkaCtl.Verbose = false + + // default --print-configs=no_defaults + if _, err := kafkaCtl.Execute("describe", "topic", topicName1, "-o", "yaml"); err != nil { + t.Fatalf("failed to execute command: %v", err) + } + + describedTopic, err := topic.FromYaml(kafkaCtl.GetStdOut()) + if err != nil { + t.Fatalf("failed to read yaml: %v", err) + } + + configKeys := getConfigKeys(describedTopic.Configs) + + testutil.AssertArraysEquals(t, []string{"retention.ms"}, configKeys) + testutil.AssertEquals(t, "3600000", describedTopic.Configs[0].Value) + + // explicitly without defaults + if _, err := kafkaCtl.Execute("describe", "topic", topicName1, "-c", "no_defaults", "-o", "yaml"); err != nil { + t.Fatalf("failed to execute command: %v", err) + } + + describedTopic, err = topic.FromYaml(kafkaCtl.GetStdOut()) + if err != nil { + t.Fatalf("failed to read yaml: %v", err) + } + + configKeys = getConfigKeys(describedTopic.Configs) + + testutil.AssertArraysEquals(t, []string{"retention.ms"}, configKeys) + testutil.AssertEquals(t, "3600000", describedTopic.Configs[0].Value) + + // all configs + if _, err := kafkaCtl.Execute("describe", "topic", topicName1, "-c", "all", "-o", "yaml"); err != nil { + t.Fatalf("failed to execute command: %v", err) + } + + describedTopic, err = topic.FromYaml(kafkaCtl.GetStdOut()) + if err != nil { + t.Fatalf("failed to read yaml: %v", err) + } + + configKeys = getConfigKeys(describedTopic.Configs) + + testutil.AssertContains(t, "retention.ms", configKeys) + testutil.AssertContains(t, "cleanup.policy", configKeys) +} + func TestDescribeTopicAutoCompletionIntegration(t *testing.T) { testutil.StartIntegrationTest(t) @@ -30,3 +90,11 @@ func TestDescribeTopicAutoCompletionIntegration(t *testing.T) { testutil.AssertContains(t, topicName2, outputLines) testutil.AssertContains(t, topicName3, outputLines) } + +func getConfigKeys(configs []internal.Config) []string { + keys := make([]string, len(configs)) + for i, config := range configs { + keys[i] = config.Name + } + return keys +} diff --git a/internal/topic/topic-operation.go b/internal/topic/topic-operation.go index 3871f966..464174e5 100644 --- a/internal/topic/topic-operation.go +++ b/internal/topic/topic-operation.go @@ -32,16 +32,18 @@ type Partition struct { } type requestedTopicFields struct { - partitionID bool - partitionOffset bool - partitionLeader bool - partitionReplicas bool - partitionISRs bool - config bool - configIncludeDefaults bool + partitionID bool + partitionOffset bool + partitionLeader bool + partitionReplicas bool + partitionISRs bool + config PrintConfigsParam } -var allFields = requestedTopicFields{partitionID: true, partitionOffset: true, partitionLeader: true, partitionReplicas: true, partitionISRs: true, config: true} +var allFields = requestedTopicFields{ + partitionID: true, partitionOffset: true, partitionLeader: true, + partitionReplicas: true, partitionISRs: true, config: NonDefaultConfigs, +} type GetTopicsFlags struct { OutputFormat string @@ -61,11 +63,18 @@ type AlterTopicFlags struct { Configs []string } +type PrintConfigsParam string + +const ( + NoConfigs PrintConfigsParam = "none" + AllConfigs PrintConfigsParam = "all" + NonDefaultConfigs PrintConfigsParam = "no_defaults" +) + type DescribeTopicFlags struct { - PrintConfigs bool + PrintConfigs PrintConfigsParam SkipEmptyPartitions bool OutputFormat string - IncludeDefaults bool } type Operation struct { @@ -164,7 +173,7 @@ func (operation *Operation) DescribeTopic(topic string, flags DescribeTopicFlags } fields := allFields - fields.configIncludeDefaults = flags.IncludeDefaults + fields.config = flags.PrintConfigs if t, err = readTopic(&client, &admin, topic, fields); err != nil { return errors.Wrap(err, "failed to read topic") @@ -175,7 +184,7 @@ func (operation *Operation) DescribeTopic(topic string, flags DescribeTopicFlags func (operation *Operation) printTopic(topic Topic, flags DescribeTopicFlags) error { - if !flags.PrintConfigs { + if flags.PrintConfigs == NoConfigs { topic.Configs = nil } @@ -406,7 +415,11 @@ func (operation *Operation) AlterTopic(topic string, flags AlterTopicFlags) erro } if flags.ValidateOnly { - describeFlags := DescribeTopicFlags{PrintConfigs: len(flags.Configs) > 0} + printConfigs := NoConfigs + if len(flags.Configs) > 0 { + printConfigs = NonDefaultConfigs + } + describeFlags := DescribeTopicFlags{PrintConfigs: printConfigs} return operation.printTopic(t, describeFlags) } return nil @@ -477,7 +490,7 @@ func (operation *Operation) CloneTopic(sourceTopic, targetTopic string) error { requestedFields := requestedTopicFields{ partitionID: true, partitionReplicas: true, - config: true, + config: NonDefaultConfigs, } if t, err = readTopic(&client, &admin, sourceTopic, requestedFields); err != nil { @@ -586,7 +599,7 @@ func (operation *Operation) GetTopics(flags GetTopicsFlags) error { } else if flags.OutputFormat == "compact" { tableWriter.Initialize() } else if flags.OutputFormat == "wide" { - requestedFields = requestedTopicFields{partitionID: true, partitionReplicas: true, config: true} + requestedFields = requestedTopicFields{partitionID: true, partitionReplicas: true, config: NonDefaultConfigs} if err := tableWriter.WriteHeader("TOPIC", "PARTITIONS", "REPLICATION FACTOR", "CONFIGS"); err != nil { return err } @@ -730,14 +743,14 @@ func readTopic(client *sarama.Client, admin *sarama.ClusterAdmin, name string, r return top.Partitions[i].ID < top.Partitions[j].ID }) - if requestedFields.config { + if requestedFields.config != NoConfigs { topicConfig := sarama.ConfigResource{ Type: sarama.TopicResource, Name: name, } - if top.Configs, err = internal.ListConfigs(admin, topicConfig, requestedFields.configIncludeDefaults); err != nil { + if top.Configs, err = internal.ListConfigs(admin, topicConfig, requestedFields.config == AllConfigs); err != nil { return top, err } }