Browse Source

Merge pull request #724 from provectus/703-additional-fields-topicConfig

703 additional fields topic config
Diego Ching Jenkins 3 years ago
parent
commit
1f268579d0

+ 2 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/mapper/ClusterMapper.java

@@ -35,7 +35,6 @@ import java.math.BigDecimal;
 import java.nio.file.Path;
 import java.nio.file.Path;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Properties;
 import java.util.Properties;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import org.apache.kafka.clients.admin.ConfigEntry;
 import org.apache.kafka.clients.admin.ConfigEntry;
@@ -123,6 +122,8 @@ public interface ClusterMapper {
     return result;
     return result;
   }
   }
 
 
+  @Mapping(target = "isReadOnly", source = "readOnly")
+  @Mapping(target = "isSensitive", source = "sensitive")
   TopicConfig toTopicConfig(InternalTopicConfig topic);
   TopicConfig toTopicConfig(InternalTopicConfig topic);
 
 
   Replica toReplica(InternalReplica replica);
   Replica toReplica(InternalReplica replica);

+ 6 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/InternalTopicConfig.java

@@ -1,8 +1,10 @@
 package com.provectus.kafka.ui.model;
 package com.provectus.kafka.ui.model;
 
 
 
 
+import java.util.List;
 import lombok.Builder;
 import lombok.Builder;
 import lombok.Data;
 import lombok.Data;
+import org.apache.kafka.clients.admin.ConfigEntry;
 
 
 @Data
 @Data
 @Builder
 @Builder
@@ -10,4 +12,8 @@ public class InternalTopicConfig {
   private final String name;
   private final String name;
   private final String value;
   private final String value;
   private final String defaultValue;
   private final String defaultValue;
+  private final ConfigEntry.ConfigSource source;
+  private final boolean isSensitive;
+  private final boolean isReadOnly;
+  private final List<ConfigEntry.ConfigSynonym> synonyms;
 }
 }

+ 2 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaService.java

@@ -337,7 +337,8 @@ public class KafkaService {
         .map(topicName -> new ConfigResource(ConfigResource.Type.TOPIC, topicName))
         .map(topicName -> new ConfigResource(ConfigResource.Type.TOPIC, topicName))
         .collect(Collectors.toList());
         .collect(Collectors.toList());
 
 
-    return ClusterUtil.toMono(adminClient.describeConfigs(resources).all())
+    return ClusterUtil.toMono(adminClient.describeConfigs(resources,
+                    new DescribeConfigsOptions().includeSynonyms(true)).all())
         .map(configs ->
         .map(configs ->
             configs.entrySet().stream().collect(Collectors.toMap(
             configs.entrySet().stream().collect(Collectors.toMap(
                 c -> c.getKey().name(),
                 c -> c.getKey().name(),

+ 5 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/ClusterUtil.java

@@ -195,7 +195,11 @@ public class ClusterUtil {
   public static InternalTopicConfig mapToInternalTopicConfig(ConfigEntry configEntry) {
   public static InternalTopicConfig mapToInternalTopicConfig(ConfigEntry configEntry) {
     InternalTopicConfig.InternalTopicConfigBuilder builder = InternalTopicConfig.builder()
     InternalTopicConfig.InternalTopicConfigBuilder builder = InternalTopicConfig.builder()
         .name(configEntry.name())
         .name(configEntry.name())
-        .value(configEntry.value());
+        .value(configEntry.value())
+        .source(configEntry.source())
+        .isReadOnly(configEntry.isReadOnly())
+        .isSensitive(configEntry.isSensitive())
+        .synonyms(configEntry.synonyms());
     if (configEntry.name().equals(MESSAGE_FORMAT_VERSION_CONFIG)) {
     if (configEntry.name().equals(MESSAGE_FORMAT_VERSION_CONFIG)) {
       builder.defaultValue(configEntry.value());
       builder.defaultValue(configEntry.value());
     } else {
     } else {

+ 47 - 7
kafka-ui-api/src/test/java/com/provectus/kafka/ui/KafkaConsumerTests.java

@@ -1,5 +1,6 @@
 package com.provectus.kafka.ui;
 package com.provectus.kafka.ui;
 
 
+import com.provectus.kafka.ui.api.model.TopicConfig;
 import com.provectus.kafka.ui.model.BrokerConfig;
 import com.provectus.kafka.ui.model.BrokerConfig;
 import com.provectus.kafka.ui.model.PartitionsIncrease;
 import com.provectus.kafka.ui.model.PartitionsIncrease;
 import com.provectus.kafka.ui.model.PartitionsIncreaseResponse;
 import com.provectus.kafka.ui.model.PartitionsIncreaseResponse;
@@ -127,6 +128,12 @@ public class KafkaConsumerTests extends AbstractBaseTest {
         .exchange()
         .exchange()
         .expectStatus()
         .expectStatus()
         .isNotFound();
         .isNotFound();
+
+    webTestClient.get()
+        .uri("/api/clusters/{clusterName}/topics/{topicName}/config", LOCAL, topicName)
+        .exchange()
+        .expectStatus()
+        .isNotFound();
   }
   }
 
 
   @Test
   @Test
@@ -144,18 +151,17 @@ public class KafkaConsumerTests extends AbstractBaseTest {
         .returnResult()
         .returnResult()
         .getResponseBody();
         .getResponseBody();
 
 
-    assert configs != null;
+    Assertions.assertNotNull(configs);
     assert !configs.isEmpty();
     assert !configs.isEmpty();
-    Assertions.assertNotEquals(null, configs.get(0).getName());
-    Assertions.assertNotEquals(null, configs.get(0).getIsReadOnly());
-    Assertions.assertNotEquals(null, configs.get(0).getIsSensitive());
-    Assertions.assertNotEquals(null, configs.get(0).getSource());
+    Assertions.assertNotNull(configs.get(0).getName());
+    Assertions.assertNotNull(configs.get(0).getIsReadOnly());
+    Assertions.assertNotNull(configs.get(0).getIsSensitive());
+    Assertions.assertNotNull(configs.get(0).getSource());
+    Assertions.assertNotNull(configs.get(0).getSynonyms());
   }
   }
 
 
   @Test
   @Test
   public void shouldReturn404ForNonExistingBroker() {
   public void shouldReturn404ForNonExistingBroker() {
-    var topicName = UUID.randomUUID().toString();
-
     webTestClient.get()
     webTestClient.get()
         .uri("/api/clusters/{clusterName}/brokers/{id}/configs",
         .uri("/api/clusters/{clusterName}/brokers/{id}/configs",
             LOCAL,
             LOCAL,
@@ -164,4 +170,38 @@ public class KafkaConsumerTests extends AbstractBaseTest {
         .expectStatus()
         .expectStatus()
         .isNotFound();
         .isNotFound();
   }
   }
+
+  @Test
+  public void shouldRetrieveTopicConfig() {
+    var topicName = UUID.randomUUID().toString();
+
+    webTestClient.post()
+            .uri("/api/clusters/{clusterName}/topics", LOCAL)
+            .bodyValue(new TopicCreation()
+                    .name(topicName)
+                    .partitions(1)
+                    .replicationFactor(1)
+                    .configs(Map.of())
+            )
+            .exchange()
+            .expectStatus()
+            .isOk();
+
+    List<TopicConfig> configs = webTestClient.get()
+            .uri("/api/clusters/{clusterName}/topics/{topicName}/config", LOCAL, topicName)
+            .exchange()
+            .expectStatus()
+            .isOk()
+            .expectBodyList(TopicConfig.class)
+            .returnResult()
+            .getResponseBody();
+
+    Assertions.assertNotNull(configs);
+    assert !configs.isEmpty();
+    Assertions.assertNotNull(configs.get(0).getName());
+    Assertions.assertNotNull(configs.get(0).getIsReadOnly());
+    Assertions.assertNotNull(configs.get(0).getIsSensitive());
+    Assertions.assertNotNull(configs.get(0).getSource());
+    Assertions.assertNotNull(configs.get(0).getSynonyms());
+  }
 }
 }

+ 44 - 0
kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ClusterServiceTest.java

@@ -6,9 +6,11 @@ import static org.mockito.Mockito.when;
 
 
 import com.provectus.kafka.ui.mapper.ClusterMapper;
 import com.provectus.kafka.ui.mapper.ClusterMapper;
 import com.provectus.kafka.ui.model.InternalTopic;
 import com.provectus.kafka.ui.model.InternalTopic;
+import com.provectus.kafka.ui.model.InternalTopicConfig;
 import com.provectus.kafka.ui.model.KafkaCluster;
 import com.provectus.kafka.ui.model.KafkaCluster;
 import com.provectus.kafka.ui.model.Topic;
 import com.provectus.kafka.ui.model.Topic;
 import com.provectus.kafka.ui.model.TopicColumnsToSort;
 import com.provectus.kafka.ui.model.TopicColumnsToSort;
+import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Optional;
@@ -16,6 +18,7 @@ import java.util.UUID;
 import java.util.function.Function;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 import java.util.stream.IntStream;
+import org.apache.kafka.clients.admin.ConfigEntry;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mapstruct.factory.Mappers;
 import org.mapstruct.factory.Mappers;
@@ -256,4 +259,45 @@ class ClusterServiceTest {
     assertThat(topics.getTopics()).map(Topic::getPartitionCount).isSorted();
     assertThat(topics.getTopics()).map(Topic::getPartitionCount).isSorted();
   }
   }
 
 
+  @Test
+  public void shouldRetrieveTopicConfigs() {
+    var topicName = UUID.randomUUID().toString();
+
+    when(clustersStorage.getClusterByName(topicName))
+        .thenReturn(Optional.of(KafkaCluster.builder()
+            .topics(
+                IntStream.rangeClosed(1, 100).boxed()
+                    .map(Objects::toString)
+                    .collect(Collectors.toMap(Function.identity(), e -> InternalTopic.builder()
+                        .name(e)
+                        .topicConfigs(
+                            List.of(InternalTopicConfig.builder()
+                                .name("testName")
+                                .value("testValue")
+                                .defaultValue("testDefaultValue")
+                                .source(ConfigEntry.ConfigSource.DEFAULT_CONFIG)
+                                .isReadOnly(true)
+                                .isSensitive(true)
+                                .synonyms(List.of())
+                                .build()
+                            )
+                        )
+                        .build()))
+            )
+            .build()));
+
+    var configs = clusterService.getTopicConfigs(topicName, "1");
+    var topicConfig = configs.isPresent() ? configs.get().get(0) : null;
+
+    assertThat(configs.isPresent()).isTrue();
+    assertThat(topicConfig.getName()).isEqualTo("testName");
+    assertThat(topicConfig.getValue()).isEqualTo("testValue");
+    assertThat(topicConfig.getDefaultValue()).isEqualTo("testDefaultValue");
+    assertThat(topicConfig.getSource().getValue())
+            .isEqualTo(ConfigEntry.ConfigSource.DEFAULT_CONFIG.name());
+    assertThat(topicConfig.getSynonyms()).isNotNull();
+    assertThat(topicConfig.getIsReadOnly()).isTrue();
+    assertThat(topicConfig.getIsSensitive()).isTrue();
+  }
+
 }
 }

+ 10 - 0
kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml

@@ -1722,6 +1722,16 @@ components:
           type: string
           type: string
         defaultValue:
         defaultValue:
           type: string
           type: string
+        source:
+          $ref: "#/components/schemas/ConfigSource"
+        isSensitive:
+          type: boolean
+        isReadOnly:
+          type: boolean
+        synonyms:
+          type: array
+          items:
+            $ref: "#/components/schemas/ConfigSynonym"
       required:
       required:
         - name
         - name