diff --git a/docs/src/main/asciidoc/images/devui_card_light.png b/docs/src/main/asciidoc/images/devui_card_light.png index 68fef68069b68..61628079d705e 100644 Binary files a/docs/src/main/asciidoc/images/devui_card_light.png and b/docs/src/main/asciidoc/images/devui_card_light.png differ diff --git a/extensions/flyway-oracle/runtime/pom.xml b/extensions/flyway-oracle/runtime/pom.xml index 436acd351abe5..ff907cbe24a91 100644 --- a/extensions/flyway-oracle/runtime/pom.xml +++ b/extensions/flyway-oracle/runtime/pom.xml @@ -29,6 +29,11 @@ org.flywaydb flyway-database-oracle + + org.graalvm.sdk + nativeimage + provided + diff --git a/extensions/flyway-oracle/runtime/src/main/java/io/quarkus/flyway/oracle/runtime/graal/OracleDatabaseTypeSubstitution.java b/extensions/flyway-oracle/runtime/src/main/java/io/quarkus/flyway/oracle/runtime/graal/OracleDatabaseTypeSubstitution.java new file mode 100644 index 0000000000000..4960add3ded82 --- /dev/null +++ b/extensions/flyway-oracle/runtime/src/main/java/io/quarkus/flyway/oracle/runtime/graal/OracleDatabaseTypeSubstitution.java @@ -0,0 +1,27 @@ +package io.quarkus.flyway.oracle.runtime.graal; + +import java.sql.Connection; +import java.util.Properties; + +import org.flywaydb.core.api.configuration.Configuration; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; + +@TargetClass(org.flywaydb.database.oracle.OracleDatabaseType.class) +public final class OracleDatabaseTypeSubstitution { + + @Substitute + public Connection alterConnectionAsNeeded(Connection connection, Configuration configuration) { + return connection; + } + + @Substitute + public void setDefaultConnectionProps(String url, Properties props, ClassLoader classLoader) { + String osUser = System.getProperty("user.name"); + props.put("v$session.osuser", osUser.substring(0, Math.min(osUser.length(), 30))); + props.put("v$session.program", "Flyway by Redgate"); + props.put("oracle.net.keepAlive", "true"); + props.put("oracle.net.disableOob", "true"); + } +} diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/OracleDatabaseTypeSubstitution.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/OracleDatabaseTypeSubstitution.java deleted file mode 100644 index 67001f0d8c9f8..0000000000000 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/OracleDatabaseTypeSubstitution.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.quarkus.flyway.runtime.graal; - -import java.sql.Connection; -import java.util.function.BooleanSupplier; - -import org.flywaydb.core.api.configuration.Configuration; -import org.flywaydb.core.internal.util.ClassUtils; - -import com.oracle.svm.core.annotate.Substitute; -import com.oracle.svm.core.annotate.TargetClass; - -/** - * Avoid loading the oracle.jdbc.OracleConnection class if unavailable - */ -@TargetClass(className = "org.flywaydb.database.oracle.OracleDatabaseType", onlyWith = { - OracleDatabaseTypeSubstitution.OracleAvailable.class, - OracleDatabaseTypeSubstitution.OracleDriverUnavailable.class }) -public final class OracleDatabaseTypeSubstitution { - - @Substitute - public Connection alterConnectionAsNeeded(Connection connection, Configuration configuration) { - return connection; - } - - public static final class OracleDriverUnavailable implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return !ClassUtils.isPresent("oracle.jdbc.OracleConnection", Thread.currentThread().getContextClassLoader()); - } - } - - public static final class OracleAvailable implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return ClassUtils.isPresent("org.flywaydb.database.oracle.OracleDatabaseType", - Thread.currentThread().getContextClassLoader()); - } - } -} diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/ScannerSubstitutions.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/ScannerSubstitutions.java deleted file mode 100644 index 3690cccdecf4e..0000000000000 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/graal/ScannerSubstitutions.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.quarkus.flyway.runtime.graal; - -import org.flywaydb.core.api.Location; -import org.flywaydb.core.api.configuration.Configuration; -import org.flywaydb.core.internal.scanner.Scanner; - -import com.oracle.svm.core.annotate.Substitute; -import com.oracle.svm.core.annotate.TargetClass; - -/** - * Needed to get rid of some Android related classes - */ -@TargetClass(Scanner.class) -public final class ScannerSubstitutions { - - @Substitute - public ScannerSubstitutions(final Class implementedInterface, - final Configuration configuration, - final Location[] locations) { - throw new IllegalStateException("'org.flywaydb.core.internal.scanner.Scanner' is never used in Quarkus"); - } -} diff --git a/extensions/kubernetes-client/deployment-internal/src/main/java/io/quarkus/kubernetes/client/deployment/internal/KubernetesClientBuildStep.java b/extensions/kubernetes-client/deployment-internal/src/main/java/io/quarkus/kubernetes/client/deployment/internal/KubernetesClientBuildStep.java index 0f42d8b37aff5..4dfc9b6400f38 100644 --- a/extensions/kubernetes-client/deployment-internal/src/main/java/io/quarkus/kubernetes/client/deployment/internal/KubernetesClientBuildStep.java +++ b/extensions/kubernetes-client/deployment-internal/src/main/java/io/quarkus/kubernetes/client/deployment/internal/KubernetesClientBuildStep.java @@ -1,21 +1,17 @@ package io.quarkus.kubernetes.client.deployment.internal; -import static io.quarkus.kubernetes.client.runtime.internal.KubernetesClientUtils.createConfig; - import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.builditem.QuarkusBuildCloseablesBuildItem; -import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientBuildConfig; +import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientUtils; import io.quarkus.kubernetes.client.runtime.internal.QuarkusHttpClientFactory; import io.quarkus.kubernetes.client.spi.KubernetesClientBuildItem; public class KubernetesClientBuildStep { - private KubernetesClientBuildConfig buildConfig; - @BuildStep public KubernetesClientBuildItem process(QuarkusBuildCloseablesBuildItem closeablesBuildItem) { QuarkusHttpClientFactory httpClientFactory = new QuarkusHttpClientFactory(); closeablesBuildItem.add(httpClientFactory); - return new KubernetesClientBuildItem(createConfig(buildConfig), httpClientFactory); + return new KubernetesClientBuildItem(KubernetesClientUtils.createConfig(), httpClientFactory); } } diff --git a/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/DevServicesKubernetesProcessor.java b/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/DevServicesKubernetesProcessor.java index 81e45b00e7f81..eea23d06d2ab9 100644 --- a/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/DevServicesKubernetesProcessor.java +++ b/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/DevServicesKubernetesProcessor.java @@ -72,7 +72,7 @@ import io.quarkus.devservices.common.ContainerAddress; import io.quarkus.devservices.common.ContainerLocator; import io.quarkus.devservices.common.ContainerShutdownCloseable; -import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientBuildConfig; +import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientBuildTimeConfig; import io.quarkus.kubernetes.client.runtime.internal.KubernetesDevServicesBuildTimeConfig; import io.quarkus.kubernetes.client.runtime.internal.KubernetesDevServicesBuildTimeConfig.Flavor; import io.quarkus.kubernetes.client.spi.KubernetesDevServiceInfoBuildItem; @@ -101,7 +101,7 @@ public DevServicesResultBuildItem setupKubernetesDevService( DockerStatusBuildItem dockerStatusBuildItem, DevServicesComposeProjectBuildItem composeProjectBuildItem, LaunchModeBuildItem launchMode, - KubernetesClientBuildConfig kubernetesClientBuildTimeConfig, + KubernetesClientBuildTimeConfig kubernetesClientBuildTimeConfig, List devServicesSharedNetworkBuildItem, Optional consoleInstalledBuildItem, CuratedApplicationShutdownBuildItem closeBuildItem, @@ -110,7 +110,7 @@ public DevServicesResultBuildItem setupKubernetesDevService( BuildProducer devServicesKube, Optional devServiceKubeRequest) { - KubernetesDevServiceCfg configuration = getConfiguration(kubernetesClientBuildTimeConfig); + KubernetesDevServiceCfg configuration = new KubernetesDevServiceCfg(kubernetesClientBuildTimeConfig.devservices()); if (devService != null) { boolean shouldShutdownTheCluster = !configuration.equals(cfg); @@ -181,7 +181,7 @@ public DevServicesResultBuildItem setupKubernetesDevService( @Produce(ServiceStartBuildItem.class) public void applyManifests( KubernetesDevServiceInfoBuildItem kubernetesDevServiceInfoBuildItem, - KubernetesClientBuildConfig kubernetesClientBuildTimeConfig) { + KubernetesClientBuildTimeConfig kubernetesClientBuildTimeConfig) { if (kubernetesDevServiceInfoBuildItem == null) { // Gracefully return in case the Kubernetes dev service could not be found log.error("Cannot apply manifests because the Kubernetes dev service is not running"); @@ -399,7 +399,6 @@ private > T findOrElseThrow(final Flavor flav } private Map getKubernetesClientConfigFromKubeConfig(KubeConfig kubeConfig) { - ClusterSpec cluster = kubeConfig.getClusters().get(0).getCluster(); UserSpec user = kubeConfig.getUsers().get(0).getUser(); return Map.of( @@ -427,11 +426,6 @@ private KubeConfig getKubeconfigFromRunningContainer(ContainerAddress containerA return container.getKubeconfigFromContainer(); } - private KubernetesDevServiceCfg getConfiguration(KubernetesClientBuildConfig cfg) { - KubernetesDevServicesBuildTimeConfig devServicesConfig = cfg.devservices(); - return new KubernetesDevServiceCfg(devServicesConfig); - } - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") private static final class KubernetesDevServiceCfg { diff --git a/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/KubernetesClientProcessor.java b/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/KubernetesClientProcessor.java index 4a4907662da5e..fabfd2bb2da6f 100644 --- a/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/KubernetesClientProcessor.java +++ b/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/KubernetesClientProcessor.java @@ -50,7 +50,7 @@ import io.quarkus.kubernetes.client.runtime.KubernetesClientProducer; import io.quarkus.kubernetes.client.runtime.KubernetesConfigProducer; import io.quarkus.kubernetes.client.runtime.KubernetesSerializationProducer; -import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientBuildConfig; +import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientBuildTimeConfig; import io.quarkus.kubernetes.client.spi.KubernetesClientCapabilityBuildItem; import io.quarkus.maven.dependency.ArtifactKey; @@ -98,7 +98,7 @@ RemovedResourceBuildItem unregisterVertHttpClient() { @BuildStep public void process(ApplicationIndexBuildItem applicationIndex, CombinedIndexBuildItem combinedIndexBuildItem, - KubernetesClientBuildConfig kubernetesClientConfig, + KubernetesClientBuildTimeConfig kubernetesClientBuildTimeConfig, BuildProducer sslNativeSupport, BuildProducer featureProducer, BuildProducer reflectiveClasses, @@ -110,7 +110,7 @@ public void process(ApplicationIndexBuildItem applicationIndex, CombinedIndexBui featureProducer.produce(new FeatureBuildItem(Feature.KUBERNETES_CLIENT)); kubernetesClientCapabilityProducer - .produce(new KubernetesClientCapabilityBuildItem(kubernetesClientConfig.generateRbac())); + .produce(new KubernetesClientCapabilityBuildItem(kubernetesClientBuildTimeConfig.generateRbac())); // register fully (and not weakly) for reflection watchers, informers and custom resources final Set watchedClasses = new HashSet<>(); diff --git a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientBuildTimeConfig.java b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientBuildTimeConfig.java new file mode 100644 index 0000000000000..f2726872b617d --- /dev/null +++ b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientBuildTimeConfig.java @@ -0,0 +1,26 @@ +package io.quarkus.kubernetes.client.runtime.internal; + +import io.quarkus.runtime.annotations.ConfigDocSection; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; + +@ConfigMapping(prefix = "quarkus.kubernetes-client") +@ConfigRoot(phase = ConfigPhase.BUILD_TIME) +public interface KubernetesClientBuildTimeConfig { + + /** + * Enable the generation of the RBAC manifests. If enabled and no other role binding are provided using the properties + * `quarkus.kubernetes.rbac.`, it will generate a default role binding using the role "view" and the application + * service account. + */ + @WithDefault("true") + boolean generateRbac(); + + /** + * Dev Services + */ + @ConfigDocSection(generated = true) + KubernetesDevServicesBuildTimeConfig devservices(); +} diff --git a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientBuildConfig.java b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientConfig.java similarity index 80% rename from extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientBuildConfig.java rename to extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientConfig.java index c0c4f96c8c400..07f757e71a131 100644 --- a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientBuildConfig.java +++ b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientConfig.java @@ -5,15 +5,13 @@ import java.util.Optional; import java.util.OptionalInt; -import io.quarkus.runtime.annotations.ConfigDocSection; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; import io.smallrye.config.ConfigMapping; -import io.smallrye.config.WithDefault; @ConfigMapping(prefix = "quarkus.kubernetes-client") -@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) -public interface KubernetesClientBuildConfig { +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +public interface KubernetesClientConfig { /** * Whether the client should trust a self-signed certificate if so presented by the API server @@ -25,12 +23,6 @@ public interface KubernetesClientBuildConfig { */ Optional apiServerUrl(); - /** - * Use api-server-url instead. - */ - @Deprecated(forRemoval = true) - Optional masterUrl(); - /** * Default namespace to use */ @@ -153,17 +145,4 @@ public interface KubernetesClientBuildConfig { */ Optional> noProxy(); - /** - * Enable the generation of the RBAC manifests. If enabled and no other role binding are provided using the properties - * `quarkus.kubernetes.rbac.`, it will generate a default role binding using the role "view" and the application - * service account. - */ - @WithDefault("true") - boolean generateRbac(); - - /** - * Dev Services - */ - @ConfigDocSection(generated = true) - KubernetesDevServicesBuildTimeConfig devservices(); } diff --git a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientUtils.java b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientUtils.java index d0eba086dcf8a..3db7da9de5746 100644 --- a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientUtils.java +++ b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesClientUtils.java @@ -6,8 +6,6 @@ import java.time.Duration; import java.util.Optional; -import org.eclipse.microprofile.config.ConfigProvider; - import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.KubernetesClient; @@ -20,12 +18,12 @@ public class KubernetesClientUtils { private KubernetesClientUtils() { } - public static Config createConfig(KubernetesClientBuildConfig buildConfig) { - boolean globalTrustAll = ConfigProvider.getConfig().getOptionalValue("quarkus.tls.trust-all", Boolean.class) - .orElse(false); + public static Config createConfig(KubernetesClientConfig clientConfig) { + io.smallrye.config.Config config = io.smallrye.config.Config.get(); + boolean globalTrustAll = config.getOptionalValue("quarkus.tls.trust-all", Boolean.class).orElse(false); Config base; - if (buildConfig.kubeconfigFile().isPresent()) { - String kubeconfigPath = buildConfig.kubeconfigFile().get(); + if (clientConfig.kubeconfigFile().isPresent()) { + String kubeconfigPath = clientConfig.kubeconfigFile().get(); try { String kubeconfig = Files.readString(Path.of(kubeconfigPath)); base = Config.fromKubeconfig(kubeconfig); @@ -35,81 +33,100 @@ public static Config createConfig(KubernetesClientBuildConfig buildConfig) { } else { base = Config.autoConfigure(null); } - boolean trustAll = buildConfig.trustCerts().isPresent() ? buildConfig.trustCerts().get() : globalTrustAll; + boolean trustAll = clientConfig.trustCerts().isPresent() ? clientConfig.trustCerts().get() : globalTrustAll; final var configBuilder = new ConfigBuilder(base).withTrustCerts(trustAll); - buildConfig.watchReconnectInterval().ifPresent(d -> configBuilder.withWatchReconnectInterval(millisAsInt(d))); - buildConfig.watchReconnectLimit().ifPresent(configBuilder::withWatchReconnectLimit); - buildConfig.connectionTimeout().ifPresent(d -> configBuilder.withConnectionTimeout(millisAsInt(d))); - buildConfig.requestTimeout().ifPresent(d -> configBuilder.withRequestTimeout(millisAsInt(d))); - buildConfig.apiServerUrl().or(buildConfig::masterUrl).ifPresent(configBuilder::withMasterUrl); - buildConfig.namespace().ifPresent(configBuilder::withNamespace); - buildConfig.username().ifPresent(configBuilder::withUsername); - buildConfig.password().ifPresent(configBuilder::withPassword); - buildConfig.token().ifPresent(configBuilder::withOauthToken); - buildConfig.caCertFile().ifPresent(configBuilder::withCaCertFile); - buildConfig.caCertData().ifPresent(configBuilder::withCaCertData); - buildConfig.clientCertFile().ifPresent(configBuilder::withClientCertFile); - buildConfig.clientCertData().ifPresent(configBuilder::withClientCertData); - buildConfig.clientKeyFile().ifPresent(configBuilder::withClientKeyFile); - buildConfig.clientKeyData().ifPresent(configBuilder::withClientKeyData); - buildConfig.clientKeyAlgo().ifPresent(configBuilder::withClientKeyAlgo); - buildConfig.clientKeyPassphrase().ifPresent(configBuilder::withClientKeyPassphrase); - buildConfig.httpProxy().ifPresent(configBuilder::withHttpProxy); - buildConfig.httpsProxy().ifPresent(configBuilder::withHttpsProxy); - buildConfig.proxyUsername().ifPresent(configBuilder::withProxyUsername); - buildConfig.proxyPassword().ifPresent(configBuilder::withProxyPassword); - buildConfig.noProxy().ifPresent(list -> list.toArray(new String[0])); - buildConfig.requestRetryBackoffInterval().ifPresent(d -> configBuilder.withRequestRetryBackoffInterval(millisAsInt(d))); - buildConfig.requestRetryBackoffLimit().ifPresent(configBuilder::withRequestRetryBackoffLimit); + clientConfig.watchReconnectInterval().ifPresent(d -> configBuilder.withWatchReconnectInterval(millisAsInt(d))); + clientConfig.watchReconnectLimit().ifPresent(configBuilder::withWatchReconnectLimit); + clientConfig.connectionTimeout().ifPresent(d -> configBuilder.withConnectionTimeout(millisAsInt(d))); + clientConfig.requestTimeout().ifPresent(d -> configBuilder.withRequestTimeout(millisAsInt(d))); + clientConfig.apiServerUrl().ifPresent(configBuilder::withMasterUrl); + clientConfig.namespace().ifPresent(configBuilder::withNamespace); + clientConfig.username().ifPresent(configBuilder::withUsername); + clientConfig.password().ifPresent(configBuilder::withPassword); + clientConfig.token().ifPresent(configBuilder::withOauthToken); + clientConfig.caCertFile().ifPresent(configBuilder::withCaCertFile); + clientConfig.caCertData().ifPresent(configBuilder::withCaCertData); + clientConfig.clientCertFile().ifPresent(configBuilder::withClientCertFile); + clientConfig.clientCertData().ifPresent(configBuilder::withClientCertData); + clientConfig.clientKeyFile().ifPresent(configBuilder::withClientKeyFile); + clientConfig.clientKeyData().ifPresent(configBuilder::withClientKeyData); + clientConfig.clientKeyAlgo().ifPresent(configBuilder::withClientKeyAlgo); + clientConfig.clientKeyPassphrase().ifPresent(configBuilder::withClientKeyPassphrase); + clientConfig.httpProxy().ifPresent(configBuilder::withHttpProxy); + clientConfig.httpsProxy().ifPresent(configBuilder::withHttpsProxy); + clientConfig.proxyUsername().ifPresent(configBuilder::withProxyUsername); + clientConfig.proxyPassword().ifPresent(configBuilder::withProxyPassword); + clientConfig.noProxy().ifPresent(list -> configBuilder.withNoProxy(list.toArray(new String[0]))); + clientConfig.requestRetryBackoffInterval() + .ifPresent(d -> configBuilder.withRequestRetryBackoffInterval(millisAsInt(d))); + clientConfig.requestRetryBackoffLimit().ifPresent(configBuilder::withRequestRetryBackoffLimit); return configBuilder.build(); } - private static int millisAsInt(Duration duration) { - return (int) duration.toMillis(); - } - - public static KubernetesClient createClient(KubernetesClientBuildConfig buildConfig) { - return new KubernetesClientBuilder().withConfig(createConfig(buildConfig)).build(); - } - - public static KubernetesClient createClient() { - org.eclipse.microprofile.config.Config config = ConfigProvider.getConfig(); - Config base = Config.autoConfigure(null); - final var configBuilder = new ConfigBuilder(base); - optional(config, "trust-certs", Boolean.class).ifPresent(configBuilder::withTrustCerts); - optional(config, "watch-reconnect-limit", Integer.class).ifPresent(configBuilder::withWatchReconnectLimit); + public static Config createConfig() { + io.smallrye.config.Config config = io.smallrye.config.Config.get(); + boolean globalTrustAll = config.getOptionalValue("quarkus.tls.trust-all", Boolean.class).orElse(false); + Config base; + Optional kubeconfigFile = optional(config, "kubeconfig-file", String.class); + if (kubeconfigFile.isPresent()) { + String kubeconfigPath = kubeconfigFile.get(); + try { + String kubeconfig = Files.readString(Path.of(kubeconfigPath)); + base = Config.fromKubeconfig(kubeconfig); + } catch (IOException e) { + throw new RuntimeException("Failed to read kubeconfig file: " + kubeconfigPath, e); + } + } else { + base = Config.autoConfigure(null); + } + boolean trustAll = optional(config, "trust-certs", Boolean.class).orElse(globalTrustAll); + final var configBuilder = new ConfigBuilder(base).withTrustCerts(trustAll); optional(config, "watch-reconnect-interval", Duration.class) - .map(KubernetesClientUtils::millisAsInt) - .ifPresent(configBuilder::withWatchReconnectInterval); + .ifPresent(d -> configBuilder.withWatchReconnectInterval(millisAsInt(d))); + optional(config, "watch-reconnect-limit", Integer.class).ifPresent(configBuilder::withWatchReconnectLimit); optional(config, "connection-timeout", Duration.class) - .map(KubernetesClientUtils::millisAsInt) - .ifPresent(configBuilder::withConnectionTimeout); + .ifPresent(d -> configBuilder.withConnectionTimeout(millisAsInt(d))); optional(config, "request-timeout", Duration.class) - .map(KubernetesClientUtils::millisAsInt) - .ifPresent(configBuilder::withRequestTimeout); + .ifPresent(d -> configBuilder.withRequestTimeout(millisAsInt(d))); optional(config, "api-server-url", String.class) .or(() -> optional(config, "master-url", String.class)) .ifPresent(configBuilder::withMasterUrl); optional(config, "namespace", String.class).ifPresent(configBuilder::withNamespace); optional(config, "username", String.class).ifPresent(configBuilder::withUsername); optional(config, "password", String.class).ifPresent(configBuilder::withPassword); + optional(config, "token", String.class).ifPresent(configBuilder::withOauthToken); optional(config, "ca-cert-file", String.class).ifPresent(configBuilder::withCaCertFile); optional(config, "ca-cert-data", String.class).ifPresent(configBuilder::withCaCertData); optional(config, "client-cert-file", String.class).ifPresent(configBuilder::withClientCertFile); optional(config, "client-cert-data", String.class).ifPresent(configBuilder::withClientCertData); optional(config, "client-key-file", String.class).ifPresent(configBuilder::withClientKeyFile); optional(config, "client-key-data", String.class).ifPresent(configBuilder::withClientKeyData); - optional(config, "client-key-passphrase", String.class).ifPresent(configBuilder::withClientKeyPassphrase); optional(config, "client-key-algo", String.class).ifPresent(configBuilder::withClientKeyAlgo); + optional(config, "client-key-passphrase", String.class).ifPresent(configBuilder::withClientKeyPassphrase); optional(config, "http-proxy", String.class).ifPresent(configBuilder::withHttpProxy); optional(config, "https-proxy", String.class).ifPresent(configBuilder::withHttpsProxy); optional(config, "proxy-username", String.class).ifPresent(configBuilder::withProxyUsername); optional(config, "proxy-password", String.class).ifPresent(configBuilder::withProxyPassword); optional(config, "no-proxy", String[].class).ifPresent(configBuilder::withNoProxy); - return new KubernetesClientBuilder().withConfig(configBuilder.build()).build(); + optional(config, "request-retry-backoff-interval", Duration.class) + .ifPresent(d -> configBuilder.withRequestRetryBackoffInterval(millisAsInt(d))); + optional(config, "request-retry-backoff-limit", Integer.class).ifPresent(configBuilder::withRequestRetryBackoffLimit); + return configBuilder.build(); + } + + public static KubernetesClient createClient(KubernetesClientConfig buildConfig) { + return new KubernetesClientBuilder().withConfig(createConfig(buildConfig)).build(); + } + + public static KubernetesClient createClient() { + return new KubernetesClientBuilder().withConfig(createConfig()).build(); } private static Optional optional(org.eclipse.microprofile.config.Config config, String key, Class valueType) { return config.getOptionalValue(PREFIX + key, valueType); } + + private static int millisAsInt(Duration duration) { + return (int) duration.toMillis(); + } } diff --git a/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/KubernetesConfigCustomizer.java b/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/KubernetesConfigCustomizer.java index c03a474491eef..5239643a2f354 100644 --- a/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/KubernetesConfigCustomizer.java +++ b/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/KubernetesConfigCustomizer.java @@ -7,7 +7,7 @@ import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.quarkus.kubernetes.client.runtime.KubernetesClientProducer; import io.quarkus.kubernetes.client.runtime.KubernetesConfigProducer; -import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientBuildConfig; +import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientConfig; /** * Meant to be implemented by a CDI bean that provided arbitrary customization for the default {@link Config} created by @@ -16,7 +16,7 @@ * The {@link Config} is in turn used to produce the default {@link KubernetesClient} *

* - * @see KubernetesConfigProducer#config(KubernetesClientBuildConfig, List) + * @see KubernetesConfigProducer#config(KubernetesClientConfig, List) * @see KubernetesClientProducer#kubernetesClient(KubernetesSerialization, Config) */ public interface KubernetesConfigCustomizer { diff --git a/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesConfigProducer.java b/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesConfigProducer.java index 0869047881d93..237ee366bc14e 100644 --- a/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesConfigProducer.java +++ b/extensions/kubernetes-client/runtime/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesConfigProducer.java @@ -9,7 +9,7 @@ import io.quarkus.arc.All; import io.quarkus.arc.DefaultBean; import io.quarkus.kubernetes.client.KubernetesConfigCustomizer; -import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientBuildConfig; +import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientConfig; import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientUtils; @Singleton @@ -18,9 +18,9 @@ public class KubernetesConfigProducer { @DefaultBean @Singleton @Produces - public Config config(KubernetesClientBuildConfig buildConfig, + public Config config(KubernetesClientConfig clientConfig, @All List customizers) { - var result = KubernetesClientUtils.createConfig(buildConfig); + var result = KubernetesClientUtils.createConfig(clientConfig); for (KubernetesConfigCustomizer customizer : customizers) { customizer.customize(result); } diff --git a/extensions/kubernetes-client/runtime/src/test/java/io/quarkus/kubernetes/client/runtime/KubernetesClientUtilsTest.java b/extensions/kubernetes-client/runtime/src/test/java/io/quarkus/kubernetes/client/runtime/KubernetesClientUtilsTest.java index b766b60134caa..973b228e83db9 100644 --- a/extensions/kubernetes-client/runtime/src/test/java/io/quarkus/kubernetes/client/runtime/KubernetesClientUtilsTest.java +++ b/extensions/kubernetes-client/runtime/src/test/java/io/quarkus/kubernetes/client/runtime/KubernetesClientUtilsTest.java @@ -5,6 +5,7 @@ import java.io.File; +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -31,10 +32,12 @@ void shouldGetConfigWithTrustCerts() throws Exception { @Test void shouldGetClientWithTrustCerts() throws Exception { + io.smallrye.config.Config config = io.smallrye.config.Config.getOrCreate(); System.setProperty(Config.KUBERNETES_KUBECONFIG_FILE, new File(getClass().getResource("/test-kubeconfig").toURI()).getAbsolutePath()); try (KubernetesClient client = KubernetesClientUtils.createClient()) { assertTrue(client.getConfiguration().isTrustCerts()); } + ConfigProviderResolver.instance().releaseConfig(config); } } diff --git a/extensions/kubernetes-config/runtime/src/main/java/io/quarkus/kubernetes/config/runtime/KubernetesConfigSourceFactoryBuilder.java b/extensions/kubernetes-config/runtime/src/main/java/io/quarkus/kubernetes/config/runtime/KubernetesConfigSourceFactoryBuilder.java index b3b0f1bd9592b..77fe5e7c3818d 100644 --- a/extensions/kubernetes-config/runtime/src/main/java/io/quarkus/kubernetes/config/runtime/KubernetesConfigSourceFactoryBuilder.java +++ b/extensions/kubernetes-config/runtime/src/main/java/io/quarkus/kubernetes/config/runtime/KubernetesConfigSourceFactoryBuilder.java @@ -5,7 +5,7 @@ import org.eclipse.microprofile.config.spi.ConfigSource; import io.fabric8.kubernetes.client.KubernetesClient; -import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientBuildConfig; +import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientConfig; import io.quarkus.kubernetes.client.runtime.internal.KubernetesClientUtils; import io.quarkus.runtime.ApplicationLifecycleManager; import io.quarkus.runtime.configuration.ConfigBuilder; @@ -19,10 +19,10 @@ public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder) return builder.withSources(new KubernetesConfigFactory()); } - static class KubernetesConfigFactory implements ConfigurableConfigSourceFactory { + static class KubernetesConfigFactory implements ConfigurableConfigSourceFactory { @Override public Iterable getConfigSources(final ConfigSourceContext context, - final KubernetesClientBuildConfig config) { + final KubernetesClientConfig config) { boolean inAppCDsGeneration = Boolean .parseBoolean(System.getProperty(ApplicationLifecycleManager.QUARKUS_APPCDS_GENERATE_PROP, "false")); if (inAppCDsGeneration) { diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java index 80ed485304571..b2597805dee32 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java @@ -1059,7 +1059,8 @@ private void log() { String info = appDescriptions.stream().limit(limit).map(d -> "\t- " + d).collect(Collectors.joining(",\n")); if (appDescriptions.size() > limit) { info += "\n\t- and " + (appDescriptions.size() - limit) - + " more - please enable debug logging to see the full list"; + + " more - to see the full list, add quarkus.log.category.\"" + + LOGGER.getName() + "\".level=DEBUG to your application.properties"; } LOGGER.infof( "Found unrecommended usage of private members (use package-private instead) in application beans:%n%s", diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/DefaultAsyncObserverExceptionHandler.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/DefaultAsyncObserverExceptionHandler.java index c1f983e284d4d..05109effd9534 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/DefaultAsyncObserverExceptionHandler.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/DefaultAsyncObserverExceptionHandler.java @@ -18,8 +18,9 @@ public class DefaultAsyncObserverExceptionHandler implements AsyncObserverExcept @Override public void handle(Throwable throwable, ObserverMethod observerMethod, EventContext eventContext) { LOG.errorf( - "Failure occurred while notifying an async %s for event of type %s \n- please enable debug logging to see the full stack trace", - observerMethod, eventContext.getMetadata().getType().getTypeName()); + "Failure occurred while notifying an async %s for event of type %s" + + "\n- to see the full stack trace, add quarkus.log.category.\"%s\".level=DEBUG to your application.properties", + observerMethod, eventContext.getMetadata().getType().getTypeName(), LOG.getName()); LOG.debugf(throwable, "Failure occurred while notifying an async %s for event of type %s", observerMethod, eventContext.getMetadata().getType().getTypeName()); } diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java index 6657dabd22dc1..194b6c1fae565 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java @@ -493,14 +493,14 @@ public void run() { } catch (Exception e) { // swallow exception and log errors for every problematic OM LOG.errorf( - "Failure occurred while notifying a transational %s for event of type %s " + - "\n- please enable debug logging to see the full stack trace" + - "\n %s", - observerMethod, eventContext.getMetadata().getType().getTypeName(), + "Failure occurred while notifying a transactional %s for event of type %s" + + "\n- to see the full stack trace, add quarkus.log.category.\"%s\".level=DEBUG " + + "to your application.properties \n %s", + observerMethod, eventContext.getMetadata().getType().getTypeName(), LOG.getName(), e.getCause() != null && e.getMessage() != null ? "Cause: " + e.getCause() + " Message: " + e.getMessage() : "Exception caught: " + e); - LOG.debugf(e, "Failure occurred while notifying a transational %s for event of type %s", + LOG.debugf(e, "Failure occurred while notifying a transactional %s for event of type %s", observerMethod, eventContext.getMetadata().getType().getTypeName()); } }