diff --git a/build.gradle b/build.gradle index 92961e2e..c3617798 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { - id("com.github.johnrengelman.shadow") version "7.1.2" - id("io.micronaut.application") version "3.7.10" + id("com.github.johnrengelman.shadow") version "8.1.1" + id("io.micronaut.application") version "4.0.3" id("jacoco") id("org.sonarqube") version "4.3.0.3225" id("pl.allegro.tech.build.axion-release") version "1.15.4" @@ -18,23 +18,30 @@ dependencies { annotationProcessor("io.micronaut:micronaut-http-validation") annotationProcessor("io.micronaut.openapi:micronaut-openapi") annotationProcessor("io.micronaut.security:micronaut-security-annotations") + annotationProcessor("io.micronaut.serde:micronaut-serde-processor") + annotationProcessor("io.micronaut.validation:micronaut-validation-processor") implementation("io.micronaut:micronaut-http-client") - implementation("io.micronaut:micronaut-jackson-databind") implementation("io.micronaut.kafka:micronaut-kafka") + implementation("io.micronaut.reactor:micronaut-reactor") + implementation("io.micronaut.reactor:micronaut-reactor-http-client") implementation("io.micronaut.security:micronaut-security") implementation("io.micronaut.security:micronaut-security-jwt") implementation("io.micronaut.security:micronaut-security-ldap") + implementation("io.micronaut.serde:micronaut-serde-jackson") + implementation("io.micronaut.validation:micronaut-validation") + implementation("io.micronaut.openapi:micronaut-openapi") implementation("io.swagger.core.v3:swagger-annotations") implementation("jakarta.annotation:jakarta.annotation-api") - implementation("io.micronaut.openapi:micronaut-openapi") - implementation("io.micronaut.reactor:micronaut-reactor") + implementation("jakarta.validation:jakarta.validation-api") compileOnly("org.projectlombok:lombok") compileOnly("com.google.code.findbugs:jsr305") // https://github.com/micronaut-projects/micronaut-core/pull/5691 runtimeOnly("ch.qos.logback:logback-classic") + runtimeOnly("org.yaml:snakeyaml") + testImplementation("io.micronaut:micronaut-http-client") testImplementation("org.mockito:mockito-core") testImplementation("org.testcontainers:junit-jupiter") testImplementation("org.testcontainers:testcontainers") @@ -45,7 +52,6 @@ dependencies { } testImplementation("org.mockito:mockito-junit-jupiter:5.5.0") testImplementation("io.projectreactor:reactor-test") - testAnnotationProcessor("org.projectlombok:lombok") testCompileOnly("org.projectlombok:lombok") } @@ -107,14 +113,14 @@ sonarqube { jacocoTestReport { dependsOn test reports { - html.enabled true - xml.enabled true + html.required = true + xml.required = true } } test { reports { - html.enabled false + html.required = false } } diff --git a/gradle.properties b/gradle.properties index b54c62c6..54734fe8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -micronautVersion=3.9.2 \ No newline at end of file +micronautVersion=4.1.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832..033e24c4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661e..cef6c224 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +networkTimeout=100000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb6..fcb6fca1 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +130,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,6 +197,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/gradlew.bat b/gradlew.bat index 53a6b238..6689b85b 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% diff --git a/micronaut-cli.yml b/micronaut-cli.yml index f66ede51..066d2650 100644 --- a/micronaut-cli.yml +++ b/micronaut-cli.yml @@ -3,4 +3,4 @@ defaultPackage: com.michelin.ns4kafka testFramework: junit sourceLanguage: java buildTool: gradle -features: [annotation-api, app-name, gradle, http-client, java, java-application, junit, kafka, logback, netty-server, openapi, reactor, reactor-http-client, readme, security, security-annotations, security-jwt, security-ldap, shade, yaml] +features: [annotation-api, app-name, gradle, http-client, java, java-application, junit, kafka, logback, lombok, micronaut-aot, micronaut-build, micronaut-http-validation, netty-server, openapi, properties, reactor, reactor-http-client, readme, security, security-annotations, security-jwt, security-ldap, serialization-jackson, shade, test-resources, validation] diff --git a/src/main/java/com/michelin/ns4kafka/config/BeanFactoryConfig.java b/src/main/java/com/michelin/ns4kafka/config/BeanFactoryConfig.java new file mode 100644 index 00000000..fca579cb --- /dev/null +++ b/src/main/java/com/michelin/ns4kafka/config/BeanFactoryConfig.java @@ -0,0 +1,40 @@ +package com.michelin.ns4kafka.config; + +import io.micronaut.context.annotation.Bean; +import io.micronaut.context.annotation.Factory; +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.type.Argument; +import io.micronaut.serde.Decoder; +import io.micronaut.serde.Deserializer; +import io.micronaut.serde.Serializer; +import io.micronaut.serde.exceptions.SerdeException; + +import java.io.IOException; +import java.text.NumberFormat; +import java.text.ParseException; + +@Factory +public class BeanFactoryConfig { + @Bean + public Deserializer serializerNumber() { + return new Deserializer<>() { + @Override + public @Nullable Number deserialize(@NonNull Decoder decoder, + @NonNull DecoderContext context, + @NonNull Argument type) throws + IOException { + try { + return NumberFormat.getInstance().parse(decoder.decodeString()); + } catch (ParseException e) { + throw new SerdeException("Error decoding number of type " + type + ":" + e.getMessage(), e); + } + } + }; + } + + @Bean + public Serializer serializer() { + return (encoder, context, type, value) -> encoder.encodeString(NumberFormat.getInstance().format(value)); + } +} diff --git a/src/main/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderController.java b/src/main/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderController.java index 3e9ecec5..f774f9d3 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderController.java @@ -1,23 +1,23 @@ package com.michelin.ns4kafka.controllers; -import com.michelin.ns4kafka.config.AkhqClaimProviderControllerConfig; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; import com.michelin.ns4kafka.models.AccessControlEntry; +import com.michelin.ns4kafka.properties.AkhqClaimProviderControllerProperties; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.services.AccessControlEntryService; import com.michelin.ns4kafka.services.NamespaceService; -import io.micronaut.core.annotation.Introspected; import io.micronaut.http.annotation.Body; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; import io.micronaut.security.rules.SecurityRule; +import io.micronaut.serde.annotation.Serdeable; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; +import jakarta.validation.Valid; import lombok.Builder; import lombok.Data; import lombok.Getter; -import javax.annotation.security.RolesAllowed; -import javax.validation.Valid; import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -31,7 +31,7 @@ public class AkhqClaimProviderController { private static final List ADMIN_REGEXP = List.of(".*"); @Inject - AkhqClaimProviderControllerConfig config; + AkhqClaimProviderControllerProperties config; @Inject AccessControlEntryService accessControlEntryService; @@ -40,7 +40,7 @@ public class AkhqClaimProviderController { NamespaceService namespaceService; @Inject - List managedClusters; + List managedClusters; /** * List AKHQ claims (v019 and prior) @@ -292,9 +292,9 @@ private static void optimizeACL(List acl) { .anyMatch(escapedString -> accessControlEntry.getSpec().getResource().startsWith(escapedString))); } - @Introspected - @Builder @Getter + @Builder + @Serdeable public static class AKHQClaimRequest { String providerType; String providerName; @@ -302,9 +302,9 @@ public static class AKHQClaimRequest { List groups; } - @Introspected - @Builder @Getter + @Builder + @Serdeable public static class AKHQClaimResponse { private List roles; private Map> attributes; @@ -335,9 +335,9 @@ public static AKHQClaimResponse ofAdmin(List roles) { } } - @Introspected - @Builder @Getter + @Builder + @Serdeable public static class AKHQClaimResponseV2 { private List roles; private List topicsFilterRegexp; @@ -364,9 +364,9 @@ public static AKHQClaimResponseV2 ofAdmin(List roles) { } } - @Introspected - @Builder @Getter + @Builder + @Serdeable public static class AKHQClaimResponseV3 { private Map> groups; @@ -380,7 +380,7 @@ public static AKHQClaimResponseV3 ofAdmin(Map patterns; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/ApiResourcesController.java b/src/main/java/com/michelin/ns4kafka/controllers/ApiResourcesController.java index 99419752..77929add 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/ApiResourcesController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/ApiResourcesController.java @@ -9,16 +9,16 @@ import io.micronaut.http.annotation.Get; import io.micronaut.security.authentication.Authentication; import io.micronaut.security.rules.SecurityRule; +import io.micronaut.serde.annotation.Serdeable; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import javax.annotation.security.RolesAllowed; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; @Tag(name = "Resources", description = "Manage the API resources.") @RolesAllowed(SecurityRule.IS_ANONYMOUS) @@ -170,10 +170,11 @@ public List list(@Nullable Authentication authentication) { .toList(); } - @Introspected - @Builder @Getter @Setter + @Builder + @Serdeable + @Introspected public static class ResourceDefinition { private String kind; private boolean namespaced; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/ConnectorController.java b/src/main/java/com/michelin/ns4kafka/controllers/ConnectorController.java index 163bafc1..336c5218 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/ConnectorController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/ConnectorController.java @@ -19,7 +19,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.Date; import java.util.List; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/ConsumerGroupController.java b/src/main/java/com/michelin/ns4kafka/controllers/ConsumerGroupController.java index cfbacd2b..cda7ef24 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/ConsumerGroupController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/ConsumerGroupController.java @@ -15,7 +15,7 @@ import jakarta.inject.Inject; import org.apache.kafka.common.TopicPartition; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.Date; import java.util.List; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/ExceptionHandlerController.java b/src/main/java/com/michelin/ns4kafka/controllers/ExceptionHandlerController.java index 74af3313..1d19e53c 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/ExceptionHandlerController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/ExceptionHandlerController.java @@ -14,10 +14,10 @@ import io.micronaut.security.authentication.AuthorizationException; import lombok.extern.slf4j.Slf4j; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.ElementKind; -import javax.validation.Path; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.ElementKind; +import jakarta.validation.Path; import java.util.Iterator; import java.util.List; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/NamespaceController.java b/src/main/java/com/michelin/ns4kafka/controllers/NamespaceController.java index 9e496364..4df03541 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/NamespaceController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/NamespaceController.java @@ -11,8 +11,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; -import javax.annotation.security.RolesAllowed; -import javax.validation.Valid; +import jakarta.annotation.security.RolesAllowed; +import jakarta.validation.Valid; import java.time.Instant; import java.util.ArrayList; import java.util.Date; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/RoleBindingController.java b/src/main/java/com/michelin/ns4kafka/controllers/RoleBindingController.java index 5ab9d959..c1494d8f 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/RoleBindingController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/RoleBindingController.java @@ -14,7 +14,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.Date; import java.util.List; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/SchemaController.java b/src/main/java/com/michelin/ns4kafka/controllers/SchemaController.java index ceb64a54..50f409ea 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/SchemaController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/SchemaController.java @@ -19,7 +19,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.Date; import java.util.List; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/StreamController.java b/src/main/java/com/michelin/ns4kafka/controllers/StreamController.java index 2b446a19..28ffc6c5 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/StreamController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/StreamController.java @@ -12,7 +12,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.Date; import java.util.List; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/acl/AclController.java b/src/main/java/com/michelin/ns4kafka/controllers/acl/AclController.java index 7ff39ba3..55e6f92a 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/acl/AclController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/acl/AclController.java @@ -15,7 +15,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.Comparator; import java.util.Date; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/acl/AclNonNamespacedController.java b/src/main/java/com/michelin/ns4kafka/controllers/acl/AclNonNamespacedController.java index fabf2a39..44bedc8e 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/acl/AclNonNamespacedController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/acl/AclNonNamespacedController.java @@ -9,7 +9,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; -import javax.annotation.security.RolesAllowed; +import jakarta.annotation.security.RolesAllowed; import java.util.List; @Tag(name = "ACLs", description = "Manage the ACLs.") diff --git a/src/main/java/com/michelin/ns4kafka/controllers/connect/ConnectClusterController.java b/src/main/java/com/michelin/ns4kafka/controllers/connect/ConnectClusterController.java index de8967ff..51c88b3b 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/connect/ConnectClusterController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/connect/ConnectClusterController.java @@ -19,7 +19,7 @@ import jakarta.inject.Inject; import reactor.core.publisher.Mono; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.ArrayList; import java.util.Date; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/connect/ConnectClusterNonNamespacedController.java b/src/main/java/com/michelin/ns4kafka/controllers/connect/ConnectClusterNonNamespacedController.java index ec202808..58c14d67 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/connect/ConnectClusterNonNamespacedController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/connect/ConnectClusterNonNamespacedController.java @@ -13,7 +13,7 @@ import jakarta.inject.Inject; import reactor.core.publisher.Flux; -import javax.annotation.security.RolesAllowed; +import jakarta.annotation.security.RolesAllowed; @Tag(name = "Connect Clusters", description = "Manage the Kafka Connect clusters.") @Controller(value = "/api/connect-clusters") diff --git a/src/main/java/com/michelin/ns4kafka/controllers/quota/ResourceQuotaController.java b/src/main/java/com/michelin/ns4kafka/controllers/quota/ResourceQuotaController.java index e4d37d15..640cd44c 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/quota/ResourceQuotaController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/quota/ResourceQuotaController.java @@ -15,7 +15,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.Date; import java.util.List; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/quota/ResourceQuotaNonNamespacedController.java b/src/main/java/com/michelin/ns4kafka/controllers/quota/ResourceQuotaNonNamespacedController.java index 054e5380..24a57906 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/quota/ResourceQuotaNonNamespacedController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/quota/ResourceQuotaNonNamespacedController.java @@ -9,7 +9,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; -import javax.annotation.security.RolesAllowed; +import jakarta.annotation.security.RolesAllowed; import java.util.List; @Tag(name = "Quotas", description = "Manage the resource quotas.") diff --git a/src/main/java/com/michelin/ns4kafka/controllers/topic/TopicController.java b/src/main/java/com/michelin/ns4kafka/controllers/topic/TopicController.java index a2b443d2..5dd36aff 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/topic/TopicController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/topic/TopicController.java @@ -15,7 +15,7 @@ import jakarta.inject.Inject; import org.apache.kafka.common.TopicPartition; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.time.Instant; import java.util.*; import java.util.concurrent.ExecutionException; diff --git a/src/main/java/com/michelin/ns4kafka/controllers/topic/TopicNonNamespacedController.java b/src/main/java/com/michelin/ns4kafka/controllers/topic/TopicNonNamespacedController.java index 792ff267..5c634ad9 100644 --- a/src/main/java/com/michelin/ns4kafka/controllers/topic/TopicNonNamespacedController.java +++ b/src/main/java/com/michelin/ns4kafka/controllers/topic/TopicNonNamespacedController.java @@ -9,7 +9,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; -import javax.annotation.security.RolesAllowed; +import jakarta.annotation.security.RolesAllowed; import java.util.List; @Tag(name = "Topics", description = "Manage the topics.") diff --git a/src/main/java/com/michelin/ns4kafka/models/AccessControlEntry.java b/src/main/java/com/michelin/ns4kafka/models/AccessControlEntry.java index d4b09188..b5740fb9 100644 --- a/src/main/java/com/michelin/ns4kafka/models/AccessControlEntry.java +++ b/src/main/java/com/michelin/ns4kafka/models/AccessControlEntry.java @@ -1,17 +1,19 @@ package com.michelin.ns4kafka.models; -import io.micronaut.core.annotation.Introspected; -import lombok.*; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -@Introspected +@Data @Builder +@Serdeable @NoArgsConstructor @AllArgsConstructor -@Data public class AccessControlEntry { private final String apiVersion = "v1"; private final String kind = "AccessControlEntry"; @@ -24,11 +26,11 @@ public class AccessControlEntry { @NotNull private AccessControlEntrySpec spec; - @Introspected + @Data @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor - @Data + @AllArgsConstructor public static class AccessControlEntrySpec { @NotNull protected ResourceType resourceType; diff --git a/src/main/java/com/michelin/ns4kafka/models/DeleteRecordsResponse.java b/src/main/java/com/michelin/ns4kafka/models/DeleteRecordsResponse.java index bea9022a..4438209d 100644 --- a/src/main/java/com/michelin/ns4kafka/models/DeleteRecordsResponse.java +++ b/src/main/java/com/michelin/ns4kafka/models/DeleteRecordsResponse.java @@ -1,14 +1,13 @@ package com.michelin.ns4kafka.models; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - @Getter @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class DeleteRecordsResponse { @@ -23,12 +22,12 @@ public class DeleteRecordsResponse { @NotNull private DeleteRecordsResponseSpec spec; - @Introspected @Builder - @AllArgsConstructor - @NoArgsConstructor @Getter @ToString + @Serdeable + @NoArgsConstructor + @AllArgsConstructor public static class DeleteRecordsResponseSpec { private String topic; private int partition; diff --git a/src/main/java/com/michelin/ns4kafka/models/KafkaStream.java b/src/main/java/com/michelin/ns4kafka/models/KafkaStream.java index ef58c6aa..9b61b346 100644 --- a/src/main/java/com/michelin/ns4kafka/models/KafkaStream.java +++ b/src/main/java/com/michelin/ns4kafka/models/KafkaStream.java @@ -1,14 +1,16 @@ package com.michelin.ns4kafka.models; -import io.micronaut.core.annotation.Introspected; -import lombok.*; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class KafkaStream { diff --git a/src/main/java/com/michelin/ns4kafka/models/KafkaUserResetPassword.java b/src/main/java/com/michelin/ns4kafka/models/KafkaUserResetPassword.java index c8bf6311..d2b4b14a 100644 --- a/src/main/java/com/michelin/ns4kafka/models/KafkaUserResetPassword.java +++ b/src/main/java/com/michelin/ns4kafka/models/KafkaUserResetPassword.java @@ -1,12 +1,12 @@ package com.michelin.ns4kafka.models; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; import lombok.*; @Getter @Setter @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class KafkaUserResetPassword { @@ -15,11 +15,11 @@ public class KafkaUserResetPassword { private ObjectMeta metadata; private KafkaUserResetPasswordSpec spec; - @Introspected + @Getter @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor - @Getter + @AllArgsConstructor public static class KafkaUserResetPasswordSpec { private String newPassword; } diff --git a/src/main/java/com/michelin/ns4kafka/models/Namespace.java b/src/main/java/com/michelin/ns4kafka/models/Namespace.java index af6d277c..cfaeb90d 100644 --- a/src/main/java/com/michelin/ns4kafka/models/Namespace.java +++ b/src/main/java/com/michelin/ns4kafka/models/Namespace.java @@ -2,20 +2,20 @@ import com.michelin.ns4kafka.validation.ConnectValidator; import com.michelin.ns4kafka.validation.TopicValidator; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; import java.util.List; @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class Namespace { @@ -32,8 +32,9 @@ public class Namespace { @Data @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor + @AllArgsConstructor public static class NamespaceSpec { @NotBlank private String kafkaUser; @@ -42,4 +43,4 @@ public static class NamespaceSpec { private TopicValidator topicValidator; private ConnectValidator connectValidator; } -} \ No newline at end of file +} diff --git a/src/main/java/com/michelin/ns4kafka/models/ObjectMeta.java b/src/main/java/com/michelin/ns4kafka/models/ObjectMeta.java index e1853e54..69930952 100644 --- a/src/main/java/com/michelin/ns4kafka/models/ObjectMeta.java +++ b/src/main/java/com/michelin/ns4kafka/models/ObjectMeta.java @@ -1,17 +1,16 @@ package com.michelin.ns4kafka.models; -import com.fasterxml.jackson.annotation.JsonFormat; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import lombok.*; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; import java.util.Date; import java.util.Map; @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class ObjectMeta { @@ -24,7 +23,6 @@ public class ObjectMeta { @EqualsAndHashCode.Exclude private int generation; @EqualsAndHashCode.Exclude - @JsonFormat(shape = JsonFormat.Shape.STRING) private Date creationTimestamp; } diff --git a/src/main/java/com/michelin/ns4kafka/models/RoleBinding.java b/src/main/java/com/michelin/ns4kafka/models/RoleBinding.java index 536082e6..993448fd 100644 --- a/src/main/java/com/michelin/ns4kafka/models/RoleBinding.java +++ b/src/main/java/com/michelin/ns4kafka/models/RoleBinding.java @@ -1,23 +1,23 @@ package com.michelin.ns4kafka.models; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; import java.util.Collection; -@Introspected(classes = {RoleBinding.class, RoleBinding.RoleBindingSpec.class, RoleBinding.Role.class, RoleBinding.Subject.class}) +@Data @Builder +@Serdeable @AllArgsConstructor @NoArgsConstructor -@Data public class RoleBinding { private final String apiVersion = "v1"; private final String kind = "RoleBinding"; @@ -30,10 +30,11 @@ public class RoleBinding { @NotNull private RoleBindingSpec spec; + @Data @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor - @Data + @AllArgsConstructor public static class RoleBindingSpec { @Valid @NotNull @@ -44,10 +45,11 @@ public static class RoleBindingSpec { private Subject subject; } + @Data @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor - @Data + @AllArgsConstructor public static class Role { @NotNull @NotEmpty @@ -58,10 +60,11 @@ public static class Role { private Collection verbs; } + @Data @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor - @Data + @AllArgsConstructor public static class Subject { @NotNull private SubjectType subjectType; diff --git a/src/main/java/com/michelin/ns4kafka/models/Status.java b/src/main/java/com/michelin/ns4kafka/models/Status.java index 475c8bba..03797ea0 100644 --- a/src/main/java/com/michelin/ns4kafka/models/Status.java +++ b/src/main/java/com/michelin/ns4kafka/models/Status.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.models; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,7 +10,7 @@ @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class Status { @@ -22,10 +22,11 @@ public class Status { private StatusDetails details; private int code; + @Data @Builder + @Serdeable @AllArgsConstructor @NoArgsConstructor - @Data public static class StatusDetails { private String name; private String kind; diff --git a/src/main/java/com/michelin/ns4kafka/models/Topic.java b/src/main/java/com/michelin/ns4kafka/models/Topic.java index 487916e5..7c55d3d8 100644 --- a/src/main/java/com/michelin/ns4kafka/models/Topic.java +++ b/src/main/java/com/michelin/ns4kafka/models/Topic.java @@ -1,19 +1,18 @@ package com.michelin.ns4kafka.models; -import com.fasterxml.jackson.annotation.JsonFormat; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; import java.time.Instant; import java.util.Date; import java.util.Map; @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class Topic { @@ -30,27 +29,27 @@ public class Topic { @EqualsAndHashCode.Exclude private TopicStatus status; + @Data @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor - @Data + @AllArgsConstructor public static class TopicSpec { private int replicationFactor; private int partitions; private Map configs; } - @Builder - @AllArgsConstructor - @NoArgsConstructor @Getter @Setter + @Builder + @Serdeable + @NoArgsConstructor + @AllArgsConstructor @Schema(description = "Server-side", accessMode = Schema.AccessMode.READ_ONLY) public static class TopicStatus { private TopicPhase phase; private String message; - - @JsonFormat(shape = JsonFormat.Shape.STRING) private Date lastUpdateTime; /** diff --git a/src/main/java/com/michelin/ns4kafka/models/connect/cluster/ConnectCluster.java b/src/main/java/com/michelin/ns4kafka/models/connect/cluster/ConnectCluster.java index e6583fb8..1233b339 100644 --- a/src/main/java/com/michelin/ns4kafka/models/connect/cluster/ConnectCluster.java +++ b/src/main/java/com/michelin/ns4kafka/models/connect/cluster/ConnectCluster.java @@ -1,15 +1,14 @@ package com.michelin.ns4kafka.models.connect.cluster; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class ConnectCluster { @@ -20,13 +19,15 @@ public class ConnectCluster { @NotNull private ObjectMeta metadata; + @Valid @NotNull private ConnectClusterSpec spec; + @Data @Builder + @Serdeable @AllArgsConstructor @NoArgsConstructor - @Data public static class ConnectClusterSpec { /** * Gets or sets the Kafka Connect Cluster url. diff --git a/src/main/java/com/michelin/ns4kafka/models/connect/cluster/VaultResponse.java b/src/main/java/com/michelin/ns4kafka/models/connect/cluster/VaultResponse.java index a82aa71d..599402a1 100644 --- a/src/main/java/com/michelin/ns4kafka/models/connect/cluster/VaultResponse.java +++ b/src/main/java/com/michelin/ns4kafka/models/connect/cluster/VaultResponse.java @@ -2,28 +2,22 @@ import com.michelin.ns4kafka.models.ObjectMeta; import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * Represents the Kafka Connect Cluster Vault Response. */ @Getter @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class VaultResponse { - /** - * The API version. - */ private final String apiVersion = "v1"; - - /** - * The Vault Response ns4kafka kind. - */ private final String kind = "VaultResponse"; /** @@ -43,12 +37,12 @@ public class VaultResponse { /** * Represents the vault response specification. */ - @Introspected + @Getter @Builder + @ToString + @Introspected @AllArgsConstructor @NoArgsConstructor - @Getter - @ToString public static class VaultResponseSpec { /** * The clear text to encrypt. diff --git a/src/main/java/com/michelin/ns4kafka/models/connector/ChangeConnectorState.java b/src/main/java/com/michelin/ns4kafka/models/connector/ChangeConnectorState.java index 91c7a4cd..08316124 100644 --- a/src/main/java/com/michelin/ns4kafka/models/connector/ChangeConnectorState.java +++ b/src/main/java/com/michelin/ns4kafka/models/connector/ChangeConnectorState.java @@ -1,19 +1,18 @@ package com.michelin.ns4kafka.models.connector; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; import io.micronaut.http.HttpStatus; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class ChangeConnectorState { @@ -27,11 +26,12 @@ public class ChangeConnectorState { @Valid @NotNull private ChangeConnectorStateSpec spec; + private ChangeConnectorStateStatus status; @Data @Builder - @Introspected + @Serdeable @AllArgsConstructor @NoArgsConstructor public static class ChangeConnectorStateSpec { @@ -41,7 +41,7 @@ public static class ChangeConnectorStateSpec { @Data @Builder - @Introspected + @Serdeable @AllArgsConstructor @NoArgsConstructor public static class ChangeConnectorStateStatus { diff --git a/src/main/java/com/michelin/ns4kafka/models/connector/Connector.java b/src/main/java/com/michelin/ns4kafka/models/connector/Connector.java index ce8e3725..bfdfb30d 100644 --- a/src/main/java/com/michelin/ns4kafka/models/connector/Connector.java +++ b/src/main/java/com/michelin/ns4kafka/models/connector/Connector.java @@ -1,21 +1,20 @@ package com.michelin.ns4kafka.models.connector; -import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; import java.util.Date; import java.util.List; import java.util.Map; @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class Connector { @@ -33,10 +32,11 @@ public class Connector { @EqualsAndHashCode.Exclude private ConnectorStatus status; + @Data @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor - @Data + @AllArgsConstructor public static class ConnectorSpec { @NotBlank private String connectCluster; @@ -46,26 +46,26 @@ public static class ConnectorSpec { private Map config; } + @Getter + @Setter @Builder + @Serdeable @AllArgsConstructor @NoArgsConstructor - @Getter - @Setter public static class ConnectorStatus { private TaskState state; private String worker_id; private List tasks; - - @JsonFormat(shape = JsonFormat.Shape.STRING) private Date lastUpdateTime; } - @Builder - @AllArgsConstructor - @NoArgsConstructor @Getter @Setter + @Builder + @Serdeable + @NoArgsConstructor + @AllArgsConstructor public static class TaskStatus { String id; TaskState state; diff --git a/src/main/java/com/michelin/ns4kafka/models/consumer/group/ConsumerGroupResetOffsets.java b/src/main/java/com/michelin/ns4kafka/models/consumer/group/ConsumerGroupResetOffsets.java index f84d1204..4c53199a 100644 --- a/src/main/java/com/michelin/ns4kafka/models/consumer/group/ConsumerGroupResetOffsets.java +++ b/src/main/java/com/michelin/ns4kafka/models/consumer/group/ConsumerGroupResetOffsets.java @@ -2,15 +2,16 @@ import com.michelin.ns4kafka.models.ObjectMeta; import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class ConsumerGroupResetOffsets { @@ -29,7 +30,7 @@ public class ConsumerGroupResetOffsets { @Setter @Builder @ToString - @Introspected + @Serdeable @AllArgsConstructor @NoArgsConstructor public static class ConsumerGroupResetOffsetsSpec { @@ -39,6 +40,7 @@ public static class ConsumerGroupResetOffsetsSpec { @NotNull private ResetOffsetsMethod method; + private String options; } diff --git a/src/main/java/com/michelin/ns4kafka/models/consumer/group/ConsumerGroupResetOffsetsResponse.java b/src/main/java/com/michelin/ns4kafka/models/consumer/group/ConsumerGroupResetOffsetsResponse.java index 01204745..26286a25 100644 --- a/src/main/java/com/michelin/ns4kafka/models/consumer/group/ConsumerGroupResetOffsetsResponse.java +++ b/src/main/java/com/michelin/ns4kafka/models/consumer/group/ConsumerGroupResetOffsetsResponse.java @@ -1,15 +1,14 @@ package com.michelin.ns4kafka.models.consumer.group; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -@Introspected -@Builder @Getter +@Builder +@Serdeable @NoArgsConstructor @AllArgsConstructor public class ConsumerGroupResetOffsetsResponse { @@ -37,12 +36,12 @@ public class ConsumerGroupResetOffsetsResponse { @NotNull private ConsumerGroupResetOffsetsResponseSpec spec; - @Introspected - @Builder - @AllArgsConstructor - @NoArgsConstructor @Getter + @Builder @ToString + @Serdeable + @NoArgsConstructor + @AllArgsConstructor public static class ConsumerGroupResetOffsetsResponseSpec { /** * The topic that was reset diff --git a/src/main/java/com/michelin/ns4kafka/models/quota/ResourceQuota.java b/src/main/java/com/michelin/ns4kafka/models/quota/ResourceQuota.java index a4a49845..33ea1688 100644 --- a/src/main/java/com/michelin/ns4kafka/models/quota/ResourceQuota.java +++ b/src/main/java/com/michelin/ns4kafka/models/quota/ResourceQuota.java @@ -1,18 +1,18 @@ package com.michelin.ns4kafka.models.quota; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; import java.util.Map; @Data @Builder -@Introspected -@AllArgsConstructor +@Serdeable @NoArgsConstructor +@AllArgsConstructor public class ResourceQuota { private final String apiVersion = "v1"; private final String kind = "ResourceQuota"; @@ -21,12 +21,11 @@ public class ResourceQuota { @NotNull private ObjectMeta metadata; - @Valid @NotNull private Map spec; @Getter - @Introspected + @Serdeable @AllArgsConstructor public enum ResourceQuotaSpecKey { COUNT_TOPICS("count/topics"), diff --git a/src/main/java/com/michelin/ns4kafka/models/quota/ResourceQuotaResponse.java b/src/main/java/com/michelin/ns4kafka/models/quota/ResourceQuotaResponse.java index 0aa09115..2e8ab96c 100644 --- a/src/main/java/com/michelin/ns4kafka/models/quota/ResourceQuotaResponse.java +++ b/src/main/java/com/michelin/ns4kafka/models/quota/ResourceQuotaResponse.java @@ -1,15 +1,14 @@ package com.michelin.ns4kafka.models.quota; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - @Getter @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class ResourceQuotaResponse { @@ -27,7 +26,7 @@ public class ResourceQuotaResponse { @Getter @Builder @ToString - @Introspected + @Serdeable @AllArgsConstructor @NoArgsConstructor public static class ResourceQuotaResponseSpec { diff --git a/src/main/java/com/michelin/ns4kafka/models/schema/Schema.java b/src/main/java/com/michelin/ns4kafka/models/schema/Schema.java index c4483924..bf8b81dc 100644 --- a/src/main/java/com/michelin/ns4kafka/models/schema/Schema.java +++ b/src/main/java/com/michelin/ns4kafka/models/schema/Schema.java @@ -1,16 +1,16 @@ package com.michelin.ns4kafka.models.schema; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; import java.util.List; @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class Schema { @@ -25,10 +25,11 @@ public class Schema { @NotNull private SchemaSpec spec; + @Data @Builder - @AllArgsConstructor + @Serdeable @NoArgsConstructor - @Data + @AllArgsConstructor public static class SchemaSpec { private Integer id; private Integer version; @@ -39,13 +40,15 @@ public static class SchemaSpec { @Builder.Default private Compatibility compatibility = Compatibility.GLOBAL; + private List references; - @Builder @Getter @Setter - @AllArgsConstructor + @Builder + @Serdeable @NoArgsConstructor + @AllArgsConstructor public static class Reference { private String name; private String subject; @@ -53,7 +56,6 @@ public static class Reference { } } - @Introspected public enum Compatibility { GLOBAL, BACKWARD, @@ -65,7 +67,6 @@ public enum Compatibility { NONE } - @Introspected public enum SchemaType { AVRO, JSON, diff --git a/src/main/java/com/michelin/ns4kafka/models/schema/SchemaCompatibilityState.java b/src/main/java/com/michelin/ns4kafka/models/schema/SchemaCompatibilityState.java index 7e9d76e8..6ac53ab9 100644 --- a/src/main/java/com/michelin/ns4kafka/models/schema/SchemaCompatibilityState.java +++ b/src/main/java/com/michelin/ns4kafka/models/schema/SchemaCompatibilityState.java @@ -1,15 +1,14 @@ package com.michelin.ns4kafka.models.schema; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -@Introspected @Builder @Getter +@Serdeable @NoArgsConstructor @AllArgsConstructor public class SchemaCompatibilityState { @@ -24,12 +23,12 @@ public class SchemaCompatibilityState { @NotNull private SchemaCompatibilityState.SchemaCompatibilityStateSpec spec; - @Introspected - @Builder - @AllArgsConstructor - @NoArgsConstructor @Getter + @Builder @ToString + @Serdeable + @NoArgsConstructor + @AllArgsConstructor public static class SchemaCompatibilityStateSpec { @Builder.Default private final Schema.Compatibility compatibility = Schema.Compatibility.GLOBAL; diff --git a/src/main/java/com/michelin/ns4kafka/models/schema/SchemaList.java b/src/main/java/com/michelin/ns4kafka/models/schema/SchemaList.java index 6d0255b8..ee9c378d 100644 --- a/src/main/java/com/michelin/ns4kafka/models/schema/SchemaList.java +++ b/src/main/java/com/michelin/ns4kafka/models/schema/SchemaList.java @@ -1,18 +1,17 @@ package com.michelin.ns4kafka.models.schema; import com.michelin.ns4kafka.models.ObjectMeta; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - @Data @Builder -@Introspected +@Serdeable @NoArgsConstructor @AllArgsConstructor public class SchemaList { diff --git a/src/main/java/com/michelin/ns4kafka/config/AkhqClaimProviderControllerConfig.java b/src/main/java/com/michelin/ns4kafka/properties/AkhqClaimProviderControllerProperties.java similarity index 78% rename from src/main/java/com/michelin/ns4kafka/config/AkhqClaimProviderControllerConfig.java rename to src/main/java/com/michelin/ns4kafka/properties/AkhqClaimProviderControllerProperties.java index 30e25294..27b5205a 100644 --- a/src/main/java/com/michelin/ns4kafka/config/AkhqClaimProviderControllerConfig.java +++ b/src/main/java/com/michelin/ns4kafka/properties/AkhqClaimProviderControllerProperties.java @@ -1,7 +1,8 @@ -package com.michelin.ns4kafka.config; +package com.michelin.ns4kafka.properties; import com.michelin.ns4kafka.models.AccessControlEntry; import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.serde.annotation.Serdeable; import lombok.Getter; import lombok.Setter; @@ -10,8 +11,9 @@ @Getter @Setter +@Serdeable @ConfigurationProperties("ns4kafka.akhq") -public class AkhqClaimProviderControllerConfig { +public class AkhqClaimProviderControllerProperties { private String groupLabel; private Map roles; private List formerRoles; diff --git a/src/main/java/com/michelin/ns4kafka/config/KafkaAsyncExecutorConfig.java b/src/main/java/com/michelin/ns4kafka/properties/KafkaAsyncExecutorProperties.java similarity index 82% rename from src/main/java/com/michelin/ns4kafka/config/KafkaAsyncExecutorConfig.java rename to src/main/java/com/michelin/ns4kafka/properties/KafkaAsyncExecutorProperties.java index 86060f1e..efea289a 100644 --- a/src/main/java/com/michelin/ns4kafka/config/KafkaAsyncExecutorConfig.java +++ b/src/main/java/com/michelin/ns4kafka/properties/KafkaAsyncExecutorProperties.java @@ -1,9 +1,9 @@ -package com.michelin.ns4kafka.config; +package com.michelin.ns4kafka.properties; import io.micronaut.context.annotation.ConfigurationProperties; import io.micronaut.context.annotation.EachProperty; import io.micronaut.context.annotation.Parameter; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; import lombok.Getter; import lombok.Setter; import org.apache.kafka.clients.admin.Admin; @@ -13,8 +13,9 @@ @Getter @Setter +@Serdeable @EachProperty("ns4kafka.managed-clusters") -public class KafkaAsyncExecutorConfig { +public class KafkaAsyncExecutorProperties { private String name; private boolean manageTopics; private boolean manageAcls; @@ -27,18 +28,18 @@ public class KafkaAsyncExecutorConfig { private RegistryConfig schemaRegistry; private Admin adminClient = null; - public KafkaAsyncExecutorConfig(@Parameter String name) { + public KafkaAsyncExecutorProperties(@Parameter String name) { this.name = name; } - public KafkaAsyncExecutorConfig(@Parameter String name, @Parameter KafkaProvider provider) { + public KafkaAsyncExecutorProperties(@Parameter String name, @Parameter KafkaProvider provider) { this.name = name; this.provider = provider; } @Getter @Setter - @Introspected + @Serdeable public static class ConnectConfig { String url; String basicAuthUsername; @@ -47,6 +48,7 @@ public static class ConnectConfig { @Getter @Setter + @Serdeable @ConfigurationProperties("schema-registry") public static class RegistryConfig { String url; diff --git a/src/main/java/com/michelin/ns4kafka/config/KafkaStoreConfig.java b/src/main/java/com/michelin/ns4kafka/properties/KafkaStoreProperties.java similarity index 84% rename from src/main/java/com/michelin/ns4kafka/config/KafkaStoreConfig.java rename to src/main/java/com/michelin/ns4kafka/properties/KafkaStoreProperties.java index 0d23f3b9..45cb6dee 100644 --- a/src/main/java/com/michelin/ns4kafka/config/KafkaStoreConfig.java +++ b/src/main/java/com/michelin/ns4kafka/properties/KafkaStoreProperties.java @@ -1,4 +1,4 @@ -package com.michelin.ns4kafka.config; +package com.michelin.ns4kafka.properties; import io.micronaut.context.annotation.ConfigurationProperties; import io.micronaut.core.convert.format.MapFormat; @@ -10,7 +10,7 @@ @Getter @Setter @ConfigurationProperties("ns4kafka.store.kafka.topics") -public class KafkaStoreConfig { +public class KafkaStoreProperties { private String prefix; private int replicationFactor; diff --git a/src/main/java/com/michelin/ns4kafka/config/SecurityConfig.java b/src/main/java/com/michelin/ns4kafka/properties/SecurityProperties.java similarity index 72% rename from src/main/java/com/michelin/ns4kafka/config/SecurityConfig.java rename to src/main/java/com/michelin/ns4kafka/properties/SecurityProperties.java index 6515cc26..451c2588 100644 --- a/src/main/java/com/michelin/ns4kafka/config/SecurityConfig.java +++ b/src/main/java/com/michelin/ns4kafka/properties/SecurityProperties.java @@ -1,7 +1,8 @@ -package com.michelin.ns4kafka.config; +package com.michelin.ns4kafka.properties; import com.michelin.ns4kafka.security.local.LocalUser; import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.serde.annotation.Serdeable; import lombok.Getter; import lombok.Setter; @@ -9,8 +10,9 @@ @Getter @Setter +@Serdeable @ConfigurationProperties("ns4kafka.security") -public class SecurityConfig { +public class SecurityProperties { private List localUsers; private String adminGroup; private String aes256EncryptionKey; diff --git a/src/main/java/com/michelin/ns4kafka/repositories/kafka/KafkaStore.java b/src/main/java/com/michelin/ns4kafka/repositories/kafka/KafkaStore.java index 1f1465be..d445f396 100644 --- a/src/main/java/com/michelin/ns4kafka/repositories/kafka/KafkaStore.java +++ b/src/main/java/com/michelin/ns4kafka/repositories/kafka/KafkaStore.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.repositories.kafka; -import com.michelin.ns4kafka.config.KafkaStoreConfig; +import com.michelin.ns4kafka.properties.KafkaStoreProperties; import io.micronaut.context.ApplicationContext; import io.micronaut.context.annotation.Property; import io.micronaut.scheduling.TaskExecutors; @@ -40,7 +40,7 @@ public abstract class KafkaStore { AdminClient adminClient; @Inject - KafkaStoreConfig kafkaStoreConfig; + KafkaStoreProperties kafkaStoreProperties; @Inject @Named(TaskExecutors.SCHEDULED) @@ -136,9 +136,9 @@ private void verifyInternalTopic() throws KafkaStoreException, InterruptedExcept throw new KafkaStoreException("The topic " + kafkaTopic + " should have only 1 partition but has " + numPartitions + "."); } - if (description.partitions().get(0).replicas().size() < kafkaStoreConfig.getReplicationFactor() && log.isWarnEnabled()) { + if (description.partitions().get(0).replicas().size() < kafkaStoreProperties.getReplicationFactor() && log.isWarnEnabled()) { log.warn("The replication factor of the topic " + kafkaTopic + " is less than the desired one of " - + kafkaStoreConfig.getReplicationFactor() + ". If this is a production environment, it's crucial to add more brokers and " + + kafkaStoreProperties.getReplicationFactor() + ". If this is a production environment, it's crucial to add more brokers and " + "increase the replication factor of the topic."); } @@ -180,16 +180,16 @@ private void createInternalTopic() throws KafkaStoreException, InterruptedExcept throw new KafkaStoreException("No live Kafka brokers."); } - int schemaTopicReplicationFactor = Math.min(numLiveBrokers, kafkaStoreConfig.getReplicationFactor()); - if (schemaTopicReplicationFactor < kafkaStoreConfig.getReplicationFactor() && log.isWarnEnabled()) { + int schemaTopicReplicationFactor = Math.min(numLiveBrokers, kafkaStoreProperties.getReplicationFactor()); + if (schemaTopicReplicationFactor < kafkaStoreProperties.getReplicationFactor() && log.isWarnEnabled()) { log.warn("Creating the kafkaTopic {}" + kafkaTopic + " using a replication factor of " + schemaTopicReplicationFactor + ", which is less than the desired one of " - + kafkaStoreConfig.getReplicationFactor() + ". If this is a production environment, it's " + + kafkaStoreProperties.getReplicationFactor() + ". If this is a production environment, it's " + "crucial to add more brokers and increase the replication factor of the kafkaTopic."); } NewTopic schemaTopicRequest = new NewTopic(kafkaTopic, 1, (short) schemaTopicReplicationFactor); - schemaTopicRequest.configs(kafkaStoreConfig.getProps()); + schemaTopicRequest.configs(kafkaStoreProperties.getProps()); try { adminClient.createTopics(Collections.singleton(schemaTopicRequest)) diff --git a/src/main/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRule.java b/src/main/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRule.java index 71833fab..79694be9 100644 --- a/src/main/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRule.java +++ b/src/main/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRule.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.security; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.models.RoleBinding; import com.michelin.ns4kafka.repositories.NamespaceRepository; import com.michelin.ns4kafka.repositories.RoleBindingRepository; @@ -11,7 +11,6 @@ import io.micronaut.security.authentication.Authentication; import io.micronaut.security.rules.SecurityRule; import io.micronaut.security.rules.SecurityRuleResult; -import io.micronaut.web.router.RouteMatch; import jakarta.inject.Inject; import jakarta.inject.Singleton; import lombok.extern.slf4j.Slf4j; @@ -25,13 +24,13 @@ @Slf4j @Singleton -public class ResourceBasedSecurityRule implements SecurityRule { +public class ResourceBasedSecurityRule implements SecurityRule> { public static final String IS_ADMIN = "isAdmin()"; private final Pattern namespacedResourcePattern = Pattern.compile("^\\/api\\/namespaces\\/(?[a-zA-Z0-9_-]+)\\/(?[a-z_-]+)(\\/([a-zA-Z0-9_.-]+)(\\/(?[a-z-]+))?)?$"); @Inject - SecurityConfig securityConfig; + SecurityProperties securityProperties; @Inject RoleBindingRepository roleBindingRepository; @@ -40,7 +39,7 @@ public class ResourceBasedSecurityRule implements SecurityRule { NamespaceRepository namespaceRepository; @Override - public Publisher check(HttpRequest request, RouteMatch routeMatch, Authentication authentication) { + public Publisher check(@Nullable HttpRequest request, @Nullable Authentication authentication) { return Publishers.just(checkSecurity(request, authentication)); } @@ -128,7 +127,7 @@ public int getOrder() { public List computeRolesFromGroups(List groups) { List roles = new ArrayList<>(); - if (groups.contains(securityConfig.getAdminGroup())) { + if (groups.contains(securityProperties.getAdminGroup())) { roles.add(ResourceBasedSecurityRule.IS_ADMIN); } diff --git a/src/main/java/com/michelin/ns4kafka/security/gitlab/GitlabAuthenticationProvider.java b/src/main/java/com/michelin/ns4kafka/security/gitlab/GitlabAuthenticationProvider.java index 6d7a1828..75a50bb2 100644 --- a/src/main/java/com/michelin/ns4kafka/security/gitlab/GitlabAuthenticationProvider.java +++ b/src/main/java/com/michelin/ns4kafka/security/gitlab/GitlabAuthenticationProvider.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.security.gitlab; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.security.ResourceBasedSecurityRule; import com.michelin.ns4kafka.services.RoleBindingService; import io.micronaut.core.annotation.Nullable; @@ -17,7 +17,7 @@ @Slf4j @Singleton -public class GitlabAuthenticationProvider implements AuthenticationProvider { +public class GitlabAuthenticationProvider implements AuthenticationProvider> { @Inject GitlabAuthenticationService gitlabAuthenticationService; @@ -28,7 +28,7 @@ public class GitlabAuthenticationProvider implements AuthenticationProvider { RoleBindingService roleBindingService; @Inject - SecurityConfig securityConfig; + SecurityProperties securityProperties; /** * Perform user authentication with GitLab @@ -47,7 +47,7 @@ public Publisher authenticate(@Nullable HttpRequest h .flatMap(username -> gitlabAuthenticationService.findAllGroups(token).collectList() .onErrorResume(error -> Mono.error(new AuthenticationException(new AuthenticationFailed("Cannot retrieve your GitLab groups")))) .flatMap(groups -> { - if (roleBindingService.listByGroups(groups).isEmpty() && !groups.contains(securityConfig.getAdminGroup())) { + if (roleBindingService.listByGroups(groups).isEmpty() && !groups.contains(securityProperties.getAdminGroup())) { log.debug("Error during authentication: user groups not found in any namespace"); return Mono.error(new AuthenticationException(new AuthenticationFailed("No namespace matches your GitLab groups"))); } else { diff --git a/src/main/java/com/michelin/ns4kafka/security/local/LocalUser.java b/src/main/java/com/michelin/ns4kafka/security/local/LocalUser.java index e828b0ce..f6beff2e 100644 --- a/src/main/java/com/michelin/ns4kafka/security/local/LocalUser.java +++ b/src/main/java/com/michelin/ns4kafka/security/local/LocalUser.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.security.local; -import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -12,26 +12,26 @@ import java.util.List; @Slf4j -@Introspected -@Builder @Getter @Setter +@Builder +@Serdeable public class LocalUser { String username; String password; List groups; - public boolean isValidPassword(String input_password) { + public boolean isValidPassword(String inputPassword) { log.debug("Verifying password for user {}", username); MessageDigest digest = null; try { digest = MessageDigest.getInstance("SHA-256"); byte[] encodedhash = digest.digest( - input_password.getBytes(StandardCharsets.UTF_8)); + inputPassword.getBytes(StandardCharsets.UTF_8)); StringBuilder hexString = new StringBuilder(2 * encodedhash.length); - for (int i = 0; i < encodedhash.length; i++) { - String hex = Integer.toHexString(0xff & encodedhash[i]); + for (byte b : encodedhash) { + String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } diff --git a/src/main/java/com/michelin/ns4kafka/security/local/LocalUserAuthenticationProvider.java b/src/main/java/com/michelin/ns4kafka/security/local/LocalUserAuthenticationProvider.java index 150b5799..d28adb22 100644 --- a/src/main/java/com/michelin/ns4kafka/security/local/LocalUserAuthenticationProvider.java +++ b/src/main/java/com/michelin/ns4kafka/security/local/LocalUserAuthenticationProvider.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.security.local; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.security.ResourceBasedSecurityRule; import io.micronaut.core.annotation.Nullable; import io.micronaut.http.HttpRequest; @@ -16,9 +16,9 @@ @Slf4j @Singleton -public class LocalUserAuthenticationProvider implements AuthenticationProvider { +public class LocalUserAuthenticationProvider implements AuthenticationProvider> { @Inject - SecurityConfig securityConfig; + SecurityProperties securityProperties; @Inject ResourceBasedSecurityRule resourceBasedSecurityRule; @@ -30,7 +30,7 @@ public Publisher authenticate(@Nullable HttpRequest h String password = authenticationRequest.getSecret().toString(); log.debug("Checking local authentication for user: {}", username); - Optional authenticatedUser = securityConfig.getLocalUsers().stream() + Optional authenticatedUser = securityProperties.getLocalUsers().stream() .filter(localUser -> localUser.getUsername().equals(username)) .filter(localUser -> localUser.isValidPassword(password)) .findFirst(); diff --git a/src/main/java/com/michelin/ns4kafka/services/ConnectClusterService.java b/src/main/java/com/michelin/ns4kafka/services/ConnectClusterService.java index 9fdb2565..88520e49 100644 --- a/src/main/java/com/michelin/ns4kafka/services/ConnectClusterService.java +++ b/src/main/java/com/michelin/ns4kafka/services/ConnectClusterService.java @@ -1,7 +1,7 @@ package com.michelin.ns4kafka.services; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.models.AccessControlEntry; import com.michelin.ns4kafka.models.Namespace; import com.michelin.ns4kafka.models.ObjectMeta; @@ -51,10 +51,10 @@ public class ConnectClusterService { ConnectClusterRepository connectClusterRepository; @Inject - List kafkaAsyncExecutorConfig; + List kafkaAsyncExecutorProperties; @Inject - SecurityConfig securityConfig; + SecurityProperties securityProperties; @Inject @Client @@ -69,7 +69,7 @@ public Flux findAll(boolean all) { List results = connectClusterRepository.findAll(); if (all) { - results.addAll(kafkaAsyncExecutorConfig + results.addAll(kafkaAsyncExecutorProperties .stream() .map(config -> config.getConnects().entrySet() .stream() @@ -142,9 +142,9 @@ public List findAllByNamespaceOwner(Namespace namespace) { var builder = ConnectCluster.ConnectClusterSpec.builder() .url(connectCluster.getSpec().getUrl()) .username(connectCluster.getSpec().getUsername()) - .password(EncryptionUtils.decryptAES256GCM(connectCluster.getSpec().getPassword(), securityConfig.getAes256EncryptionKey())) - .aes256Key(EncryptionUtils.decryptAES256GCM(connectCluster.getSpec().getAes256Key(), securityConfig.getAes256EncryptionKey())) - .aes256Salt(EncryptionUtils.decryptAES256GCM(connectCluster.getSpec().getAes256Salt(), securityConfig.getAes256EncryptionKey())) + .password(EncryptionUtils.decryptAES256GCM(connectCluster.getSpec().getPassword(), securityProperties.getAes256EncryptionKey())) + .aes256Key(EncryptionUtils.decryptAES256GCM(connectCluster.getSpec().getAes256Key(), securityProperties.getAes256EncryptionKey())) + .aes256Salt(EncryptionUtils.decryptAES256GCM(connectCluster.getSpec().getAes256Salt(), securityProperties.getAes256EncryptionKey())) .aes256Format(connectCluster.getSpec().getAes256Format()); try { @@ -210,19 +210,19 @@ public Optional findByNamespaceAndNameOwner(Namespace namespace, public ConnectCluster create(ConnectCluster connectCluster) { if (StringUtils.hasText(connectCluster.getSpec().getPassword())) { connectCluster.getSpec() - .setPassword(EncryptionUtils.encryptAES256GCM(connectCluster.getSpec().getPassword(), securityConfig.getAes256EncryptionKey())); + .setPassword(EncryptionUtils.encryptAES256GCM(connectCluster.getSpec().getPassword(), securityProperties.getAes256EncryptionKey())); } // encrypt aes256 key if present if (StringUtils.hasText(connectCluster.getSpec().getAes256Key())) { connectCluster.getSpec() - .setAes256Key(EncryptionUtils.encryptAES256GCM(connectCluster.getSpec().getAes256Key(), securityConfig.getAes256EncryptionKey())); + .setAes256Key(EncryptionUtils.encryptAES256GCM(connectCluster.getSpec().getAes256Key(), securityProperties.getAes256EncryptionKey())); } // encrypt aes256 salt if present if (StringUtils.hasText(connectCluster.getSpec().getAes256Salt())) { connectCluster.getSpec() - .setAes256Salt(EncryptionUtils.encryptAES256GCM(connectCluster.getSpec().getAes256Salt(), securityConfig.getAes256EncryptionKey())); + .setAes256Salt(EncryptionUtils.encryptAES256GCM(connectCluster.getSpec().getAes256Salt(), securityProperties.getAes256EncryptionKey())); } return connectClusterRepository.create(connectCluster); @@ -237,7 +237,7 @@ public ConnectCluster create(ConnectCluster connectCluster) { public Mono> validateConnectClusterCreation(ConnectCluster connectCluster) { List errors = new ArrayList<>(); - if (kafkaAsyncExecutorConfig.stream().anyMatch(cluster -> + if (kafkaAsyncExecutorProperties.stream().anyMatch(cluster -> cluster.getConnects().entrySet().stream().anyMatch(entry -> entry.getKey().equals(connectCluster.getMetadata().getName())))) { errors.add(String.format("A Kafka Connect is already defined globally with the name \"%s\". Please provide a different name.", connectCluster.getMetadata().getName())); } @@ -367,8 +367,8 @@ public List vaultPassword(final Namespace namespace, final String .toList(); } - final String aes256Key = EncryptionUtils.decryptAES256GCM(kafkaConnect.get().getSpec().getAes256Key(), securityConfig.getAes256EncryptionKey()); - final String aes256Salt = EncryptionUtils.decryptAES256GCM(kafkaConnect.get().getSpec().getAes256Salt(), securityConfig.getAes256EncryptionKey()); + final String aes256Key = EncryptionUtils.decryptAES256GCM(kafkaConnect.get().getSpec().getAes256Key(), securityProperties.getAes256EncryptionKey()); + final String aes256Salt = EncryptionUtils.decryptAES256GCM(kafkaConnect.get().getSpec().getAes256Salt(), securityProperties.getAes256EncryptionKey()); final String aes256Format = StringUtils.hasText(kafkaConnect.get().getSpec().getAes256Format()) ? kafkaConnect.get().getSpec().getAes256Format() : DEFAULT_FORMAT; diff --git a/src/main/java/com/michelin/ns4kafka/services/NamespaceService.java b/src/main/java/com/michelin/ns4kafka/services/NamespaceService.java index a9ccc385..d209338e 100644 --- a/src/main/java/com/michelin/ns4kafka/services/NamespaceService.java +++ b/src/main/java/com/michelin/ns4kafka/services/NamespaceService.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.services; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.models.Namespace; import com.michelin.ns4kafka.repositories.NamespaceRepository; import jakarta.inject.Inject; @@ -9,7 +9,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import java.util.stream.Stream; @Singleton @@ -18,7 +17,7 @@ public class NamespaceService { NamespaceRepository namespaceRepository; @Inject - List kafkaAsyncExecutorConfigList; + List kafkaAsyncExecutorPropertiesList; @Inject TopicService topicService; @@ -40,7 +39,7 @@ public class NamespaceService { public List validateCreation(Namespace namespace) { List validationErrors = new ArrayList<>(); - if (kafkaAsyncExecutorConfigList.stream().noneMatch(config -> config.getName().equals(namespace.getMetadata().getCluster()))) { + if (kafkaAsyncExecutorPropertiesList.stream().noneMatch(config -> config.getName().equals(namespace.getMetadata().getCluster()))) { validationErrors.add("Invalid value " + namespace.getMetadata().getCluster() + " for cluster: Cluster doesn't exist"); } @@ -72,7 +71,7 @@ public List validate(Namespace namespace) { * @return true it does, false otherwise */ private boolean connectClusterExists(String kafkaCluster, String connectCluster) { - return kafkaAsyncExecutorConfigList.stream() + return kafkaAsyncExecutorPropertiesList.stream() .anyMatch(kafkaAsyncExecutorConfig -> kafkaAsyncExecutorConfig.getName().equals(kafkaCluster) && kafkaAsyncExecutorConfig.getConnects().containsKey(connectCluster)); } @@ -90,8 +89,8 @@ public void delete(Namespace namespace) { } public List listAll() { - return kafkaAsyncExecutorConfigList.stream() - .map(KafkaAsyncExecutorConfig::getName) + return kafkaAsyncExecutorPropertiesList.stream() + .map(KafkaAsyncExecutorProperties::getName) .flatMap(s -> namespaceRepository.findAllForCluster(s).stream()) .toList(); } diff --git a/src/main/java/com/michelin/ns4kafka/services/TopicService.java b/src/main/java/com/michelin/ns4kafka/services/TopicService.java index 0a438288..b3748ed1 100644 --- a/src/main/java/com/michelin/ns4kafka/services/TopicService.java +++ b/src/main/java/com/michelin/ns4kafka/services/TopicService.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.services; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.models.AccessControlEntry; import com.michelin.ns4kafka.models.Namespace; import com.michelin.ns4kafka.models.Topic; @@ -32,7 +32,7 @@ public class TopicService { ApplicationContext applicationContext; @Inject - List kafkaAsyncExecutorConfig; + List kafkaAsyncExecutorProperties; /** * Find all topics @@ -159,12 +159,12 @@ public List validateTopicUpdate(Namespace namespace, Topic existingTopic newTopic.getSpec().getReplicationFactor(), existingTopic.getSpec().getReplicationFactor())); } - Optional topicCluster = kafkaAsyncExecutorConfig + Optional topicCluster = kafkaAsyncExecutorProperties .stream() .filter(cluster -> namespace.getMetadata().getCluster().equals(cluster.getName())) .findFirst(); - boolean confluentCloudCluster = topicCluster.isPresent() && topicCluster.get().getProvider().equals(KafkaAsyncExecutorConfig.KafkaProvider.CONFLUENT_CLOUD); + boolean confluentCloudCluster = topicCluster.isPresent() && topicCluster.get().getProvider().equals(KafkaAsyncExecutorProperties.KafkaProvider.CONFLUENT_CLOUD); if (confluentCloudCluster && existingTopic.getSpec().getConfigs().get(CLEANUP_POLICY_CONFIG).equals(CLEANUP_POLICY_DELETE) && newTopic.getSpec().getConfigs().get(CLEANUP_POLICY_CONFIG).equals(CLEANUP_POLICY_COMPACT)) { validationErrors.add(String.format("Invalid value %s for configuration cleanup.policy: Altering topic configuration from `delete` to `compact` is not currently supported. Please create a new topic with `compact` policy specified instead.", diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/KafkaConnectClient.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/KafkaConnectClient.java index 176e5e7d..b9d684cb 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/KafkaConnectClient.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/KafkaConnectClient.java @@ -1,7 +1,7 @@ package com.michelin.ns4kafka.services.clients.connect; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.models.connect.cluster.ConnectCluster; import com.michelin.ns4kafka.repositories.ConnectClusterRepository; import com.michelin.ns4kafka.services.clients.connect.entities.*; @@ -35,13 +35,13 @@ public class KafkaConnectClient { private HttpClient httpClient; @Inject - private List kafkaAsyncExecutorConfigs; + private List kafkaAsyncExecutorProperties; @Inject ConnectClusterRepository connectClusterRepository; @Inject - private SecurityConfig securityConfig; + private SecurityProperties securityProperties; /** * Get the Kafka connect version @@ -190,7 +190,7 @@ public Mono> resume(String kafkaCluster, String connectCluste * @return The Kafka Connect configuration */ public KafkaConnectClient.KafkaConnectHttpConfig getKafkaConnectConfig(String kafkaCluster, String connectCluster) { - Optional config = kafkaAsyncExecutorConfigs.stream() + Optional config = kafkaAsyncExecutorProperties.stream() .filter(kafkaAsyncExecutorConfig -> kafkaAsyncExecutorConfig.getName().equals(kafkaCluster)) .findFirst(); @@ -207,11 +207,11 @@ public KafkaConnectClient.KafkaConnectHttpConfig getKafkaConnectConfig(String ka return KafkaConnectClient.KafkaConnectHttpConfig.builder() .url(connectClusterOptional.get().getSpec().getUrl()) .username(connectClusterOptional.get().getSpec().getUsername()) - .password(EncryptionUtils.decryptAES256GCM(connectClusterOptional.get().getSpec().getPassword(), securityConfig.getAes256EncryptionKey())) + .password(EncryptionUtils.decryptAES256GCM(connectClusterOptional.get().getSpec().getPassword(), securityProperties.getAes256EncryptionKey())) .build(); } - KafkaAsyncExecutorConfig.ConnectConfig connectConfig = config.get().getConnects().get(connectCluster); + KafkaAsyncExecutorProperties.ConnectConfig connectConfig = config.get().getConnects().get(connectCluster); if (connectConfig == null) { throw new ResourceValidationException(List.of("Connect cluster \"" + connectCluster + "\" not found"), null, null); } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigInfo.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigInfo.java index 0444aca4..5545a3c7 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigInfo.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigInfo.java @@ -17,6 +17,8 @@ package com.michelin.ns4kafka.services.clients.connect.entities; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; +@Serdeable public record ConfigInfo(@JsonProperty("definition") ConfigKeyInfo configKey, @JsonProperty("value") ConfigValueInfo configValue) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigInfos.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigInfos.java index 62a1e41d..ca5d0c1a 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigInfos.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigInfos.java @@ -17,8 +17,10 @@ package com.michelin.ns4kafka.services.clients.connect.entities; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; import java.util.List; +@Serdeable public record ConfigInfos(String name, @JsonProperty("error_count") int errorCount, List groups, List configs) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigKeyInfo.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigKeyInfo.java index cd1ac20c..eb0a5672 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigKeyInfo.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigKeyInfo.java @@ -17,9 +17,11 @@ package com.michelin.ns4kafka.services.clients.connect.entities; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; import java.util.List; +@Serdeable public record ConfigKeyInfo(String name, String type, @JsonProperty("required") boolean required, @JsonProperty("default_value") String defaultValue, String importance, String documentation, String group, @JsonProperty("order_in_group") int orderInGroup, diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigValueInfo.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigValueInfo.java index e1ec72bf..0ead883b 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigValueInfo.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConfigValueInfo.java @@ -17,9 +17,11 @@ package com.michelin.ns4kafka.services.clients.connect.entities; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; import java.util.List; +@Serdeable public record ConfigValueInfo(String name, String value, @JsonProperty("recommended_values") List recommendedValues, List errors, @JsonProperty("visible") boolean visible) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorInfo.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorInfo.java index af3ff430..c0dbc010 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorInfo.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorInfo.java @@ -16,8 +16,11 @@ */ package com.michelin.ns4kafka.services.clients.connect.entities; +import io.micronaut.serde.annotation.Serdeable; + import java.util.List; import java.util.Map; +@Serdeable public record ConnectorInfo(String name, Map config, List tasks, ConnectorType type) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorPluginInfo.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorPluginInfo.java index 6178b25c..3b4d71c6 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorPluginInfo.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorPluginInfo.java @@ -17,6 +17,8 @@ package com.michelin.ns4kafka.services.clients.connect.entities; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; +@Serdeable public record ConnectorPluginInfo(@JsonProperty("class") String className, ConnectorType type, String version) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorSpecs.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorSpecs.java index 4a1c8b79..fada1b71 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorSpecs.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorSpecs.java @@ -2,10 +2,12 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; import java.util.Map; @Builder +@Serdeable public record ConnectorSpecs(@JsonAnyGetter @JsonInclude(value = JsonInclude.Include.NON_ABSENT) Map config) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorStateInfo.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorStateInfo.java index cd49f6c4..78e1f537 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorStateInfo.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorStateInfo.java @@ -18,11 +18,13 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; import lombok.Getter; import java.util.List; import java.util.Objects; +@Serdeable public record ConnectorStateInfo(String name, ConnectorState connector, List tasks, ConnectorType type) { @Getter @@ -40,6 +42,7 @@ public abstract static class AbstractState { } } + @Serdeable public static class ConnectorState extends AbstractState { public ConnectorState(@JsonProperty("state") String state, @JsonProperty("worker_id") String worker, @JsonProperty("msg") String msg) { @@ -48,10 +51,11 @@ public ConnectorState(@JsonProperty("state") String state, @JsonProperty("worker } @Getter + @Serdeable public static class TaskState extends AbstractState implements Comparable { - private final int id; + private final Integer id; - public TaskState(@JsonProperty("id") int id, @JsonProperty("state") String state, @JsonProperty("worker_id") String worker, + public TaskState(@JsonProperty("id") Integer id, @JsonProperty("state") String state, @JsonProperty("worker_id") String worker, @JsonProperty("msg") String msg) { super(state, worker, msg); this.id = id; diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorStatus.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorStatus.java index d3332213..73f86f5f 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorStatus.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorStatus.java @@ -1,4 +1,7 @@ package com.michelin.ns4kafka.services.clients.connect.entities; +import io.micronaut.serde.annotation.Serdeable; + +@Serdeable public record ConnectorStatus(ConnectorInfo info, ConnectorStateInfo status) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorTaskId.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorTaskId.java index 8b2ba95e..b4383f29 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorTaskId.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorTaskId.java @@ -17,6 +17,7 @@ package com.michelin.ns4kafka.services.clients.connect.entities; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; import java.io.Serializable; @@ -24,6 +25,7 @@ * Unique ID for a single task. It includes a unique connector ID and a task ID that is unique within * the connector. */ +@Serdeable public record ConnectorTaskId(@JsonProperty("connector") String connector, @JsonProperty("task") int task) implements Serializable, Comparable { @Override public int compareTo(ConnectorTaskId o) { diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorType.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorType.java index 11e95360..54934ed0 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorType.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ConnectorType.java @@ -18,9 +18,11 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import io.micronaut.serde.annotation.Serdeable; import java.util.Locale; +@Serdeable public enum ConnectorType { SOURCE, SINK, UNKNOWN; diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ServerInfo.java b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ServerInfo.java index 799ec15d..4f963bf3 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ServerInfo.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/connect/entities/ServerInfo.java @@ -17,8 +17,10 @@ package com.michelin.ns4kafka.services.clients.connect.entities; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; @Builder +@Serdeable public record ServerInfo(@JsonProperty("version") String version, @JsonProperty("commit") String commit, @JsonProperty("kafka_cluster_id") String kafkaClusterId) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/schema/SchemaRegistryClient.java b/src/main/java/com/michelin/ns4kafka/services/clients/schema/SchemaRegistryClient.java index c16a12e5..b16e067a 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/schema/SchemaRegistryClient.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/schema/SchemaRegistryClient.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.services.clients.schema; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.services.clients.schema.entities.*; import com.michelin.ns4kafka.utils.exceptions.ResourceValidationException; import io.micronaut.core.util.StringUtils; @@ -31,7 +31,7 @@ public class SchemaRegistryClient { private HttpClient httpClient; @Inject - private List kafkaAsyncExecutorConfigs; + private List kafkaAsyncExecutorProperties; /** * List subjects @@ -39,7 +39,7 @@ public class SchemaRegistryClient { * @return A list of subjects */ public Flux getSubjects(String kafkaCluster) { - KafkaAsyncExecutorConfig.RegistryConfig config = getSchemaRegistry(kafkaCluster); + KafkaAsyncExecutorProperties.RegistryConfig config = getSchemaRegistry(kafkaCluster); HttpRequest request = HttpRequest.GET(URI.create(StringUtils.prependUri(config.getUrl(), "/subjects"))) .basicAuth(config.getBasicAuthUsername(), config.getBasicAuthPassword()); return Flux.from(httpClient.retrieve(request, String[].class)).flatMap(Flux::fromArray); @@ -52,7 +52,7 @@ public Flux getSubjects(String kafkaCluster) { * @return A version of a subject */ public Mono getLatestSubject(String kafkaCluster, String subject) { - KafkaAsyncExecutorConfig.RegistryConfig config = getSchemaRegistry(kafkaCluster); + KafkaAsyncExecutorProperties.RegistryConfig config = getSchemaRegistry(kafkaCluster); HttpRequest request = HttpRequest.GET(URI.create(StringUtils.prependUri(config.getUrl(), SUBJECTS + subject + "/versions/latest"))) .basicAuth(config.getBasicAuthUsername(), config.getBasicAuthPassword()); return Mono.from(httpClient.retrieve(request, SchemaResponse.class)) @@ -68,7 +68,7 @@ public Mono getLatestSubject(String kafkaCluster, String subject * @return The response of the registration */ public Mono register(String kafkaCluster, String subject, SchemaRequest body) { - KafkaAsyncExecutorConfig.RegistryConfig config = getSchemaRegistry(kafkaCluster); + KafkaAsyncExecutorProperties.RegistryConfig config = getSchemaRegistry(kafkaCluster); HttpRequest request = HttpRequest.POST(URI.create(StringUtils.prependUri(config.getUrl(), SUBJECTS + subject + "/versions")), body) .basicAuth(config.getBasicAuthUsername(), config.getBasicAuthPassword()); return Mono.from(httpClient.retrieve(request, SchemaResponse.class)); @@ -82,7 +82,7 @@ public Mono register(String kafkaCluster, String subject, Schema * @return The versions of the deleted subject */ public Mono deleteSubject(String kafkaCluster, String subject, boolean hardDelete) { - KafkaAsyncExecutorConfig.RegistryConfig config = getSchemaRegistry(kafkaCluster); + KafkaAsyncExecutorProperties.RegistryConfig config = getSchemaRegistry(kafkaCluster); MutableHttpRequest request = HttpRequest.DELETE(URI.create(StringUtils.prependUri(config.getUrl(), SUBJECTS + subject + "?permanent=" + hardDelete))) .basicAuth(config.getBasicAuthUsername(), config.getBasicAuthPassword()); return Mono.from(httpClient.retrieve(request, Integer[].class)); @@ -96,7 +96,7 @@ public Mono deleteSubject(String kafkaCluster, String subject, boolea * @return The schema compatibility validation */ public Mono validateSchemaCompatibility(String kafkaCluster, String subject, SchemaRequest body) { - KafkaAsyncExecutorConfig.RegistryConfig config = getSchemaRegistry(kafkaCluster); + KafkaAsyncExecutorProperties.RegistryConfig config = getSchemaRegistry(kafkaCluster); HttpRequest request = HttpRequest.POST(URI.create(StringUtils.prependUri(config.getUrl(), "/compatibility/subjects/" + subject + "/versions?verbose=true")), body) .basicAuth(config.getBasicAuthUsername(), config.getBasicAuthPassword()); return Mono.from(httpClient.retrieve(request, SchemaCompatibilityCheckResponse.class)) @@ -112,7 +112,7 @@ public Mono validateSchemaCompatibility(String * @return The schema compatibility update */ public Mono updateSubjectCompatibility(String kafkaCluster, String subject, SchemaCompatibilityRequest body) { - KafkaAsyncExecutorConfig.RegistryConfig config = getSchemaRegistry(kafkaCluster); + KafkaAsyncExecutorProperties.RegistryConfig config = getSchemaRegistry(kafkaCluster); HttpRequest request = HttpRequest.PUT(URI.create(StringUtils.prependUri(config.getUrl(), CONFIG + subject)), body) .basicAuth(config.getBasicAuthUsername(), config.getBasicAuthPassword()); return Mono.from(httpClient.retrieve(request, SchemaCompatibilityResponse.class)); @@ -125,7 +125,7 @@ public Mono updateSubjectCompatibility(String kafka * @return The current schema compatibility */ public Mono getCurrentCompatibilityBySubject(String kafkaCluster, String subject) { - KafkaAsyncExecutorConfig.RegistryConfig config = getSchemaRegistry(kafkaCluster); + KafkaAsyncExecutorProperties.RegistryConfig config = getSchemaRegistry(kafkaCluster); HttpRequest request = HttpRequest.GET(URI.create(StringUtils.prependUri(config.getUrl(), CONFIG + subject))) .basicAuth(config.getBasicAuthUsername(), config.getBasicAuthPassword()); return Mono.from(httpClient.retrieve(request, SchemaCompatibilityResponse.class)) @@ -140,7 +140,7 @@ public Mono getCurrentCompatibilityBySubject(String * @return The deleted schema compatibility */ public Mono deleteCurrentCompatibilityBySubject(String kafkaCluster, String subject) { - KafkaAsyncExecutorConfig.RegistryConfig config = getSchemaRegistry(kafkaCluster); + KafkaAsyncExecutorProperties.RegistryConfig config = getSchemaRegistry(kafkaCluster); MutableHttpRequest request = HttpRequest.DELETE(URI.create(StringUtils.prependUri(config.getUrl(), CONFIG + subject))) .basicAuth(config.getBasicAuthUsername(), config.getBasicAuthPassword()); return Mono.from(httpClient.retrieve(request, SchemaCompatibilityResponse.class)); @@ -151,8 +151,8 @@ public Mono deleteCurrentCompatibilityBySubject(Str * @param kafkaCluster The Kafka cluster * @return The schema registry configuration */ - private KafkaAsyncExecutorConfig.RegistryConfig getSchemaRegistry(String kafkaCluster) { - Optional config = kafkaAsyncExecutorConfigs.stream() + private KafkaAsyncExecutorProperties.RegistryConfig getSchemaRegistry(String kafkaCluster) { + Optional config = kafkaAsyncExecutorProperties.stream() .filter(kafkaAsyncExecutorConfig -> kafkaAsyncExecutorConfig.getName().equals(kafkaCluster)) .findFirst(); diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityCheckResponse.java b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityCheckResponse.java index 3cc089c0..016cd349 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityCheckResponse.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityCheckResponse.java @@ -1,10 +1,12 @@ package com.michelin.ns4kafka.services.clients.schema.entities; import com.fasterxml.jackson.annotation.JsonProperty; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; import java.util.List; @Builder +@Serdeable public record SchemaCompatibilityCheckResponse(@JsonProperty("is_compatible") boolean isCompatible, List messages) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityRequest.java b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityRequest.java index 4b58667f..0715ed75 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityRequest.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityRequest.java @@ -1,7 +1,9 @@ package com.michelin.ns4kafka.services.clients.schema.entities; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; @Builder +@Serdeable public record SchemaCompatibilityRequest(String compatibility) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityResponse.java b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityResponse.java index 63611e47..a83660ca 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityResponse.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaCompatibilityResponse.java @@ -1,8 +1,10 @@ package com.michelin.ns4kafka.services.clients.schema.entities; import com.michelin.ns4kafka.models.schema.Schema; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; @Builder +@Serdeable public record SchemaCompatibilityResponse(Schema.Compatibility compatibilityLevel) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaRequest.java b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaRequest.java index 6a59c291..4c2fafd7 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaRequest.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaRequest.java @@ -1,10 +1,12 @@ package com.michelin.ns4kafka.services.clients.schema.entities; import com.michelin.ns4kafka.models.schema.Schema; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; import java.util.List; @Builder +@Serdeable public record SchemaRequest(String schemaType, String schema, List references) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaResponse.java b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaResponse.java index 7107b1a8..fd75f72a 100644 --- a/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaResponse.java +++ b/src/main/java/com/michelin/ns4kafka/services/clients/schema/entities/SchemaResponse.java @@ -1,7 +1,9 @@ package com.michelin.ns4kafka.services.clients.schema.entities; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; @Builder +@Serdeable public record SchemaResponse(Integer id, Integer version, String subject, String schema, String schemaType) { } diff --git a/src/main/java/com/michelin/ns4kafka/services/executors/AccessControlEntryAsyncExecutor.java b/src/main/java/com/michelin/ns4kafka/services/executors/AccessControlEntryAsyncExecutor.java index d8cc82ef..2d223316 100644 --- a/src/main/java/com/michelin/ns4kafka/services/executors/AccessControlEntryAsyncExecutor.java +++ b/src/main/java/com/michelin/ns4kafka/services/executors/AccessControlEntryAsyncExecutor.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.services.executors; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.models.AccessControlEntry; import com.michelin.ns4kafka.models.KafkaStream; import com.michelin.ns4kafka.models.Namespace; @@ -34,12 +34,12 @@ import static com.michelin.ns4kafka.services.AccessControlEntryService.PUBLIC_GRANTED_TO; @Slf4j -@EachBean(KafkaAsyncExecutorConfig.class) +@EachBean(KafkaAsyncExecutorProperties.class) @Singleton public class AccessControlEntryAsyncExecutor { private static final String USER_PRINCIPAL = "User:"; - private final KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig; + private final KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties; @Inject AccessControlEntryService accessControlEntryService; @@ -53,15 +53,15 @@ public class AccessControlEntryAsyncExecutor { @Inject NamespaceRepository namespaceRepository; - public AccessControlEntryAsyncExecutor(KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig) { - this.kafkaAsyncExecutorConfig = kafkaAsyncExecutorConfig; + public AccessControlEntryAsyncExecutor(KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties) { + this.kafkaAsyncExecutorProperties = kafkaAsyncExecutorProperties; } /** * Run the ACL executor */ public void run() { - if (this.kafkaAsyncExecutorConfig.isManageAcls()) { + if (this.kafkaAsyncExecutorProperties.isManageAcls()) { synchronizeACLs(); } } @@ -70,7 +70,7 @@ public void run() { * Start the ACLs synchronization */ private void synchronizeACLs() { - log.debug("Starting ACL collection for cluster {}", kafkaAsyncExecutorConfig.getName()); + log.debug("Starting ACL collection for cluster {}", kafkaAsyncExecutorProperties.getName()); try { // List ACLs from broker @@ -92,7 +92,7 @@ private void synchronizeACLs() { } if (!toDelete.isEmpty()) { - if (!kafkaAsyncExecutorConfig.isDropUnsyncAcls()) { + if (!kafkaAsyncExecutorProperties.isDropUnsyncAcls()) { log.debug("The ACL drop is disabled. The following ACLs won't be deleted."); } log.debug("ACL(s) to delete: " + String.join("," , toDelete.stream().map(AclBinding::toString).toList())); @@ -102,7 +102,7 @@ private void synchronizeACLs() { // such as deleting only to add one second later createACLs(toCreate); - if (kafkaAsyncExecutorConfig.isDropUnsyncAcls()) { + if (kafkaAsyncExecutorProperties.isDropUnsyncAcls()) { deleteACLs(toDelete); } } catch (KafkaStoreException | ExecutionException | TimeoutException e) { @@ -121,7 +121,7 @@ private void synchronizeACLs() { * @return A list of ACLs */ private List collectNs4KafkaACLs() { - List namespaces = namespaceRepository.findAllForCluster(kafkaAsyncExecutorConfig.getName()); + List namespaces = namespaceRepository.findAllForCluster(kafkaAsyncExecutorProperties.getName()); // Converts topic, group and transaction Ns4kafka ACLs to topic and group Kafka AclBindings Stream aclBindingFromACLs = namespaces @@ -183,7 +183,7 @@ private List collectBrokerACLs(boolean managedUsersOnly) throws Exec // Collect the list of users managed in Ns4Kafka List managedUsers = new ArrayList<>(); managedUsers.add(USER_PRINCIPAL + PUBLIC_GRANTED_TO); - managedUsers.addAll(namespaceRepository.findAllForCluster(kafkaAsyncExecutorConfig.getName()) + managedUsers.addAll(namespaceRepository.findAllForCluster(kafkaAsyncExecutorProperties.getName()) .stream() .flatMap(namespace -> Stream.of(USER_PRINCIPAL + namespace.getSpec().getKafkaUser())) .toList()); @@ -316,12 +316,12 @@ private void deleteACLs(List toDelete) { .values().forEach((key, value) -> { try { value.get(10, TimeUnit.SECONDS); - log.info("Success deleting ACL {} on {}", key, this.kafkaAsyncExecutorConfig.getName()); + log.info("Success deleting ACL {} on {}", key, this.kafkaAsyncExecutorProperties.getName()); } catch (InterruptedException e) { log.error("Error", e); Thread.currentThread().interrupt(); } catch (Exception e) { - log.error(String.format("Error while deleting ACL %s on %s", key, this.kafkaAsyncExecutorConfig.getName()), e); + log.error(String.format("Error while deleting ACL %s on %s", key, this.kafkaAsyncExecutorProperties.getName()), e); } }); } @@ -334,7 +334,7 @@ private void deleteACLs(List toDelete) { * @param ns4kafkaACL The Kafka ACL */ public void deleteNs4KafkaACL(Namespace namespace, AccessControlEntry ns4kafkaACL) { - if (kafkaAsyncExecutorConfig.isManageAcls()) { + if (kafkaAsyncExecutorProperties.isManageAcls()) { List results = new ArrayList<>(); if (List.of(TOPIC, GROUP, TRANSACTIONAL_ID).contains(ns4kafkaACL.getSpec().getResourceType())) { @@ -357,7 +357,7 @@ public void deleteNs4KafkaACL(Namespace namespace, AccessControlEntry ns4kafkaAC * @param kafkaStream The Kafka Streams */ public void deleteKafkaStreams(Namespace namespace, KafkaStream kafkaStream) { - if (kafkaAsyncExecutorConfig.isManageAcls()) { + if (kafkaAsyncExecutorProperties.isManageAcls()) { List results = new ArrayList<>(buildAclBindingsFromKafkaStream(kafkaStream, namespace.getSpec().getKafkaUser())); deleteACLs(results); } @@ -374,12 +374,12 @@ private void createACLs(List toCreate) { .forEach((key, value) -> { try { value.get(10, TimeUnit.SECONDS); - log.info("Success creating ACL {} on {}", key, this.kafkaAsyncExecutorConfig.getName()); + log.info("Success creating ACL {} on {}", key, this.kafkaAsyncExecutorProperties.getName()); } catch (InterruptedException e) { log.error("Error", e); Thread.currentThread().interrupt(); } catch (Exception e) { - log.error(String.format("Error while creating ACL %s on %s", key, this.kafkaAsyncExecutorConfig.getName()), e); + log.error(String.format("Error while creating ACL %s on %s", key, this.kafkaAsyncExecutorProperties.getName()), e); } }); } @@ -390,6 +390,6 @@ private void createACLs(List toCreate) { * @return The admin client */ private Admin getAdminClient() { - return kafkaAsyncExecutorConfig.getAdminClient(); + return kafkaAsyncExecutorProperties.getAdminClient(); } } diff --git a/src/main/java/com/michelin/ns4kafka/services/executors/ConnectorAsyncExecutor.java b/src/main/java/com/michelin/ns4kafka/services/executors/ConnectorAsyncExecutor.java index af93a640..0dc7b644 100644 --- a/src/main/java/com/michelin/ns4kafka/services/executors/ConnectorAsyncExecutor.java +++ b/src/main/java/com/michelin/ns4kafka/services/executors/ConnectorAsyncExecutor.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.services.executors; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.models.ObjectMeta; import com.michelin.ns4kafka.models.connect.cluster.ConnectCluster; import com.michelin.ns4kafka.models.connector.Connector; @@ -25,10 +25,10 @@ import java.util.stream.Stream; @Slf4j -@EachBean(KafkaAsyncExecutorConfig.class) +@EachBean(KafkaAsyncExecutorProperties.class) @Singleton public class ConnectorAsyncExecutor { - private final KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig; + private final KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties; @Inject private ConnectorRepository connectorRepository; @@ -42,15 +42,15 @@ public class ConnectorAsyncExecutor { private final Set healthyConnectClusters = new HashSet<>(); private final Set idleConnectClusters = new HashSet<>(); - public ConnectorAsyncExecutor(KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig) { - this.kafkaAsyncExecutorConfig = kafkaAsyncExecutorConfig; + public ConnectorAsyncExecutor(KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties) { + this.kafkaAsyncExecutorProperties = kafkaAsyncExecutorProperties; } /** * Start connector synchronization */ public Flux run() { - if (kafkaAsyncExecutorConfig.isManageConnectors()) { + if (kafkaAsyncExecutorProperties.isManageConnectors()) { return synchronizeConnectors(); } return Flux.empty(); @@ -60,7 +60,7 @@ public Flux run() { * Start connector synchronization */ public Flux runHealthCheck() { - if (kafkaAsyncExecutorConfig.isManageConnectors()) { + if (kafkaAsyncExecutorProperties.isManageConnectors()) { return checkConnectClusterHealth(); } return Flux.empty(); @@ -73,7 +73,7 @@ public Flux runHealthCheck() { */ private Flux getConnectClusters() { return connectClusterService.findAll(true) - .filter(connectCluster -> connectCluster.getMetadata().getCluster().equals(kafkaAsyncExecutorConfig.getName())); + .filter(connectCluster -> connectCluster.getMetadata().getCluster().equals(kafkaAsyncExecutorProperties.getName())); } /** @@ -101,12 +101,12 @@ private Flux checkConnectClusterHealth() { */ private Flux synchronizeConnectors() { log.debug("Starting connector synchronization for Kafka cluster {}. Healthy Kafka Connects: {}. Idle Kafka Connects: {}", - kafkaAsyncExecutorConfig.getName(), + kafkaAsyncExecutorProperties.getName(), !healthyConnectClusters.isEmpty() ? String.join(",", healthyConnectClusters) : "N/A", !idleConnectClusters.isEmpty() ? String.join(",", idleConnectClusters) : "N/A"); if (healthyConnectClusters.isEmpty()) { - log.debug("No healthy Kafka Connect for Kafka cluster {}. Skipping synchronization.", kafkaAsyncExecutorConfig.getName()); + log.debug("No healthy Kafka Connect for Kafka cluster {}. Skipping synchronization.", kafkaAsyncExecutorProperties.getName()); return Flux.empty(); } @@ -120,17 +120,17 @@ private Flux synchronizeConnectors() { */ private Flux synchronizeConnectCluster(String connectCluster) { log.debug("Starting connector collection for Kafka cluster {} and Kafka Connect {}.", - kafkaAsyncExecutorConfig.getName(), connectCluster); + kafkaAsyncExecutorProperties.getName(), connectCluster); return collectBrokerConnectors(connectCluster) .doOnError(error -> { if (error instanceof HttpClientResponseException httpClientResponseException) { log.error("Invalid HTTP response {} ({}) during connectors synchronization for Kafka cluster {} and Kafka Connect {}.", httpClientResponseException.getStatus(), httpClientResponseException.getResponse().getStatus(), - kafkaAsyncExecutorConfig.getName(), connectCluster); + kafkaAsyncExecutorProperties.getName(), connectCluster); } else { log.error("Exception during connectors synchronization for Kafka cluster {} and Kafka Connect {}: {}.", - kafkaAsyncExecutorConfig.getName(), connectCluster, error.getMessage()); + kafkaAsyncExecutorProperties.getName(), connectCluster, error.getMessage()); } }) .collectList() @@ -170,9 +170,9 @@ private Flux synchronizeConnectCluster(String connectCluster) { * @return A list of connectors */ public Flux collectBrokerConnectors(String connectCluster) { - return kafkaConnectClient.listAll(kafkaAsyncExecutorConfig.getName(), connectCluster) + return kafkaConnectClient.listAll(kafkaAsyncExecutorProperties.getName(), connectCluster) .flatMapMany(connectors -> { - log.debug("{} connectors found on Kafka Connect {} of Kafka cluster {}.", connectors.size(), connectCluster, kafkaAsyncExecutorConfig.getName()); + log.debug("{} connectors found on Kafka Connect {} of Kafka cluster {}.", connectors.size(), connectCluster, kafkaAsyncExecutorProperties.getName()); return Flux.fromIterable(connectors.values()) .map(connectorStatus -> buildConnectorFromConnectorStatus(connectorStatus, connectCluster)); @@ -204,11 +204,11 @@ private Connector buildConnectorFromConnectorStatus(ConnectorStatus connectorSta * @return A list of connectors */ private List collectNs4KafkaConnectors(String connectCluster) { - List connectorList = connectorRepository.findAllForCluster(kafkaAsyncExecutorConfig.getName()) + List connectorList = connectorRepository.findAllForCluster(kafkaAsyncExecutorProperties.getName()) .stream() .filter(connector -> connector.getSpec().getConnectCluster().equals(connectCluster)) .toList(); - log.debug("{} connectors found in Ns4kafka for Kafka Connect {} of Kafka cluster {}.", connectorList.size(), connectCluster, kafkaAsyncExecutorConfig.getName()); + log.debug("{} connectors found in Ns4kafka for Kafka Connect {} of Kafka cluster {}.", connectorList.size(), connectCluster, kafkaAsyncExecutorProperties.getName()); return connectorList; } @@ -237,11 +237,11 @@ private boolean connectorsAreSame(Connector expected, Connector actual) { * @param connector The connector to deploy */ private Mono deployConnector(Connector connector) { - return kafkaConnectClient.createOrUpdate(kafkaAsyncExecutorConfig.getName(), connector.getSpec().getConnectCluster(), + return kafkaConnectClient.createOrUpdate(kafkaAsyncExecutorProperties.getName(), connector.getSpec().getConnectCluster(), connector.getMetadata().getName(), ConnectorSpecs.builder().config(connector.getSpec().getConfig()).build()) .doOnSuccess(httpResponse -> log.info("Success deploying connector {} on Kafka Connect {} of Kafka cluster {}.", - connector.getMetadata().getName(), connector.getSpec().getConnectCluster(), kafkaAsyncExecutorConfig.getName())) + connector.getMetadata().getName(), connector.getSpec().getConnectCluster(), kafkaAsyncExecutorProperties.getName())) .doOnError(httpError -> log.error("Error deploying connector {} on Kafka Connect {} of Kafka cluster {}: {}", - connector.getMetadata().getName(), connector.getSpec().getConnectCluster(), kafkaAsyncExecutorConfig.getName(), httpError.getMessage())); + connector.getMetadata().getName(), connector.getSpec().getConnectCluster(), kafkaAsyncExecutorProperties.getName(), httpError.getMessage())); } } diff --git a/src/main/java/com/michelin/ns4kafka/services/executors/ConsumerGroupAsyncExecutor.java b/src/main/java/com/michelin/ns4kafka/services/executors/ConsumerGroupAsyncExecutor.java index a256de8a..9f10b3de 100644 --- a/src/main/java/com/michelin/ns4kafka/services/executors/ConsumerGroupAsyncExecutor.java +++ b/src/main/java/com/michelin/ns4kafka/services/executors/ConsumerGroupAsyncExecutor.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.services.executors; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import io.micronaut.context.annotation.EachBean; import jakarta.inject.Singleton; import lombok.extern.slf4j.Slf4j; @@ -19,13 +19,13 @@ import java.util.stream.Collectors; @Slf4j -@EachBean(KafkaAsyncExecutorConfig.class) +@EachBean(KafkaAsyncExecutorProperties.class) @Singleton public class ConsumerGroupAsyncExecutor { - private final KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig; + private final KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties; - public ConsumerGroupAsyncExecutor(KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig) { - this.kafkaAsyncExecutorConfig = kafkaAsyncExecutorConfig; + public ConsumerGroupAsyncExecutor(KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties) { + this.kafkaAsyncExecutorProperties = kafkaAsyncExecutorProperties; } /** @@ -33,7 +33,7 @@ public ConsumerGroupAsyncExecutor(KafkaAsyncExecutorConfig kafkaAsyncExecutorCon * @return A Kafka Admin client instance */ private Admin getAdminClient() { - return kafkaAsyncExecutorConfig.getAdminClient(); + return kafkaAsyncExecutorProperties.getAdminClient(); } public Map describeConsumerGroups(List groupIds) throws ExecutionException, InterruptedException { diff --git a/src/main/java/com/michelin/ns4kafka/services/executors/TopicAsyncExecutor.java b/src/main/java/com/michelin/ns4kafka/services/executors/TopicAsyncExecutor.java index 64593d24..cda7e5d5 100644 --- a/src/main/java/com/michelin/ns4kafka/services/executors/TopicAsyncExecutor.java +++ b/src/main/java/com/michelin/ns4kafka/services/executors/TopicAsyncExecutor.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.services.executors; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.models.ObjectMeta; import com.michelin.ns4kafka.models.Topic; import com.michelin.ns4kafka.repositories.TopicRepository; @@ -23,27 +23,27 @@ import java.util.stream.Collectors; @Slf4j -@EachBean(KafkaAsyncExecutorConfig.class) +@EachBean(KafkaAsyncExecutorProperties.class) @Singleton public class TopicAsyncExecutor { - private final KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig; + private final KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties; @Inject TopicRepository topicRepository; - public TopicAsyncExecutor(KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig) { - this.kafkaAsyncExecutorConfig = kafkaAsyncExecutorConfig; + public TopicAsyncExecutor(KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties) { + this.kafkaAsyncExecutorProperties = kafkaAsyncExecutorProperties; } private Admin getAdminClient(){ - return kafkaAsyncExecutorConfig.getAdminClient(); + return kafkaAsyncExecutorProperties.getAdminClient(); } /** * Start topic synchronization */ public void run() { - if (this.kafkaAsyncExecutorConfig.isManageTopics()) { + if (this.kafkaAsyncExecutorProperties.isManageTopics()) { synchronizeTopics(); } } @@ -52,11 +52,11 @@ public void run() { * Start the synchronization of topics */ public void synchronizeTopics() { - log.debug("Starting topic collection for cluster {}", kafkaAsyncExecutorConfig.getName()); + log.debug("Starting topic collection for cluster {}", kafkaAsyncExecutorProperties.getName()); try { Map brokerTopics = collectBrokerTopics(); - List ns4kafkaTopics = topicRepository.findAllForCluster(kafkaAsyncExecutorConfig.getName()); + List ns4kafkaTopics = topicRepository.findAllForCluster(kafkaAsyncExecutorProperties.getName()); List toCreate = ns4kafkaTopics.stream() .filter(topic -> !brokerTopics.containsKey(topic.getMetadata().getName())) @@ -109,7 +109,7 @@ public void synchronizeTopics() { */ public void deleteTopic(Topic topic) throws InterruptedException, ExecutionException, TimeoutException { getAdminClient().deleteTopics(List.of(topic.getMetadata().getName())).all().get(30, TimeUnit.SECONDS); - log.info("Success deleting topic {} on {}", topic.getMetadata().getName(), this.kafkaAsyncExecutorConfig.getName()); + log.info("Success deleting topic {} on {}", topic.getMetadata().getName(), this.kafkaAsyncExecutorProperties.getName()); } /** @@ -155,7 +155,7 @@ public Map collectBrokerTopicsFromNames(List topicNames) .stream() .map(stringMapEntry -> Topic.builder() .metadata(ObjectMeta.builder() - .cluster(kafkaAsyncExecutorConfig.getName()) + .cluster(kafkaAsyncExecutorProperties.getName()) .name(stringMapEntry.getKey()) .build()) .spec(Topic.TopicSpec.builder() @@ -180,14 +180,14 @@ private void alterTopics(Map> toUpdate updatedTopic.setStatus(Topic.TopicStatus.ofSuccess("Topic configs updated")); log.info("Success updating topic configs {} on {}: [{}]", key.name(), - kafkaAsyncExecutorConfig.getName(), + kafkaAsyncExecutorProperties.getName(), ops.stream().map(AlterConfigOp::toString).collect(Collectors.joining(","))); } catch (InterruptedException e) { log.error("Error", e); Thread.currentThread().interrupt(); } catch (Exception e) { updatedTopic.setStatus(Topic.TopicStatus.ofFailed("Error while updating topic configs: " + e.getMessage())); - log.error(String.format("Error while updating topic configs %s on %s", key.name(), this.kafkaAsyncExecutorConfig.getName()), e); + log.error(String.format("Error while updating topic configs %s on %s", key.name(), this.kafkaAsyncExecutorProperties.getName()), e); } topicRepository.create(updatedTopic); }); @@ -212,13 +212,13 @@ private void createTopics(List topics) { createdTopic.getMetadata().setCreationTimestamp(Date.from(Instant.now())); createdTopic.getMetadata().setGeneration(1); createdTopic.setStatus(Topic.TopicStatus.ofSuccess("Topic created")); - log.info("Success creating topic {} on {}", key, this.kafkaAsyncExecutorConfig.getName()); + log.info("Success creating topic {} on {}", key, this.kafkaAsyncExecutorProperties.getName()); } catch (InterruptedException e) { log.error("Error", e); Thread.currentThread().interrupt(); } catch (Exception e) { createdTopic.setStatus(Topic.TopicStatus.ofFailed("Error while creating topic: " + e.getMessage())); - log.error(String.format("Error while creating topic %s on %s", key, this.kafkaAsyncExecutorConfig.getName()), e); + log.error(String.format("Error while creating topic %s on %s", key, this.kafkaAsyncExecutorProperties.getName()), e); } topicRepository.create(createdTopic); }); diff --git a/src/main/java/com/michelin/ns4kafka/services/executors/UserAsyncExecutor.java b/src/main/java/com/michelin/ns4kafka/services/executors/UserAsyncExecutor.java index 6a290c4a..870e4aa4 100644 --- a/src/main/java/com/michelin/ns4kafka/services/executors/UserAsyncExecutor.java +++ b/src/main/java/com/michelin/ns4kafka/services/executors/UserAsyncExecutor.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.services.executors; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.models.quota.ResourceQuota; import com.michelin.ns4kafka.repositories.NamespaceRepository; import com.michelin.ns4kafka.repositories.ResourceQuotaRepository; @@ -24,14 +24,14 @@ import java.util.stream.Collectors; @Slf4j -@EachBean(KafkaAsyncExecutorConfig.class) +@EachBean(KafkaAsyncExecutorProperties.class) @Singleton public class UserAsyncExecutor { public static final double BYTE_RATE_DEFAULT_VALUE = 102400.0; private static final String USER_QUOTA_PREFIX = "user/"; - private final KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig; + private final KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties; private final AbstractUserSynchronizer userExecutor; @@ -41,11 +41,11 @@ public class UserAsyncExecutor { @Inject ResourceQuotaRepository quotaRepository; - public UserAsyncExecutor(KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig) { - this.kafkaAsyncExecutorConfig = kafkaAsyncExecutorConfig; - switch (kafkaAsyncExecutorConfig.getProvider()) { + public UserAsyncExecutor(KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties) { + this.kafkaAsyncExecutorProperties = kafkaAsyncExecutorProperties; + switch (kafkaAsyncExecutorProperties.getProvider()) { case SELF_MANAGED: - this.userExecutor = new Scram512UserSynchronizer(kafkaAsyncExecutorConfig.getAdminClient()); + this.userExecutor = new Scram512UserSynchronizer(kafkaAsyncExecutorProperties.getAdminClient()); break; case CONFLUENT_CLOUD: default: @@ -55,14 +55,14 @@ public UserAsyncExecutor(KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig) { } public void run() { - if (this.kafkaAsyncExecutorConfig.isManageUsers() && this.userExecutor.canSynchronizeQuotas()) { + if (this.kafkaAsyncExecutorProperties.isManageUsers() && this.userExecutor.canSynchronizeQuotas()) { synchronizeUsers(); } } public void synchronizeUsers() { - log.debug("Starting user collection for cluster {}", kafkaAsyncExecutorConfig.getName()); + log.debug("Starting user collection for cluster {}", kafkaAsyncExecutorProperties.getName()); // List user details from broker Map> brokerUserQuotas = this.userExecutor.listQuotas(); // List user details from ns4kafka @@ -98,14 +98,14 @@ public String resetPassword(String user) { return this.userExecutor.resetPassword(user); } else { throw new ResourceValidationException( - List.of("Password reset is not available with provider " + kafkaAsyncExecutorConfig.getProvider()), + List.of("Password reset is not available with provider " + kafkaAsyncExecutorProperties.getProvider()), "KafkaUserResetPassword", user); } } private Map> collectNs4kafkaQuotas() { - return namespaceRepository.findAllForCluster(this.kafkaAsyncExecutorConfig.getName()) + return namespaceRepository.findAllForCluster(this.kafkaAsyncExecutorProperties.getName()) .stream() .map(namespace -> { Optional quota = quotaRepository.findForNamespace(namespace.getMetadata().getName()); @@ -247,4 +247,4 @@ public Map> listQuotas() { throw exception; } } -} \ No newline at end of file +} diff --git a/src/main/java/com/michelin/ns4kafka/utils/config/ConnectorConfig.java b/src/main/java/com/michelin/ns4kafka/utils/config/ConnectorConfig.java index da6d34cc..5291ccb8 100644 --- a/src/main/java/com/michelin/ns4kafka/utils/config/ConnectorConfig.java +++ b/src/main/java/com/michelin/ns4kafka/utils/config/ConnectorConfig.java @@ -1,7 +1,9 @@ package com.michelin.ns4kafka.utils.config; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class ConnectorConfig { public static final String CONNECTOR_CLASS = "connector.class"; - - private ConnectorConfig() { } } diff --git a/src/main/java/com/michelin/ns4kafka/utils/config/TopicConfig.java b/src/main/java/com/michelin/ns4kafka/utils/config/TopicConfig.java index db9181d4..1d948c0e 100644 --- a/src/main/java/com/michelin/ns4kafka/utils/config/TopicConfig.java +++ b/src/main/java/com/michelin/ns4kafka/utils/config/TopicConfig.java @@ -1,8 +1,10 @@ package com.michelin.ns4kafka.utils.config; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) public final class TopicConfig { public static final String PARTITIONS = "partitions"; public static final String REPLICATION_FACTOR = "replication.factor"; - - private TopicConfig() { } } diff --git a/src/main/java/com/michelin/ns4kafka/validation/ConnectValidator.java b/src/main/java/com/michelin/ns4kafka/validation/ConnectValidator.java index b9c61f4d..e6ce9cae 100644 --- a/src/main/java/com/michelin/ns4kafka/validation/ConnectValidator.java +++ b/src/main/java/com/michelin/ns4kafka/validation/ConnectValidator.java @@ -1,9 +1,8 @@ package com.michelin.ns4kafka.validation; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; import com.michelin.ns4kafka.models.connector.Connector; import io.micronaut.core.util.StringUtils; +import io.micronaut.serde.annotation.Serdeable; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; @@ -19,20 +18,18 @@ import static com.michelin.ns4kafka.utils.config.ConnectorConfig.CONNECTOR_CLASS; @Data +@Serdeable @SuperBuilder @NoArgsConstructor @EqualsAndHashCode(callSuper=true) public class ConnectValidator extends ResourceValidator { @Builder.Default - @JsonSetter(nulls = Nulls.AS_EMPTY) private Map sourceValidationConstraints = new HashMap<>(); @Builder.Default - @JsonSetter(nulls = Nulls.AS_EMPTY) private Map sinkValidationConstraints = new HashMap<>(); @Builder.Default - @JsonSetter(nulls = Nulls.AS_EMPTY) private Map> classValidationConstraints = new HashMap<>(); /** @@ -57,15 +54,17 @@ public List validate(Connector connector, String connectorType) { "ASCII alphanumerics, '.', '_' or '-'"); } - validationConstraints.forEach((key, value) -> { - try { - value.ensureValid(key, connector.getSpec().getConfig().get(key)); - } catch (FieldValidationException e) { - validationErrors.add(e.getMessage()); - } - }); + if (validationConstraints != null) { + validationConstraints.forEach((key, value) -> { + try { + value.ensureValid(key, connector.getSpec().getConfig().get(key)); + } catch (FieldValidationException e) { + validationErrors.add(e.getMessage()); + } + }); + } - if (connectorType.equals("sink")) { + if (connectorType.equals("sink") && sinkValidationConstraints != null) { sinkValidationConstraints.forEach((key, value) -> { try { value.ensureValid(key, connector.getSpec().getConfig().get(key)); @@ -75,7 +74,7 @@ public List validate(Connector connector, String connectorType) { }); } - if (connectorType.equals("source")) { + if (connectorType.equals("source") && sourceValidationConstraints != null) { sourceValidationConstraints.forEach((key, value) -> { try { value.ensureValid(key, connector.getSpec().getConfig().get(key)); @@ -85,7 +84,7 @@ public List validate(Connector connector, String connectorType) { }); } - if (classValidationConstraints.containsKey(connector.getSpec().getConfig().get(CONNECTOR_CLASS))) { + if (classValidationConstraints != null && classValidationConstraints.containsKey(connector.getSpec().getConfig().get(CONNECTOR_CLASS))) { classValidationConstraints.get(connector.getSpec().getConfig().get(CONNECTOR_CLASS)).forEach((key, value) -> { try { value.ensureValid(key, connector.getSpec().getConfig().get(key)); diff --git a/src/main/java/com/michelin/ns4kafka/validation/ResourceValidator.java b/src/main/java/com/michelin/ns4kafka/validation/ResourceValidator.java index f91a8fa8..8cede15c 100644 --- a/src/main/java/com/michelin/ns4kafka/validation/ResourceValidator.java +++ b/src/main/java/com/michelin/ns4kafka/validation/ResourceValidator.java @@ -1,9 +1,8 @@ package com.michelin.ns4kafka.validation; -import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.Nulls; +import io.micronaut.serde.annotation.Serdeable; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -13,13 +12,13 @@ import java.util.*; @Data +@Serdeable @SuperBuilder -@AllArgsConstructor @NoArgsConstructor +@AllArgsConstructor public abstract class ResourceValidator { @Builder.Default - @JsonSetter(nulls = Nulls.AS_EMPTY) - protected Map validationConstraints = new HashMap<>(); + protected Map validationConstraints = new HashMap<>(); @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -45,23 +44,16 @@ public interface Validator { * Validation logic for numeric ranges */ @Data + @Builder + @Serdeable @NoArgsConstructor + @AllArgsConstructor public static class Range implements ResourceValidator.Validator { private Number min; private Number max; + @Builder.Default private boolean optional = false; - /** - * A numeric range with inclusive upper bound and inclusive lower bound - * @param min the lower bound - * @param max the upper bound - */ - public Range(Number min, Number max, boolean optional) { - this.min = min; - this.max = max; - this.optional = optional; - } - /** * A numeric range that checks only the lower bound * @@ -77,6 +69,7 @@ public static ResourceValidator.Range atLeast(Number min) { public static ResourceValidator.Range between(Number min, Number max) { return new ResourceValidator.Range(min, max, false); } + /** * A numeric range that checks both the upper (inclusive) and lower bound, and accepts null as well */ @@ -84,8 +77,9 @@ public static ResourceValidator.Range optionalBetween(Number min, Number max) { return new ResourceValidator.Range(min, max, true); } + @Override public void ensureValid(String name, Object o) { - Number n = null; + Number n; if (o == null) { if (optional) return; @@ -115,9 +109,9 @@ else if (max == null) } @Data + @Serdeable @NoArgsConstructor public static class ValidList implements ResourceValidator.Validator { - private List validStrings; private boolean optional = false; @@ -160,12 +154,12 @@ public String toString() { } @Data + @Serdeable @NoArgsConstructor public static class ValidString implements ResourceValidator.Validator { private List validStrings; private boolean optional = false; - public ValidString(List validStrings, boolean optional) { this.validStrings = validStrings; this.optional = optional; @@ -174,6 +168,7 @@ public ValidString(List validStrings, boolean optional) { public static ResourceValidator.ValidString in(String... validStrings) { return new ResourceValidator.ValidString(Arrays.asList(validStrings), false); } + public static ResourceValidator.ValidString optionalIn(String... validStrings) { return new ResourceValidator.ValidString(Arrays.asList(validStrings), true); } @@ -197,14 +192,14 @@ public String toString() { } } + @Serdeable public static class NonEmptyString implements ResourceValidator.Validator { - @Override public void ensureValid(String name, Object o) { if (o == null) throw new FieldValidationException(name, null, "Value must be non-null"); String s = (String) o; - if (s != null && s.isEmpty()) { + if (s.isEmpty()) { throw new FieldValidationException(name, o, "String must be non-empty"); } } @@ -218,8 +213,7 @@ public String toString() { public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; - if (!(obj instanceof NonEmptyString)) return false; - return true; + return obj instanceof NonEmptyString; } @Override @@ -229,6 +223,7 @@ public int hashCode() { } @Data + @Serdeable @NoArgsConstructor public static class CompositeValidator implements ResourceValidator.Validator { private List validators; @@ -253,151 +248,12 @@ public String toString() { if (validators == null) return ""; StringBuilder desc = new StringBuilder(); for (ResourceValidator.Validator v: validators) { - if (desc.length() > 0) { - desc.append(',').append(' '); - } - desc.append(String.valueOf(v)); - } - return desc.toString(); - } - } - /* - public static class CaseInsensitiveValidString implements ResourceValidator.Validator { - - Set validStrings; - - private CaseInsensitiveValidString(List validStrings) { - this.validStrings = validStrings.stream() - .map(s -> s.toUpperCase(Locale.ROOT)) - .collect(Collectors.toSet()); - } - - public static ResourceValidator.CaseInsensitiveValidString in(String... validStrings) { - return new ResourceValidator.CaseInsensitiveValidString(Arrays.asList(validStrings)); - } - - @Override - public void ensureValid(String name, Object o) { - String s = (String) o; - if (s == null || !validStrings.contains(s.toUpperCase(Locale.ROOT))) { - throw new ValidationException(name, o, "String must be one of (case insensitive): " + String.join(", ", validStrings)); - } - } - - public String toString() { - return "(case insensitive) [" + String.join(", ", validStrings) + "]"; - } - } - - public static class NonNullValidator implements ResourceValidator.Validator { - @Override - public void ensureValid(String name, Object value) { - if (value == null) { - // Pass in the string null to avoid the spotbugs warning - throw new ValidationException(name, "null", "entry must be non null"); - } - } - - public String toString() { - return "non-null string"; - } - } - - public static class LambdaValidator implements ResourceValidator.Validator { - BiConsumer ensureValid; - Supplier toStringFunction; - - private LambdaValidator(BiConsumer ensureValid, - Supplier toStringFunction) { - this.ensureValid = ensureValid; - this.toStringFunction = toStringFunction; - } - - public static ResourceValidator.LambdaValidator with(BiConsumer ensureValid, - Supplier toStringFunction) { - return new ResourceValidator.LambdaValidator(ensureValid, toStringFunction); - } - - @Override - public void ensureValid(String name, Object value) { - ensureValid.accept(name, value); - } - - @Override - public String toString() { - return toStringFunction.get(); - } - } - - public static class CompositeValidator implements ResourceValidator.Validator { - private final List validators; - - private CompositeValidator(List validators) { - this.validators = Collections.unmodifiableList(validators); - } - - public static ResourceValidator.CompositeValidator of(ResourceValidator.Validator... validators) { - return new ResourceValidator.CompositeValidator(Arrays.asList(validators)); - } - - @Override - public void ensureValid(String name, Object value) { - for (ResourceValidator.Validator validator: validators) { - validator.ensureValid(name, value); - } - } - - @Override - public String toString() { - if (validators == null) return ""; - StringBuilder desc = new StringBuilder(); - for (ResourceValidator.Validator v: validators) { - if (desc.length() > 0) { + if (!desc.isEmpty()) { desc.append(',').append(' '); } - desc.append(String.valueOf(v)); + desc.append(v); } return desc.toString(); } } - - public static class NonEmptyStringWithoutControlChars implements ResourceValidator.Validator { - - public static ResourceValidator.NonEmptyStringWithoutControlChars nonEmptyStringWithoutControlChars() { - return new ResourceValidator.NonEmptyStringWithoutControlChars(); - } - - @Override - public void ensureValid(String name, Object value) { - String s = (String) value; - - if (s == null) { - // This can happen during creation of the config object due to no default value being defined for the - // name configuration - a missing name parameter is caught when checking for mandatory parameters, - // thus we can ok a null value here - return; - } else if (s.isEmpty()) { - throw new ValidationException(name, value, "String may not be empty"); - } - - // Check name string for illegal characters - ArrayList foundIllegalCharacters = new ArrayList<>(); - - for (int i = 0; i < s.length(); i++) { - if (Character.isISOControl(s.codePointAt(i))) { - foundIllegalCharacters.add(String.valueOf(s.codePointAt(i))); - } - } - - if (!foundIllegalCharacters.isEmpty()) { - throw new ValidationException(name, value, "String may not contain control sequences but had the following ASCII chars: " + String.join(", ", foundIllegalCharacters)); - } - } - - public String toString() { - return "non-empty string without ISO control characters"; - } - } - - */ } diff --git a/src/main/java/com/michelin/ns4kafka/validation/TopicValidator.java b/src/main/java/com/michelin/ns4kafka/validation/TopicValidator.java index 330a5849..89b7a66d 100644 --- a/src/main/java/com/michelin/ns4kafka/validation/TopicValidator.java +++ b/src/main/java/com/michelin/ns4kafka/validation/TopicValidator.java @@ -1,6 +1,7 @@ package com.michelin.ns4kafka.validation; import com.michelin.ns4kafka.models.Topic; +import io.micronaut.serde.annotation.Serdeable; import lombok.*; import lombok.experimental.SuperBuilder; @@ -15,6 +16,7 @@ @Getter @Setter +@Serdeable @SuperBuilder @NoArgsConstructor @EqualsAndHashCode(callSuper = true) @@ -45,33 +47,36 @@ public List validate(Topic topic) { "ASCII alphanumerics, '.', '_' or '-'"); } - if (!validationConstraints.isEmpty() && topic.getSpec().getConfigs() != null) { - Set configsWithoutConstraints = topic.getSpec().getConfigs().keySet() - .stream() - .filter(s -> !validationConstraints.containsKey(s)) - .collect(Collectors.toSet()); - if (!configsWithoutConstraints.isEmpty()) { - validationErrors.add("Configurations [" + String.join(",", configsWithoutConstraints) + "] are not allowed"); + if (validationConstraints != null) { + if (!validationConstraints.isEmpty() && topic.getSpec().getConfigs() != null) { + Set configsWithoutConstraints = topic.getSpec().getConfigs().keySet() + .stream() + .filter(s -> !validationConstraints.containsKey(s)) + .collect(Collectors.toSet()); + if (!configsWithoutConstraints.isEmpty()) { + validationErrors.add("Configurations [" + String.join(",", configsWithoutConstraints) + "] are not allowed"); + } } - } - validationConstraints.forEach((key, value) -> { - try { - if (key.equals(PARTITIONS)) { - value.ensureValid(key, topic.getSpec().getPartitions()); - } else if (key.equals(REPLICATION_FACTOR)) { - value.ensureValid(key, topic.getSpec().getReplicationFactor()); - } else { - if (topic.getSpec().getConfigs() != null) { - value.ensureValid(key, topic.getSpec().getConfigs().get(key)); + validationConstraints.forEach((key, value) -> { + try { + if (key.equals(PARTITIONS)) { + value.ensureValid(key, topic.getSpec().getPartitions()); + } else if (key.equals(REPLICATION_FACTOR)) { + value.ensureValid(key, topic.getSpec().getReplicationFactor()); } else { - validationErrors.add("Invalid value null for configuration " + key + ": Value must be non-null"); + if (topic.getSpec().getConfigs() != null) { + value.ensureValid(key, topic.getSpec().getConfigs().get(key)); + } else { + validationErrors.add("Invalid value null for configuration " + key + ": Value must be non-null"); + } } + } catch (FieldValidationException e) { + validationErrors.add(e.getMessage()); } - } catch (FieldValidationException e) { - validationErrors.add(e.getMessage()); - } - }); + }); + } + return validationErrors; } diff --git a/src/test/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderControllerTest.java b/src/test/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderControllerTest.java index e6bba8c1..753cfc4b 100644 --- a/src/test/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderControllerTest.java +++ b/src/test/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderControllerTest.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.controllers; -import com.michelin.ns4kafka.config.AkhqClaimProviderControllerConfig; +import com.michelin.ns4kafka.properties.AkhqClaimProviderControllerProperties; import com.michelin.ns4kafka.models.AccessControlEntry; import com.michelin.ns4kafka.models.Namespace; import com.michelin.ns4kafka.models.ObjectMeta; @@ -34,10 +34,10 @@ class AkhqClaimProviderControllerTest { AkhqClaimProviderController akhqClaimProviderController; @Spy - AkhqClaimProviderControllerConfig akhqClaimProviderControllerConfig = getAkhqClaimProviderControllerConfig(); + AkhqClaimProviderControllerProperties akhqClaimProviderControllerProperties = getAkhqClaimProviderControllerConfig(); - private AkhqClaimProviderControllerConfig getAkhqClaimProviderControllerConfig() { - AkhqClaimProviderControllerConfig config = new AkhqClaimProviderControllerConfig(); + private AkhqClaimProviderControllerProperties getAkhqClaimProviderControllerConfig() { + AkhqClaimProviderControllerProperties config = new AkhqClaimProviderControllerProperties(); config.setGroupLabel("support-group"); config.setFormerRoles(List.of( "topic/read", diff --git a/src/test/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderControllerV3Test.java b/src/test/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderControllerV3Test.java index 99f3a891..f39cf5fd 100644 --- a/src/test/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderControllerV3Test.java +++ b/src/test/java/com/michelin/ns4kafka/controllers/AkhqClaimProviderControllerV3Test.java @@ -1,7 +1,7 @@ package com.michelin.ns4kafka.controllers; -import com.michelin.ns4kafka.config.AkhqClaimProviderControllerConfig; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.AkhqClaimProviderControllerProperties; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.models.AccessControlEntry; import com.michelin.ns4kafka.models.Namespace; import com.michelin.ns4kafka.models.ObjectMeta; @@ -31,10 +31,10 @@ class AkhqClaimProviderControllerV3Test { AkhqClaimProviderController akhqClaimProviderController; @Spy - AkhqClaimProviderControllerConfig akhqClaimProviderControllerConfig = getAkhqClaimProviderControllerConfig(); + AkhqClaimProviderControllerProperties akhqClaimProviderControllerProperties = getAkhqClaimProviderControllerConfig(); - private AkhqClaimProviderControllerConfig getAkhqClaimProviderControllerConfig() { - AkhqClaimProviderControllerConfig config = new AkhqClaimProviderControllerConfig(); + private AkhqClaimProviderControllerProperties getAkhqClaimProviderControllerConfig() { + AkhqClaimProviderControllerProperties config = new AkhqClaimProviderControllerProperties(); config.setGroupLabel("support-group"); config.setAdminGroup("GP-ADMIN"); config.setRoles(Map.of(AccessControlEntry.ResourceType.TOPIC, "topic-read", @@ -63,7 +63,7 @@ void generateClaimHappyPath() { .build()) .build(); - akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorConfig("cluster1"), new KafkaAsyncExecutorConfig("cluster2")); + akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorProperties("cluster1"), new KafkaAsyncExecutorProperties("cluster2")); Mockito.when(namespaceService.listAll()) .thenReturn(List.of(ns1Cluster1)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) @@ -101,7 +101,7 @@ void generateClaimMultipleSupportGroups() { .build()) .build(); - akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorConfig("cluster1"), new KafkaAsyncExecutorConfig("cluster2")); + akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorProperties("cluster1"), new KafkaAsyncExecutorProperties("cluster2")); Mockito.when(namespaceService.listAll()) .thenReturn(List.of(ns1Cluster1)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)) @@ -131,7 +131,7 @@ void generateClaimNoPermissions() { .build()) .build(); - akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorConfig("cluster1"), new KafkaAsyncExecutorConfig("cluster2")); + akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorProperties("cluster1"), new KafkaAsyncExecutorProperties("cluster2")); Mockito.when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1)); AkhqClaimProviderController.AKHQClaimRequest request = AkhqClaimProviderController.AKHQClaimRequest.builder() @@ -173,7 +173,7 @@ void generateClaimWithOptimizedClusters() { .build()) .build(); - akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorConfig("cluster1"), new KafkaAsyncExecutorConfig("cluster2")); + akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorProperties("cluster1"), new KafkaAsyncExecutorProperties("cluster2")); Mockito.when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1, ns1Cluster2)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(List.of(ace1Ns1Cluster1)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster2)).thenReturn(List.of(ace1Ns1Cluster2)); @@ -225,7 +225,7 @@ void generateClaimWithMultiplePatternsOnSameCluster() { .build()) .build(); - akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorConfig("cluster1"), new KafkaAsyncExecutorConfig("cluster2")); + akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorProperties("cluster1"), new KafkaAsyncExecutorProperties("cluster2")); Mockito.when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1, ns2Cluster1)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(List.of(ace1Ns1Cluster1)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns2Cluster1)).thenReturn(List.of(ace2Ns2Cluster1)); @@ -277,7 +277,7 @@ void generateClaimWithMultipleGroups() { .build()) .build(); - akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorConfig("cluster1"), new KafkaAsyncExecutorConfig("cluster2")); + akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorProperties("cluster1"), new KafkaAsyncExecutorProperties("cluster2")); Mockito.when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1, ns1Cluster2)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(List.of(ace1Cluster1)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster2)).thenReturn(List.of(ace1Cluster2)); @@ -329,7 +329,7 @@ void generateClaimWithPatternOnMultipleClusters() { .build()) .build(); - akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorConfig("cluster1"), new KafkaAsyncExecutorConfig("cluster2")); + akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorProperties("cluster1"), new KafkaAsyncExecutorProperties("cluster2")); Mockito.when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1, ns2Cluster2)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(List.of(ace1Ns1Cluster1)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns2Cluster2)).thenReturn(List.of(ace1Ns2Cluster2)); @@ -447,7 +447,7 @@ void generateClaimAndOptimizePatterns(){ .build()) .build() ); - akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorConfig("cluster1"), new KafkaAsyncExecutorConfig("cluster2")); + akhqClaimProviderController.managedClusters = List.of(new KafkaAsyncExecutorProperties("cluster1"), new KafkaAsyncExecutorProperties("cluster2")); Mockito.when(namespaceService.listAll()).thenReturn(List.of(ns1Cluster1)); Mockito.when(accessControlEntryService.findAllGrantedToNamespace(ns1Cluster1)).thenReturn(inputACLs); diff --git a/src/test/java/com/michelin/ns4kafka/controllers/ExceptionHandlerControllerTest.java b/src/test/java/com/michelin/ns4kafka/controllers/ExceptionHandlerControllerTest.java index 3be2386b..445a6d5d 100644 --- a/src/test/java/com/michelin/ns4kafka/controllers/ExceptionHandlerControllerTest.java +++ b/src/test/java/com/michelin/ns4kafka/controllers/ExceptionHandlerControllerTest.java @@ -9,7 +9,7 @@ import io.micronaut.security.authentication.AuthorizationException; import org.junit.jupiter.api.Test; -import javax.validation.ConstraintViolationException; +import jakarta.validation.ConstraintViolationException; import java.util.List; import java.util.Map; import java.util.Set; diff --git a/src/test/java/com/michelin/ns4kafka/integration/TopicTest.java b/src/test/java/com/michelin/ns4kafka/integration/TopicTest.java index 48fac0c3..3c5eb71d 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/TopicTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/TopicTest.java @@ -22,6 +22,7 @@ import io.micronaut.http.client.annotation.Client; import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.security.authentication.UsernamePasswordCredentials; +import io.micronaut.serde.annotation.Serdeable; import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import jakarta.inject.Inject; import lombok.AllArgsConstructor; @@ -486,6 +487,7 @@ void testDeleteRecordsCompactTopic() { * Bearer token class */ @Data + @Serdeable @NoArgsConstructor @AllArgsConstructor public static class BearerAccessRefreshToken { diff --git a/src/test/java/com/michelin/ns4kafka/integration/UserTest.java b/src/test/java/com/michelin/ns4kafka/integration/UserTest.java index 57d7fd55..89803c97 100644 --- a/src/test/java/com/michelin/ns4kafka/integration/UserTest.java +++ b/src/test/java/com/michelin/ns4kafka/integration/UserTest.java @@ -108,7 +108,6 @@ void init() { //force User Sync userAsyncExecutors.forEach(UserAsyncExecutor::run); - } @Test @@ -125,6 +124,7 @@ void checkDefaultQuotas() throws ExecutionException, InterruptedException { assertTrue(quotas.containsKey("consumer_byte_rate")); assertEquals(102400.0, quotas.get("consumer_byte_rate")); } + @Test void checkCustomQuotas() throws ExecutionException, InterruptedException { Map> mapQuota = getAdminClient() @@ -139,6 +139,7 @@ void checkCustomQuotas() throws ExecutionException, InterruptedException { assertTrue(quotas.containsKey("consumer_byte_rate")); assertEquals(409600.0, quotas.get("consumer_byte_rate")); } + @Test void checkUpdateQuotas() throws ExecutionException, InterruptedException { // Update the namespace user quotas diff --git a/src/test/java/com/michelin/ns4kafka/security/GitlabAuthenticationProviderTest.java b/src/test/java/com/michelin/ns4kafka/security/GitlabAuthenticationProviderTest.java index 24672ab2..09095b8d 100644 --- a/src/test/java/com/michelin/ns4kafka/security/GitlabAuthenticationProviderTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/GitlabAuthenticationProviderTest.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.security; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.models.ObjectMeta; import com.michelin.ns4kafka.models.RoleBinding; import com.michelin.ns4kafka.security.gitlab.GitlabAuthenticationProvider; @@ -39,7 +39,7 @@ class GitlabAuthenticationProviderTest { RoleBindingService roleBindingService; @Mock - SecurityConfig securityConfig; + SecurityProperties securityProperties; @InjectMocks GitlabAuthenticationProvider gitlabAuthenticationProvider; @@ -102,7 +102,7 @@ void authenticationSuccessAdmin() { .thenReturn(Flux.fromIterable(groups)); when(roleBindingService.listByGroups(groups)) .thenReturn(List.of()); - when(securityConfig.getAdminGroup()) + when(securityProperties.getAdminGroup()) .thenReturn("group-admin"); when(resourceBasedSecurityRule.computeRolesFromGroups(groups)) .thenReturn(List.of(ResourceBasedSecurityRule.IS_ADMIN)); @@ -151,7 +151,7 @@ void authenticationFailureGroupsNotFound() { .thenReturn(Flux.fromIterable(groups)); when(roleBindingService.listByGroups(groups)) .thenReturn(List.of()); - when(securityConfig.getAdminGroup()) + when(securityProperties.getAdminGroup()) .thenReturn("group-admin"); Publisher authenticationResponsePublisher = gitlabAuthenticationProvider.authenticate(null, authenticationRequest); diff --git a/src/test/java/com/michelin/ns4kafka/security/LocalUserAuthenticationProviderTest.java b/src/test/java/com/michelin/ns4kafka/security/LocalUserAuthenticationProviderTest.java index 95ed1ff0..8f04c58e 100644 --- a/src/test/java/com/michelin/ns4kafka/security/LocalUserAuthenticationProviderTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/LocalUserAuthenticationProviderTest.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.security; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.security.local.LocalUser; import com.michelin.ns4kafka.security.local.LocalUserAuthenticationProvider; import io.micronaut.security.authentication.AuthenticationException; @@ -24,7 +24,7 @@ @ExtendWith(MockitoExtension.class) class LocalUserAuthenticationProviderTest { @Mock - SecurityConfig securityConfig; + SecurityProperties securityProperties; @Mock ResourceBasedSecurityRule resourceBasedSecurityRule; @@ -36,7 +36,7 @@ class LocalUserAuthenticationProviderTest { void authenticateNoMatchUser() { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); - when(securityConfig.getLocalUsers()) + when(securityProperties.getLocalUsers()) .thenReturn(List.of()); Publisher authenticationResponsePublisher = localUserAuthenticationProvider.authenticate(null, credentials); @@ -50,7 +50,7 @@ void authenticateNoMatchUser() { void authenticateMatchUserNoMatchPassword() { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); - when(securityConfig.getLocalUsers()) + when(securityProperties.getLocalUsers()) .thenReturn(List.of(LocalUser.builder() .username("admin") .password("invalid_sha256_signature") @@ -68,7 +68,7 @@ void authenticateMatchUserNoMatchPassword() { void authenticateMatchUserMatchPassword() { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); - when(securityConfig.getLocalUsers()) + when(securityProperties.getLocalUsers()) .thenReturn(List.of(LocalUser.builder() .username("admin") .password("8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918") diff --git a/src/test/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRuleTest.java b/src/test/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRuleTest.java index 65bbe01f..5bba7781 100644 --- a/src/test/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRuleTest.java +++ b/src/test/java/com/michelin/ns4kafka/security/ResourceBasedSecurityRuleTest.java @@ -1,6 +1,6 @@ package com.michelin.ns4kafka.security; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.models.Namespace; import com.michelin.ns4kafka.models.ObjectMeta; import com.michelin.ns4kafka.models.RoleBinding; @@ -32,7 +32,7 @@ class ResourceBasedSecurityRuleTest { RoleBindingRepository roleBindingRepository; @Mock - SecurityConfig securityConfig; + SecurityProperties securityProperties; @InjectMocks ResourceBasedSecurityRule resourceBasedSecurityRule; @@ -288,7 +288,7 @@ void CheckReturnsUnknownSubResourceWithDot(){ @Test void ComputeRolesNoAdmin() { - when(securityConfig.getAdminGroup()) + when(securityProperties.getAdminGroup()) .thenReturn("admin-group"); List actual = resourceBasedSecurityRule.computeRolesFromGroups(List.of("not-admin")); @@ -297,7 +297,7 @@ void ComputeRolesNoAdmin() { @Test void ComputeRolesAdmin() { - when(securityConfig.getAdminGroup()) + when(securityProperties.getAdminGroup()) .thenReturn("admin-group"); List actual = resourceBasedSecurityRule.computeRolesFromGroups(List.of("admin-group")); diff --git a/src/test/java/com/michelin/ns4kafka/services/ConnectClusterServiceTest.java b/src/test/java/com/michelin/ns4kafka/services/ConnectClusterServiceTest.java index 058a7d43..ca715e92 100644 --- a/src/test/java/com/michelin/ns4kafka/services/ConnectClusterServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/services/ConnectClusterServiceTest.java @@ -1,7 +1,7 @@ package com.michelin.ns4kafka.services; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; -import com.michelin.ns4kafka.config.SecurityConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; +import com.michelin.ns4kafka.properties.SecurityProperties; import com.michelin.ns4kafka.models.AccessControlEntry; import com.michelin.ns4kafka.models.Namespace; import com.michelin.ns4kafka.models.ObjectMeta; @@ -48,10 +48,10 @@ class ConnectClusterServiceTest { AccessControlEntryService accessControlEntryService; @Mock - List kafkaAsyncExecutorConfigList; + List kafkaAsyncExecutorPropertiesList; @Mock - SecurityConfig securityConfig; + SecurityProperties securityProperties; @InjectMocks ConnectClusterService connectClusterService; @@ -106,9 +106,9 @@ void shouldFindAllIncludingHardDeclared() { .build(); when(connectClusterRepository.findAll()).thenReturn(new ArrayList<>(List.of(connectCluster))); - KafkaAsyncExecutorConfig kafka = new KafkaAsyncExecutorConfig("local"); - kafka.setConnects(Map.of("test-connect", new KafkaAsyncExecutorConfig.ConnectConfig())); - when(kafkaAsyncExecutorConfigList.stream()).thenReturn(Stream.of(kafka)); + KafkaAsyncExecutorProperties kafka = new KafkaAsyncExecutorProperties("local"); + kafka.setConnects(Map.of("test-connect", new KafkaAsyncExecutorProperties.ConnectConfig())); + when(kafkaAsyncExecutorPropertiesList.stream()).thenReturn(Stream.of(kafka)); when(kafkaConnectClient.version(any(), any())) .thenReturn(Mono.just(HttpResponse.ok())) .thenReturn(Mono.error(new Exception("error"))); @@ -414,7 +414,7 @@ void createCredentialsEncrypted() { .build(); when(connectClusterRepository.create(connectCluster)).thenReturn(connectCluster); - when(securityConfig.getAes256EncryptionKey()).thenReturn("changeitchangeitchangeitchangeit"); + when(securityProperties.getAes256EncryptionKey()).thenReturn("changeitchangeitchangeitchangeit"); connectClusterService.create(connectCluster); @@ -437,9 +437,9 @@ void validateConnectClusterCreationAlreadyDefined() { .build()) .build(); - KafkaAsyncExecutorConfig kafka = new KafkaAsyncExecutorConfig("local"); - kafka.setConnects(Map.of("test-connect", new KafkaAsyncExecutorConfig.ConnectConfig())); - when(kafkaAsyncExecutorConfigList.stream()).thenReturn(Stream.of(kafka)); + KafkaAsyncExecutorProperties kafka = new KafkaAsyncExecutorProperties("local"); + kafka.setConnects(Map.of("test-connect", new KafkaAsyncExecutorProperties.ConnectConfig())); + when(kafkaAsyncExecutorPropertiesList.stream()).thenReturn(Stream.of(kafka)); when(httpClient.retrieve(any(MutableHttpRequest.class), eq(ServerInfo.class))) .thenReturn(Mono.just(ServerInfo.builder().build())); @@ -466,7 +466,7 @@ void validateConnectClusterCreationDown() { .build()) .build(); - when(kafkaAsyncExecutorConfigList.stream()).thenReturn(Stream.of()); + when(kafkaAsyncExecutorPropertiesList.stream()).thenReturn(Stream.of()); when(httpClient.retrieve(any(MutableHttpRequest.class), eq(ServerInfo.class))) .thenReturn(Mono.error(new HttpClientException("Error"))); @@ -491,7 +491,7 @@ void validateConnectClusterCreationMalformedUrl() { .build()) .build(); - when(kafkaAsyncExecutorConfigList.stream()).thenReturn(Stream.of()); + when(kafkaAsyncExecutorPropertiesList.stream()).thenReturn(Stream.of()); StepVerifier.create(connectClusterService.validateConnectClusterCreation(connectCluster)) .consumeNextWith(errors -> { @@ -517,7 +517,7 @@ void validateConnectClusterCreationBadAES256MissingSalt() { .build()) .build(); - when(kafkaAsyncExecutorConfigList.stream()).thenReturn(Stream.of()); + when(kafkaAsyncExecutorPropertiesList.stream()).thenReturn(Stream.of()); when(httpClient.retrieve(any(MutableHttpRequest.class), eq(ServerInfo.class))) .thenReturn(Mono.just(ServerInfo.builder().build())); @@ -545,7 +545,7 @@ void validateConnectClusterCreationBadAES256MissingKey() { .build()) .build(); - when(kafkaAsyncExecutorConfigList.stream()).thenReturn(Stream.of()); + when(kafkaAsyncExecutorPropertiesList.stream()).thenReturn(Stream.of()); when(httpClient.retrieve(any(MutableHttpRequest.class), eq(ServerInfo.class))) .thenReturn(Mono.just(ServerInfo.builder().build())); @@ -573,7 +573,7 @@ void validateConnectClusterCreationDownWithMissingKey() { .build()) .build(); - when(kafkaAsyncExecutorConfigList.stream()).thenReturn(Stream.of()); + when(kafkaAsyncExecutorPropertiesList.stream()).thenReturn(Stream.of()); when(httpClient.retrieve(any(MutableHttpRequest.class), eq(ServerInfo.class))) .thenReturn(Mono.error(new HttpClientException("Error"))); @@ -939,7 +939,7 @@ void findAllByNamespaceWriteAsOwner() { .build() )); - when(securityConfig.getAes256EncryptionKey()).thenReturn(encryptKey); + when(securityProperties.getAes256EncryptionKey()).thenReturn(encryptKey); List actual = connectClusterService.findAllByNamespaceWrite(namespace); assertEquals(2, actual.size()); @@ -1160,7 +1160,7 @@ void vaultPasswordWithoutFormat() { .build() )); - when(securityConfig.getAes256EncryptionKey()).thenReturn("changeitchangeitchangeitchangeit"); + when(securityProperties.getAes256EncryptionKey()).thenReturn("changeitchangeitchangeitchangeit"); List actual = connectClusterService.vaultPassword(namespace, "prefix.connect-cluster", List.of("secret")); @@ -1209,7 +1209,7 @@ void vaultPasswordWithFormat() { .build() )); - when(securityConfig.getAes256EncryptionKey()).thenReturn("changeitchangeitchangeitchangeit"); + when(securityProperties.getAes256EncryptionKey()).thenReturn("changeitchangeitchangeitchangeit"); List actual = connectClusterService.vaultPassword(namespace, "prefix.connect-cluster", List.of("secret")); diff --git a/src/test/java/com/michelin/ns4kafka/services/NamespaceServiceTest.java b/src/test/java/com/michelin/ns4kafka/services/NamespaceServiceTest.java index ec3eb39d..88919132 100644 --- a/src/test/java/com/michelin/ns4kafka/services/NamespaceServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/services/NamespaceServiceTest.java @@ -1,7 +1,7 @@ package com.michelin.ns4kafka.services; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig.ConnectConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties.ConnectConfig; import com.michelin.ns4kafka.models.*; import com.michelin.ns4kafka.models.Namespace.NamespaceSpec; import com.michelin.ns4kafka.models.connector.Connector; @@ -38,7 +38,7 @@ class NamespaceServiceTest { ConnectorService connectorService; @Mock - List kafkaAsyncExecutorConfigList; + List kafkaAsyncExecutorPropertiesList; @InjectMocks NamespaceService namespaceService; @@ -88,10 +88,10 @@ void validationCreationKafkaUserAlreadyExistFail() { .kafkaUser("user") .build()) .build(); - KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig1 = new KafkaAsyncExecutorConfig("local"); + KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties1 = new KafkaAsyncExecutorProperties("local"); - when(kafkaAsyncExecutorConfigList.stream()) - .thenReturn(Stream.of(kafkaAsyncExecutorConfig1)); + when(kafkaAsyncExecutorPropertiesList.stream()) + .thenReturn(Stream.of(kafkaAsyncExecutorProperties1)); when(namespaceRepository.findAllForCluster("local")) .thenReturn(List.of(ns2)); @@ -115,10 +115,10 @@ void validateCreationNoNamespaceSuccess() { .build()) .build(); - KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig1 = new KafkaAsyncExecutorConfig("local"); + KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties1 = new KafkaAsyncExecutorProperties("local"); - when(kafkaAsyncExecutorConfigList.stream()) - .thenReturn(Stream.of(kafkaAsyncExecutorConfig1)); + when(kafkaAsyncExecutorPropertiesList.stream()) + .thenReturn(Stream.of(kafkaAsyncExecutorProperties1)); when(namespaceRepository.findAllForCluster("local")) .thenReturn(List.of()); @@ -149,10 +149,10 @@ void validateCreationANamespaceAlreadyExistsSuccess() { .build()) .build(); - KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig1 = new KafkaAsyncExecutorConfig("local"); + KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties1 = new KafkaAsyncExecutorProperties("local"); - when(kafkaAsyncExecutorConfigList.stream()) - .thenReturn(Stream.of(kafkaAsyncExecutorConfig1)); + when(kafkaAsyncExecutorPropertiesList.stream()) + .thenReturn(Stream.of(kafkaAsyncExecutorProperties1)); when(namespaceRepository.findAllForCluster("local")) .thenReturn(List.of(ns2)); @@ -174,10 +174,10 @@ void validateSuccess() { .build()) .build(); - KafkaAsyncExecutorConfig kafka = new KafkaAsyncExecutorConfig("local"); + KafkaAsyncExecutorProperties kafka = new KafkaAsyncExecutorProperties("local"); kafka.setConnects(Map.of("local-name", new ConnectConfig())); - when(kafkaAsyncExecutorConfigList.stream()) + when(kafkaAsyncExecutorPropertiesList.stream()) .thenReturn(Stream.of(kafka)); List result = namespaceService.validate(ns); @@ -200,11 +200,11 @@ void validateFail() { .build()) .build(); - KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig1 = new KafkaAsyncExecutorConfig("local"); - kafkaAsyncExecutorConfig1.setConnects(Map.of("other-connect-config", new ConnectConfig())); + KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties1 = new KafkaAsyncExecutorProperties("local"); + kafkaAsyncExecutorProperties1.setConnects(Map.of("other-connect-config", new ConnectConfig())); - when(kafkaAsyncExecutorConfigList.stream()) - .thenReturn(Stream.of(kafkaAsyncExecutorConfig1)); + when(kafkaAsyncExecutorPropertiesList.stream()) + .thenReturn(Stream.of(kafkaAsyncExecutorProperties1)); List result = namespaceService.validate(ns); @@ -246,12 +246,12 @@ void listAll() { .build()) .build(); - KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig1 = new KafkaAsyncExecutorConfig("local"); - KafkaAsyncExecutorConfig kafkaAsyncExecutorConfig2 = new KafkaAsyncExecutorConfig("other-cluster"); + KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties1 = new KafkaAsyncExecutorProperties("local"); + KafkaAsyncExecutorProperties kafkaAsyncExecutorProperties2 = new KafkaAsyncExecutorProperties("other-cluster"); - when(kafkaAsyncExecutorConfigList.stream()) + when(kafkaAsyncExecutorPropertiesList.stream()) - .thenReturn(Stream.of(kafkaAsyncExecutorConfig1, kafkaAsyncExecutorConfig2)); + .thenReturn(Stream.of(kafkaAsyncExecutorProperties1, kafkaAsyncExecutorProperties2)); when(namespaceRepository.findAllForCluster("local")) .thenReturn(List.of(ns, ns2)); when(namespaceRepository.findAllForCluster("other-cluster")) diff --git a/src/test/java/com/michelin/ns4kafka/services/TopicServiceTest.java b/src/test/java/com/michelin/ns4kafka/services/TopicServiceTest.java index 3c5e847b..edb5dee0 100644 --- a/src/test/java/com/michelin/ns4kafka/services/TopicServiceTest.java +++ b/src/test/java/com/michelin/ns4kafka/services/TopicServiceTest.java @@ -6,7 +6,7 @@ import com.michelin.ns4kafka.models.ObjectMeta; import com.michelin.ns4kafka.models.Topic; import com.michelin.ns4kafka.repositories.TopicRepository; -import com.michelin.ns4kafka.config.KafkaAsyncExecutorConfig; +import com.michelin.ns4kafka.properties.KafkaAsyncExecutorProperties; import com.michelin.ns4kafka.services.executors.TopicAsyncExecutor; import io.micronaut.context.ApplicationContext; import io.micronaut.inject.qualifiers.Qualifiers; @@ -41,7 +41,7 @@ class TopicServiceTest { ApplicationContext applicationContext; @Mock - List kafkaAsyncExecutorConfigs; + List kafkaAsyncExecutorProperties; /** * Validate find topic by name @@ -715,7 +715,7 @@ void validateTopicUpdatePartitions() { .build()) .build(); - when(kafkaAsyncExecutorConfigs.stream()).thenReturn(Stream.of()); + when(kafkaAsyncExecutorProperties.stream()).thenReturn(Stream.of()); List actual = topicService.validateTopicUpdate(ns, existing, topic); @@ -761,7 +761,7 @@ void validateTopicUpdateReplicationFactor() { .build()) .build(); - when(kafkaAsyncExecutorConfigs.stream()).thenReturn(Stream.of()); + when(kafkaAsyncExecutorProperties.stream()).thenReturn(Stream.of()); List actual = topicService.validateTopicUpdate(ns, existing, topic); @@ -807,7 +807,7 @@ void validateTopicUpdateCleanupPolicyDeleteToCompactOnCCloud() { .build()) .build(); - when(kafkaAsyncExecutorConfigs.stream()).thenReturn(Stream.of(new KafkaAsyncExecutorConfig("local", KafkaAsyncExecutorConfig.KafkaProvider.CONFLUENT_CLOUD))); + when(kafkaAsyncExecutorProperties.stream()).thenReturn(Stream.of(new KafkaAsyncExecutorProperties("local", KafkaAsyncExecutorProperties.KafkaProvider.CONFLUENT_CLOUD))); List actual = topicService.validateTopicUpdate(ns, existing, topic); @@ -853,7 +853,7 @@ void validateTopicUpdateCleanupPolicyCompactToDeleteOnCCloud() { .build()) .build(); - when(kafkaAsyncExecutorConfigs.stream()).thenReturn(Stream.of(new KafkaAsyncExecutorConfig("local", KafkaAsyncExecutorConfig.KafkaProvider.CONFLUENT_CLOUD))); + when(kafkaAsyncExecutorProperties.stream()).thenReturn(Stream.of(new KafkaAsyncExecutorProperties("local", KafkaAsyncExecutorProperties.KafkaProvider.CONFLUENT_CLOUD))); List actual = topicService.validateTopicUpdate(ns, existing, topic); @@ -898,7 +898,7 @@ void validateTopicUpdateCleanupPolicyDeleteToCompactOnSelfManaged() { .build()) .build(); - when(kafkaAsyncExecutorConfigs.stream()).thenReturn(Stream.of(new KafkaAsyncExecutorConfig("local", KafkaAsyncExecutorConfig.KafkaProvider.SELF_MANAGED))); + when(kafkaAsyncExecutorProperties.stream()).thenReturn(Stream.of(new KafkaAsyncExecutorProperties("local", KafkaAsyncExecutorProperties.KafkaProvider.SELF_MANAGED))); List actual = topicService.validateTopicUpdate(ns, existing, topic);