From 6f65622580d3f01acb8de269381767fd6d7d7a8b Mon Sep 17 00:00:00 2001 From: glefloch Date: Tue, 28 Jun 2022 22:42:38 +0200 Subject: [PATCH 01/26] Explicitly cast provider objects for older Gradle version support (cherry picked from commit 56d7655a1298a5db71aa0c53c2c9294ed77f25d5) --- ...ApplicationDeploymentClasspathBuilder.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java index c456a82b2aa4d..b463445777c46 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java @@ -22,6 +22,7 @@ import org.gradle.api.internal.artifacts.dependencies.DefaultDependencyArtifact; import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency; import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.provider.ListProperty; import io.quarkus.bootstrap.BootstrapConstants; import io.quarkus.bootstrap.model.PlatformImports; @@ -135,13 +136,15 @@ private void setUpPlatformConfiguration() { project.getConfigurations().create(this.platformConfigurationName, configuration -> { // Platform configuration is just implementation, filtered to platform dependencies - configuration.getDependencies().addAllLater(project.provider(() -> project.getConfigurations() - .getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME) - .getAllDependencies() - .stream() - .filter(dependency -> dependency instanceof ModuleDependency && - ToolingUtils.isEnforcedPlatform((ModuleDependency) dependency)) - .collect(Collectors.toList()))); + ListProperty dependencyListProperty = project.getObjects().listProperty(Dependency.class); + configuration.getDependencies() + .addAllLater(dependencyListProperty.value(project.provider(() -> project.getConfigurations() + .getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME) + .getAllDependencies() + .stream() + .filter(dependency -> dependency instanceof ModuleDependency && + ToolingUtils.isEnforcedPlatform((ModuleDependency) dependency)) + .collect(Collectors.toList())))); // Configures PlatformImportsImpl once the platform configuration is resolved configuration.getResolutionStrategy().eachDependency(d -> { ModuleIdentifier identifier = d.getTarget().getModule(); @@ -192,7 +195,8 @@ private void setUpDeploymentConfiguration() { project.getConfigurations().create(this.deploymentConfigurationName, configuration -> { Configuration enforcedPlatforms = this.getPlatformConfiguration(); configuration.extendsFrom(enforcedPlatforms); - configuration.getDependencies().addAllLater(project.provider(() -> { + ListProperty dependencyListProperty = project.getObjects().listProperty(Dependency.class); + configuration.getDependencies().addAllLater(dependencyListProperty.value(project.provider(() -> { ConditionalDependenciesEnabler cdEnabler = new ConditionalDependenciesEnabler(project, mode, enforcedPlatforms); final Collection allExtensions = cdEnabler.getAllExtensions(); @@ -225,7 +229,7 @@ private void setUpDeploymentConfiguration() { } } return deploymentDependencies; - })); + }))); }); } } From 58e206bb1a250fc096ae15f00db223c132a90575 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 21:26:07 +0000 Subject: [PATCH 02/26] Bump smallrye-common-bom from 1.12.0 to 1.13.0 Bumps [smallrye-common-bom](https://github.com/smallrye/smallrye-common) from 1.12.0 to 1.13.0. - [Release notes](https://github.com/smallrye/smallrye-common/releases) - [Commits](https://github.com/smallrye/smallrye-common/compare/1.12.0...1.13.0) --- updated-dependencies: - dependency-name: io.smallrye.common:smallrye-common-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] (cherry picked from commit 12410e88e7f6f4828f5b25d8427414a5563bc45b) --- bom/application/pom.xml | 2 +- independent-projects/bootstrap/pom.xml | 2 +- independent-projects/resteasy-reactive/pom.xml | 2 +- independent-projects/tools/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 8ab52865056b4..8994024024fff 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -39,7 +39,7 @@ 2.0 1.2 1.0 - 1.12.0 + 1.13.0 2.10.1 3.2.1 3.0.5 diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml index cef892d11f0e3..6329d510fae68 100644 --- a/independent-projects/bootstrap/pom.xml +++ b/independent-projects/bootstrap/pom.xml @@ -64,7 +64,7 @@ 1.7.36 22.1.0 2.6.0 - 1.12.0 + 1.13.0 7.4.2 0.0.9 0.1.1 diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index 72b88d8647a60..0df0d56fb4365 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -55,7 +55,7 @@ 2.0.1.Final 1.1.6 1.6.0 - 1.12.0 + 1.13.0 4.2.4 4.5.1 1.0.0.Final diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index 9eb7062c06c4b..9d751e0b22363 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -61,7 +61,7 @@ 999-SNAPSHOT 20 2.11.0 - 1.12.0 + 1.13.0 1.2.2 From 77103c3ddaa46073af5028e9c52e76bf9f999a4e Mon Sep 17 00:00:00 2001 From: Mathias Holzer Date: Tue, 28 Jun 2022 16:24:18 +0200 Subject: [PATCH 03/26] Update mongodb-panache.adoc Fixed examples of simplified update queries, see https://github.com/quarkusio/quarkus/discussions/26395 (cherry picked from commit 9010af5aff1ff789e339b625c4ff3fc33702cc8b) --- docs/src/main/asciidoc/mongodb-panache.adoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/main/asciidoc/mongodb-panache.adoc b/docs/src/main/asciidoc/mongodb-panache.adoc index 0dadf4f6b88f2..5fc7bc508281a 100644 --- a/docs/src/main/asciidoc/mongodb-panache.adoc +++ b/docs/src/main/asciidoc/mongodb-panache.adoc @@ -583,16 +583,16 @@ The MongoDB POJO codec doesn't support `ZonedDateTime` and `OffsetDateTime` so y MongoDB with Panache also supports extended MongoDB queries by providing a `Document` query, this is supported by the find/list/stream/count/delete/update methods. MongoDB with Panache offers operations to update multiple documents based on an update document and a query : -`Person.update("foo = ?1, bar = ?2", fooName, barName).where("name = ?1", name)`. +`Person.update("foo = ?1 and bar = ?2", fooName, barName).where("name = ?1", name)`. For these operations, you can express the update document the same way you express your queries, here are some examples: - `` (and single parameter) which will expand to the update document `{'$set' : {'singleColumnName': '?1'}}` -- `firstname = ?1, status = ?2` will be mapped to the update document `{'$set' : {'firstname': ?1, 'status': ?2}}` -- `firstname = :firstname, status = :status` will be mapped to the update document `{'$set' : {'firstname': :firstname, 'status': :status}}` -- `{'firstname' : ?1, 'status' : ?2}` will be mapped to the update document `{'$set' : {'firstname': ?1, 'status': ?2}}` -- `{'firstname' : firstname, 'status' : :status}` ` will be mapped to the update document `{'$set' : {'firstname': :firstname, 'status': :status}}` -- `{'$inc': {'cpt': ?1}}` will be use as-is +- `firstname = ?1 and status = ?2` will be mapped to the update document `{'$set' : {'firstname': ?1, 'status': ?2}}` +- `firstname = :firstname and status = :status` will be mapped to the update document `{'$set' : {'firstname': :firstname, 'status': :status}}` +- `{'firstname' : ?1 and 'status' : ?2}` will be mapped to the update document `{'$set' : {'firstname': ?1, 'status': ?2}}` +- `{'firstname' : :firstname and 'status' : :status}` ` will be mapped to the update document `{'$set' : {'firstname': :firstname, 'status': :status}}` +- `{'$inc': {'cpt': ?1}}` will be used as-is === Query parameters From f5d20ec6b90e0b823146a2bba803774fc5f4c298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Wed, 29 Jun 2022 10:13:02 +0200 Subject: [PATCH 04/26] Fix the wrong update example on MongoDB with Panache and Kotlin guide (cherry picked from commit 51349278caed4a1994b4b92d8bb71f099516619e) --- docs/src/main/asciidoc/mongodb-panache-kotlin.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/mongodb-panache-kotlin.adoc b/docs/src/main/asciidoc/mongodb-panache-kotlin.adoc index 9f501ee920a25..c96c289788d9b 100644 --- a/docs/src/main/asciidoc/mongodb-panache-kotlin.adoc +++ b/docs/src/main/asciidoc/mongodb-panache-kotlin.adoc @@ -155,7 +155,7 @@ personRepository.deleteAll() val deleted = personRepository.deleteById(personId) // set the name of all living persons to 'Mortal' -personRepository.update("name = 'Mortal' where status = ?1", Status.Alive) +var updated = personRepository.update("name", "Mortal").where("status", Status.Alive) ---- From bed4e9000fe93be9284e0ab4410d02d77b5cdf78 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 27 Jun 2022 10:54:27 +0300 Subject: [PATCH 05/26] Fix combination of remote-dev and Jib created containers Fixes: #26113 (cherry picked from commit 5101e8ba692d11c2e5df4d18c01695da0bc9d8b7) --- .../image/jib/deployment/JibProcessor.java | 94 ++++++++++++++----- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java index eab870372a6df..e54c923cafdd2 100644 --- a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java @@ -1,8 +1,12 @@ package io.quarkus.container.image.jib.deployment; +import static com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer.DEFAULT_FILE_PERMISSIONS_PROVIDER; +import static com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer.DEFAULT_OWNERSHIP_PROVIDER; +import static com.google.cloud.tools.jib.api.buildplan.FilePermissions.DEFAULT_FILE_PERMISSIONS; import static io.quarkus.container.image.deployment.util.EnablementUtil.buildContainerImageNeeded; import static io.quarkus.container.image.deployment.util.EnablementUtil.pushContainerImageNeeded; import static io.quarkus.container.util.PathsUtil.findMainSourcesRoot; +import static io.quarkus.deployment.pkg.PackageConfig.MUTABLE_JAR; import java.io.IOException; import java.io.UncheckedIOException; @@ -43,6 +47,8 @@ import com.google.cloud.tools.jib.api.buildplan.FileEntriesLayer; import com.google.cloud.tools.jib.api.buildplan.FileEntry; import com.google.cloud.tools.jib.api.buildplan.FilePermissions; +import com.google.cloud.tools.jib.api.buildplan.FilePermissionsProvider; +import com.google.cloud.tools.jib.api.buildplan.OwnershipProvider; import com.google.cloud.tools.jib.api.buildplan.Port; import com.google.cloud.tools.jib.frontend.CredentialRetrieverFactory; @@ -56,7 +62,7 @@ import io.quarkus.container.spi.ContainerImageLabelBuildItem; import io.quarkus.container.spi.ContainerImagePushRequestBuildItem; import io.quarkus.container.util.PathsUtil; -import io.quarkus.deployment.IsNormalNotRemoteDev; +import io.quarkus.deployment.IsNormal; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.builditem.MainClassBuildItem; @@ -89,6 +95,16 @@ public class JibProcessor { private static final String DEFAULT_BASE_IMAGE_USER = "185"; private static final String OPENTELEMETRY_CONTEXT_CONTEXT_STORAGE_PROVIDER_SYS_PROP = "io.opentelemetry.context.contextStorageProvider"; + private static final FilePermissions REMOTE_DEV_FOLDER_PERMISSIONS = FilePermissions.fromOctalString("777"); + private static final FilePermissions REMOTE_DEV_FILE_PERMISSIONS = FilePermissions.fromOctalString("666"); + + private static final FilePermissionsProvider REMOTE_DEV_FOLDER_PERMISSIONS_PROVIDER = (sourcePath, + destinationPath) -> Files.isDirectory(sourcePath) + ? REMOTE_DEV_FOLDER_PERMISSIONS + : REMOTE_DEV_FILE_PERMISSIONS; + + private static final OwnershipProvider REMOTE_DEV_OWNERSHIP_PROVIDER = (sourcePath, + destinationPath) -> DEFAULT_BASE_IMAGE_USER; @BuildStep public AvailableContainerImageExtensionBuildItem availability() { @@ -122,7 +138,7 @@ private String determineBaseJvmImage(JibConfig jibConfig, CompiledJavaVersionBui return JAVA_11_BASE_IMAGE; } - @BuildStep(onlyIf = { IsNormalNotRemoteDev.class, JibBuild.class }, onlyIfNot = NativeBuild.class) + @BuildStep(onlyIf = { IsNormal.class, JibBuild.class }, onlyIfNot = NativeBuild.class) public void buildFromJar(ContainerImageConfig containerImageConfig, JibConfig jibConfig, PackageConfig packageConfig, ContainerImageInfoBuildItem containerImage, @@ -154,7 +170,7 @@ public void buildFromJar(ContainerImageConfig containerImageConfig, JibConfig ji jibContainerBuilder = createContainerBuilderFromFastJar(determineBaseJvmImage(jibConfig, compiledJavaVersion), jibConfig, containerImageConfig, sourceJar, curateOutcome, containerImageLabels, - appCDSResult); + appCDSResult, packageType.equals(MUTABLE_JAR)); } else { throw new IllegalArgumentException( "Package type '" + packageType + "' is not supported by the container-image-jib extension"); @@ -173,7 +189,7 @@ public void buildFromJar(ContainerImageConfig containerImageConfig, JibConfig ji containerImageBuilder.produce(new ContainerImageBuilderBuildItem(JIB)); } - @BuildStep(onlyIf = { IsNormalNotRemoteDev.class, JibBuild.class, NativeBuild.class }) + @BuildStep(onlyIf = { IsNormal.class, JibBuild.class, NativeBuild.class }) public void buildFromNative(ContainerImageConfig containerImageConfig, JibConfig jibConfig, ContainerImageInfoBuildItem containerImage, NativeImageBuildItem nativeImage, @@ -350,7 +366,8 @@ private JibContainerBuilder createContainerBuilderFromFastJar(String baseJvmImag ContainerImageConfig containerImageConfig, JarBuildItem sourceJarBuildItem, CurateOutcomeBuildItem curateOutcome, List containerImageLabels, - Optional appCDSResult) { + Optional appCDSResult, + boolean isMutableJar) { Path componentsPath = sourceJarBuildItem.getPath().getParent(); Path appLibDir = componentsPath.resolve(JarResultBuildStep.LIB).resolve(JarResultBuildStep.MAIN); @@ -435,7 +452,7 @@ private JibContainerBuilder createContainerBuilderFromFastJar(String baseJvmImag if (fastChangingLibPaths.isEmpty()) { // just create a layer with the entire lib structure intact addLayer(jibContainerBuilder, Collections.singletonList(componentsPath.resolve(JarResultBuildStep.LIB)), - workDirInContainer, "fast-jar-lib"); + workDirInContainer, "fast-jar-lib", isMutableJar, now); } else { // we need to manually create each layer // the idea here is that the fast changing libraries are created in a later layer, thus when they do change, @@ -464,23 +481,21 @@ private JibContainerBuilder createContainerBuilderFromFastJar(String baseJvmImag } jibContainerBuilder.addFileEntriesLayer(bootLibsLayerBuilder.build()); - Path deploymentPath = componentsPath.resolve(JarResultBuildStep.LIB).resolve(JarResultBuildStep.DEPLOYMENT_LIB); - if (Files.exists(deploymentPath)) { // this is the case of mutable-jar - FileEntriesLayer.Builder deploymentLayerBuilder = FileEntriesLayer.builder() - .setName("fast-jar-deployment-libs"); - Files.list(deploymentPath).forEach(lib -> { - AbsoluteUnixPath libPathInContainer = workDirInContainer.resolve(JarResultBuildStep.LIB) - .resolve(JarResultBuildStep.DEPLOYMENT_LIB) - .resolve(lib.getFileName()); - deploymentLayerBuilder.addEntry(lib, libPathInContainer); - }); - jibContainerBuilder.addFileEntriesLayer(deploymentLayerBuilder.build()); + if (isMutableJar) { + Path deploymentPath = componentsPath.resolve(JarResultBuildStep.LIB) + .resolve(JarResultBuildStep.DEPLOYMENT_LIB); + addLayer(jibContainerBuilder, Collections.singletonList(deploymentPath), + workDirInContainer.resolve(JarResultBuildStep.LIB) + .resolve(JarResultBuildStep.DEPLOYMENT_LIB), + "fast-jar-deployment-libs", true, now); } AbsoluteUnixPath libsMainPath = workDirInContainer.resolve(JarResultBuildStep.LIB) .resolve(JarResultBuildStep.MAIN); - addLayer(jibContainerBuilder, nonFastChangingLibPaths, libsMainPath, "fast-jar-normal-libs"); - addLayer(jibContainerBuilder, new ArrayList<>(fastChangingLibPaths), libsMainPath, "fast-jar-changing-libs"); + addLayer(jibContainerBuilder, nonFastChangingLibPaths, libsMainPath, "fast-jar-normal-libs", + isMutableJar, now); + addLayer(jibContainerBuilder, new ArrayList<>(fastChangingLibPaths), libsMainPath, "fast-jar-changing-libs", + isMutableJar, now); } if (appCDSResult.isPresent()) { @@ -492,15 +507,21 @@ private JibContainerBuilder createContainerBuilderFromFastJar(String baseJvmImag jibContainerBuilder .addLayer(Collections.singletonList(appCDSResult.get().getAppCDS()), workDirInContainer); } else { - jibContainerBuilder.addFileEntriesLayer(FileEntriesLayer.builder().setName("fast-jar-run").addEntry( - componentsPath.resolve(JarResultBuildStep.QUARKUS_RUN_JAR), - workDirInContainer.resolve(JarResultBuildStep.QUARKUS_RUN_JAR)).build()); + jibContainerBuilder.addFileEntriesLayer(FileEntriesLayer.builder() + .setName("fast-jar-run") + .addEntry( + componentsPath.resolve(JarResultBuildStep.QUARKUS_RUN_JAR), + workDirInContainer.resolve(JarResultBuildStep.QUARKUS_RUN_JAR), + isMutableJar ? REMOTE_DEV_FILE_PERMISSIONS : DEFAULT_FILE_PERMISSIONS, + now, + isMutableJar ? DEFAULT_BASE_IMAGE_USER : "") + .build()); } addLayer(jibContainerBuilder, Collections.singletonList(componentsPath.resolve(JarResultBuildStep.APP)), - workDirInContainer, "fast-jar-quarkus-app"); + workDirInContainer, "fast-jar-quarkus-app", isMutableJar, now); addLayer(jibContainerBuilder, Collections.singletonList(componentsPath.resolve(JarResultBuildStep.QUARKUS)), - workDirInContainer, "fast-jar-quarkus"); + workDirInContainer, "fast-jar-quarkus", isMutableJar, now); if (JibConfig.DEFAULT_WORKING_DIR.equals(jibConfig.workingDirectory)) { // this layer ensures that the working directory is writeable // see https://github.com/GoogleContainerTools/jib/issues/1270 @@ -513,6 +534,23 @@ private JibContainerBuilder createContainerBuilderFromFastJar(String baseJvmImag now, DEFAULT_BASE_IMAGE_USER)) .build()); } + if (isMutableJar) { + // this layer is needed for remote-dev + jibContainerBuilder.addFileEntriesLayer(FileEntriesLayer.builder() + .addEntry( + new FileEntry( + Files.createTempDirectory("jib"), + workDirInContainer.resolve("dev"), + REMOTE_DEV_FOLDER_PERMISSIONS, + now, DEFAULT_BASE_IMAGE_USER)) + .addEntry( + new FileEntry( + componentsPath.resolve(JarResultBuildStep.QUARKUS_APP_DEPS), + workDirInContainer.resolve(JarResultBuildStep.QUARKUS_APP_DEPS), + REMOTE_DEV_FOLDER_PERMISSIONS, + now, DEFAULT_BASE_IMAGE_USER)) + .build()); + } jibContainerBuilder .setWorkingDirectory(workDirInContainer) @@ -538,13 +576,17 @@ private JibContainerBuilder createContainerBuilderFromFastJar(String baseJvmImag } public JibContainerBuilder addLayer(JibContainerBuilder jibContainerBuilder, List files, - AbsoluteUnixPath pathInContainer, String name) + AbsoluteUnixPath pathInContainer, String name, boolean isMutableJar, + Instant now) throws IOException { FileEntriesLayer.Builder layerConfigurationBuilder = FileEntriesLayer.builder().setName(name); for (Path file : files) { layerConfigurationBuilder.addEntryRecursive( - file, pathInContainer.resolve(file.getFileName())); + file, pathInContainer.resolve(file.getFileName()), + isMutableJar ? REMOTE_DEV_FOLDER_PERMISSIONS_PROVIDER : DEFAULT_FILE_PERMISSIONS_PROVIDER, + (sourcePath, destinationPath) -> now, + isMutableJar ? REMOTE_DEV_OWNERSHIP_PROVIDER : DEFAULT_OWNERSHIP_PROVIDER); } return jibContainerBuilder.addFileEntriesLayer(layerConfigurationBuilder.build()); From d93addf2ac25591c352bc70cd2071a821b344379 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 29 Jun 2022 09:02:30 +0300 Subject: [PATCH 06/26] Attempt to fix podman DNS issue As found by @holly-cummins, podman's internal DNS is case-sensitive. This seems to be causing issues for some our dev-services being run on podman. This changes ensures that the hostname is always lowercase thus circumventing the problem. See https://quarkusio.zulipchat.com/#narrow/stream/187038-dev/topic/DNS.20woes.3A.20Podman.20.2B.20Mongo.20.2B.20Dev.20services.20.2FTestcontainers.20-.2E.2E.2E/near/287736870 for a complete discussion (cherry picked from commit 324021674b6e174ea7250923c2753d6e5bfa4a8a) --- .../main/java/io/quarkus/devservices/common/ConfigureUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/devservices/common/src/main/java/io/quarkus/devservices/common/ConfigureUtil.java b/extensions/devservices/common/src/main/java/io/quarkus/devservices/common/ConfigureUtil.java index fbd23fe8f2156..1ffa51b9ab7b3 100644 --- a/extensions/devservices/common/src/main/java/io/quarkus/devservices/common/ConfigureUtil.java +++ b/extensions/devservices/common/src/main/java/io/quarkus/devservices/common/ConfigureUtil.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.io.UncheckedIOException; import java.util.Collections; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; @@ -41,7 +42,7 @@ public static String configureSharedNetwork(GenericContainer container, Strin container.setNetwork(Network.SHARED); } - String hostName = hostNamePrefix + "-" + Base58.randomString(5); + String hostName = (hostNamePrefix + "-" + Base58.randomString(5)).toLowerCase(Locale.ROOT); container.setNetworkAliases(Collections.singletonList(hostName)); return hostName; From cbef8fb0beac9bd82564fce4f7f563c2844a184c Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Fri, 24 Jun 2022 18:47:01 +0100 Subject: [PATCH 07/26] Fix Span names for 404 and when Micrometer is available and disabled (cherry picked from commit 9ab4f19b873768f37028f9a2c3865f5c37a53ede) --- .../deployment/tracing/TracerProcessor.java | 6 ++- .../deployment/TracerRouter.java | 9 ++++ .../deployment/VertxOpenTelemetryTest.java | 53 ++++++++++++++++++- .../vertx/HttpInstrumenterVertxTracer.java | 15 ++++-- integration-tests/opentelemetry-vertx/pom.xml | 17 ++++++ .../it/opentelemetry/vertx/SpanData.java | 3 +- .../src/main/resources/application.properties | 1 + 7 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 integration-tests/opentelemetry-vertx/src/main/resources/application.properties diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProcessor.java b/extensions/opentelemetry/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProcessor.java index 186ded09630f9..360d23f7d7740 100644 --- a/extensions/opentelemetry/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProcessor.java +++ b/extensions/opentelemetry/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProcessor.java @@ -11,6 +11,7 @@ import java.util.Set; import java.util.function.BooleanSupplier; +import org.eclipse.microprofile.config.ConfigProvider; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.DotName; @@ -60,7 +61,8 @@ static class MetricsExtensionAvailable implements BooleanSupplier { @Override public boolean getAsBoolean() { - return IS_MICROMETER_EXTENSION_AVAILABLE; + return IS_MICROMETER_EXTENSION_AVAILABLE && ConfigProvider.getConfig() + .getOptionalValue("quarkus.micrometer.binder.http-server.enabled", Boolean.class).orElse(true); } } @@ -178,7 +180,7 @@ VertxOptionsConsumerBuildItem vertxTracingOptions(TracerRecorder recorder) { @BuildStep(onlyIf = TracerEnabled.class, onlyIfNot = MetricsExtensionAvailable.class) @Record(ExecutionTime.STATIC_INIT) VertxOptionsConsumerBuildItem vertxTracingMetricsOptions(TracerRecorder recorder) { - return new VertxOptionsConsumerBuildItem(recorder.getVertxTracingMetricsOptions(), LIBRARY_AFTER); + return new VertxOptionsConsumerBuildItem(recorder.getVertxTracingMetricsOptions(), LIBRARY_AFTER + 1); } @BuildStep(onlyIf = TracerEnabled.class) diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/TracerRouter.java b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/TracerRouter.java index 00c2cb236f225..9010599d11f5b 100644 --- a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/TracerRouter.java +++ b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/TracerRouter.java @@ -22,5 +22,14 @@ public void register(@Observes StartupEvent ev) { .end(); rc.response().end("Hello Tracer!"); }); + + router.get("/hello/:name").handler(rc -> { + String name = rc.pathParam("name"); + if (name.equals("Naruto")) { + rc.response().end("hello " + name); + } else { + rc.response().setStatusCode(404).end(); + } + }); } } diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxOpenTelemetryTest.java b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxOpenTelemetryTest.java index e319dc5811ba6..9f2daed3684b0 100644 --- a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxOpenTelemetryTest.java +++ b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxOpenTelemetryTest.java @@ -4,11 +4,18 @@ import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_CLIENT_IP; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_FLAVOR; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_HOST; +import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_METHOD; +import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_ROUTE; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_SCHEME; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_STATUS_CODE; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_TARGET; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_USER_AGENT; +import static io.restassured.RestAssured.given; +import static io.vertx.core.http.HttpMethod.GET; +import static java.net.HttpURLConnection.HTTP_NOT_FOUND; +import static java.net.HttpURLConnection.HTTP_OK; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.stringContainsInOrder; @@ -67,7 +74,7 @@ void trace() throws NoSuchFieldException, IllegalAccessException, InvocationTarg assertEquals("io.quarkus.vertx.opentelemetry", spans.get(0).getName()); assertEquals("hello!", spans.get(0).getAttributes().get(stringKey("test.message"))); - assertEquals(200, spans.get(1).getAttributes().get(HTTP_STATUS_CODE)); + assertEquals(HTTP_OK, spans.get(1).getAttributes().get(HTTP_STATUS_CODE)); assertEquals("1.1", spans.get(1).getAttributes().get(HTTP_FLAVOR)); assertEquals("/tracer", spans.get(1).getAttributes().get(HTTP_TARGET)); assertEquals("http", spans.get(1).getAttributes().get(HTTP_SCHEME)); @@ -91,7 +98,7 @@ void spanNameWithoutQueryString() { assertEquals("io.quarkus.vertx.opentelemetry", spans.get(0).getName()); assertEquals("hello!", spans.get(0).getAttributes().get(stringKey("test.message"))); assertEquals("/tracer", spans.get(1).getName()); - assertEquals(200, spans.get(1).getAttributes().get(HTTP_STATUS_CODE)); + assertEquals(HTTP_OK, spans.get(1).getAttributes().get(HTTP_STATUS_CODE)); assertEquals("1.1", spans.get(1).getAttributes().get(HTTP_FLAVOR)); assertEquals("/tracer?id=1", spans.get(1).getAttributes().get(HTTP_TARGET)); assertEquals("http", spans.get(1).getAttributes().get(HTTP_SCHEME)); @@ -99,4 +106,46 @@ void spanNameWithoutQueryString() { assertEquals("127.0.0.1", spans.get(1).getAttributes().get(HTTP_CLIENT_IP)); assertNotNull(spans.get(1).getAttributes().get(HTTP_USER_AGENT)); } + + @Test + void spanPath() { + given() + .get("/hello/{name}", "Naruto") + .then() + .statusCode(HTTP_OK) + .body(equalTo("hello Naruto")); + + List spans = spanExporter.getFinishedSpanItems(1); + + assertEquals("/hello/:name", spans.get(0).getName()); + assertEquals(HTTP_OK, spans.get(0).getAttributes().get(HTTP_STATUS_CODE)); + assertEquals(GET.toString(), spans.get(0).getAttributes().get(HTTP_METHOD)); + assertEquals("/hello/:name", spans.get(0).getAttributes().get(HTTP_ROUTE)); + } + + @Test + void notFound() { + RestAssured.when().get("/notFound").then().statusCode(404); + + List spans = spanExporter.getFinishedSpanItems(1); + + assertEquals("/*", spans.get(0).getName()); + assertEquals("/*", spans.get(0).getAttributes().get(HTTP_ROUTE)); + assertEquals(HTTP_NOT_FOUND, spans.get(0).getAttributes().get(HTTP_STATUS_CODE)); + } + + @Test + void notFoundPath() { + given() + .get("/hello/{name}", "Goku") + .then() + .statusCode(HTTP_NOT_FOUND); + + List spans = spanExporter.getFinishedSpanItems(1); + + assertEquals("/hello/:name", spans.get(0).getName()); + assertEquals(HTTP_NOT_FOUND, spans.get(0).getAttributes().get(HTTP_STATUS_CODE)); + assertEquals(GET.toString(), spans.get(0).getAttributes().get(HTTP_METHOD)); + assertEquals("/hello/:name", spans.get(0).getAttributes().get(HTTP_ROUTE)); + } } diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java index a0777d328fff3..4ef7f25217086 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java @@ -1,5 +1,6 @@ package io.quarkus.opentelemetry.runtime.tracing.vertx; +import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteSource.FILTER; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_CLIENT_IP; import static io.quarkus.opentelemetry.runtime.OpenTelemetryConfig.INSTRUMENTATION_NAME; @@ -7,6 +8,7 @@ import java.util.List; import java.util.function.BiConsumer; +import io.netty.handler.codec.http.HttpResponseStatus; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Scope; @@ -17,7 +19,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesGetter; -import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteGetter; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteBiGetter; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteHolder; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesGetter; @@ -90,7 +92,7 @@ public void sendResponse( final TagExtractor tagExtractor) { HttpRouteHolder.updateHttpRoute(spanOperation.getSpanContext(), FILTER, RouteGetter.ROUTE_GETTER, - ((HttpRequestSpan) spanOperation.getRequest())); + ((HttpRequestSpan) spanOperation.getRequest()), (HttpResponse) response); InstrumenterVertxTracer.super.sendResponse(context, response, spanOperation, failure, tagExtractor); } @@ -131,11 +133,12 @@ private static Instrumenter getClientInstrumenter(fin .newClientInstrumenter(new HttpRequestTextMapSetter()); } - private static class RouteGetter implements HttpRouteGetter { + private static class RouteGetter implements HttpRouteBiGetter { static final RouteGetter ROUTE_GETTER = new RouteGetter(); @Override - public String get(final io.opentelemetry.context.Context context, final HttpRequestSpan requestSpan) { + public String get(final io.opentelemetry.context.Context context, final HttpRequestSpan requestSpan, + final HttpResponse response) { // RESTEasy String route = requestSpan.getContext().getLocal("UrlPathTemplate"); if (route == null) { @@ -147,6 +150,10 @@ public String get(final io.opentelemetry.context.Context context, final HttpRequ return route; } + if (HttpResponseStatus.NOT_FOUND.code() == response.statusCode()) { + return "/*"; + } + return null; } } diff --git a/integration-tests/opentelemetry-vertx/pom.xml b/integration-tests/opentelemetry-vertx/pom.xml index e987b50566a78..47673ea3d47ea 100644 --- a/integration-tests/opentelemetry-vertx/pom.xml +++ b/integration-tests/opentelemetry-vertx/pom.xml @@ -26,6 +26,10 @@ io.quarkus quarkus-agroal + + io.quarkus + quarkus-micrometer + @@ -128,6 +132,19 @@ + + io.quarkus + quarkus-micrometer-deployment + ${project.version} + pom + test + + + * + * + + + diff --git a/integration-tests/opentelemetry-vertx/src/main/java/io/quarkus/it/opentelemetry/vertx/SpanData.java b/integration-tests/opentelemetry-vertx/src/main/java/io/quarkus/it/opentelemetry/vertx/SpanData.java index ab5978158f5ce..35839340e7f75 100644 --- a/integration-tests/opentelemetry-vertx/src/main/java/io/quarkus/it/opentelemetry/vertx/SpanData.java +++ b/integration-tests/opentelemetry-vertx/src/main/java/io/quarkus/it/opentelemetry/vertx/SpanData.java @@ -22,7 +22,8 @@ "io.opentelemetry.sdk.resources.Resource", "io.opentelemetry.sdk.resources.AutoValue_Resource", "io.opentelemetry.api.common.Attributes", - "io.quarkus.opentelemetry.runtime.tracing.DelayedAttributes" + "io.quarkus.opentelemetry.runtime.tracing.DelayedAttributes", + "io.opentelemetry.sdk.common.AutoValue_InstrumentationScopeInfo" }) public class SpanData { } diff --git a/integration-tests/opentelemetry-vertx/src/main/resources/application.properties b/integration-tests/opentelemetry-vertx/src/main/resources/application.properties new file mode 100644 index 0000000000000..3cbd3f8084660 --- /dev/null +++ b/integration-tests/opentelemetry-vertx/src/main/resources/application.properties @@ -0,0 +1 @@ +quarkus.micrometer.binder.http-server.enabled=false From e0fbcc67a3486754217fae5c1138e57a0449c105 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Jun 2022 12:35:24 +0000 Subject: [PATCH 08/26] Bump com.gradle.plugin-publish from 0.21.0 to 1.0.0 in /devtools/gradle Bumps com.gradle.plugin-publish from 0.21.0 to 1.0.0. --- updated-dependencies: - dependency-name: com.gradle.plugin-publish dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] (cherry picked from commit 199031b1578d164f671f401e352714e121dce27c) --- devtools/gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/build.gradle b/devtools/gradle/build.gradle index a6ecf99832dc0..385d7ae265bf4 100644 --- a/devtools/gradle/build.gradle +++ b/devtools/gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradle.plugin-publish' version '0.21.0' apply false + id 'com.gradle.plugin-publish' version '1.0.0' apply false } subprojects { From 7946770e0698189cbe15fe519eb1c2f51c435fdc Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Wed, 29 Jun 2022 13:40:32 +0200 Subject: [PATCH 09/26] Fix DevMojoIT.testCapabilitiesConflict on Windows (cherry picked from commit 9217e3b65d66c0542f5b2f11f23925b6b9ee8844) --- .../java/io/quarkus/maven/it/DevMojoIT.java | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java index 87986e3040397..6ecd64d8b590a 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -92,34 +93,10 @@ public void testCapabilitiesConflict() throws MavenInvocationException, IOExcept String response = DevModeTestUtils.getHttpResponse("/hello", true); assertThat(response).contains(error.report()); - final StringWriter buf = new StringWriter(); - try (BufferedWriter writer = new BufferedWriter(buf)) { - writer.write(" "); - writer.newLine(); - writer.write(" org.acme"); - writer.newLine(); - writer.write(" acme-quarkus-ext"); - writer.newLine(); - writer.write(" "); - writer.newLine(); - } - final String acmeDep = buf.toString(); - filter(runnerPom, Collections.singletonMap(acmeDep, "")); + filter(runnerPom, Map.of("acme-quarkus-ext", "alt-quarkus-ext")); assertThat(DevModeTestUtils.getHttpResponse("/hello", false)).isEqualTo("hello"); - buf.getBuffer().setLength(0); - try (BufferedWriter writer = new BufferedWriter(buf)) { - writer.write(" "); - writer.newLine(); - writer.write(" org.acme"); - writer.newLine(); - writer.write(" alt-quarkus-ext"); - writer.newLine(); - writer.write(" "); - writer.newLine(); - } - final String altDep = buf.toString(); - filter(runnerPom, Collections.singletonMap(acmeDep, altDep)); + filter(runnerPom, Map.of("alt-quarkus-ext", "acme-quarkus-ext")); assertThat(DevModeTestUtils.getHttpResponse("/hello", false)).isEqualTo("hello"); } From ee1cc70e7169782934549583122b48498633bc61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Jun 2022 12:46:41 +0000 Subject: [PATCH 10/26] Bump testcontainers.version from 1.17.2 to 1.17.3 Bumps `testcontainers.version` from 1.17.2 to 1.17.3. Updates `testcontainers-bom` from 1.17.2 to 1.17.3 - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.17.2...1.17.3) Updates `testcontainers` from 1.17.2 to 1.17.3 - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.17.2...1.17.3) --- updated-dependencies: - dependency-name: org.testcontainers:testcontainers-bom dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.testcontainers:testcontainers dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] (cherry picked from commit f73fb479e95974fdf335229fdac096c31bd61f1f) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 8994024024fff..19fe9e47a601a 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -192,7 +192,7 @@ 2.2.3.Final 0.1.9.Final 0.8.8 - 1.17.2 + 1.17.3 3.2.13 2.2 2.6 From f18cc46876e7ea523ead29d53f65872afd7499f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 21:05:24 +0000 Subject: [PATCH 11/26] Bump apicurio-registry.version from 2.2.3.Final to 2.2.4.Final Bumps `apicurio-registry.version` from 2.2.3.Final to 2.2.4.Final. Updates `apicurio-registry-client` from 2.2.3.Final to 2.2.4.Final - [Release notes](https://github.com/apicurio/apicurio-registry/releases) - [Commits](https://github.com/apicurio/apicurio-registry/compare/2.2.3.Final...2.2.4.Final) Updates `apicurio-registry-serdes-avro-serde` from 2.2.3.Final to 2.2.4.Final --- updated-dependencies: - dependency-name: io.apicurio:apicurio-registry-client dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.apicurio:apicurio-registry-serdes-avro-serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] (cherry picked from commit 0058cb62791255ab5d3f0732ac2818b7ce4dbafa) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 19fe9e47a601a..9735571ad7618 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -189,7 +189,7 @@ 2.17.2 1.3.0.Final 1.11.0 - 2.2.3.Final + 2.2.4.Final 0.1.9.Final 0.8.8 1.17.3 From b9f75f153aa67dbd78139dc1f72e66ad2f108f25 Mon Sep 17 00:00:00 2001 From: Eric Deandrea Date: Thu, 23 Jun 2022 09:52:48 -0400 Subject: [PATCH 12/26] Update `apicurio-common-rest-client-vertx` version Update `apicurio-common-rest-client-vertx` version to the most recent version. The current version (`0.1.9.Final`) does not work with some versions of apicurio. `0.1.11.Final` does, and is being used already. See https://github.com/quarkusio/quarkus-super-heroes/blob/280ba7d522d8f3a30a809cd92c8c89987276d8f9/rest-fights/pom.xml#L104-L122 Closes #25378 (cherry picked from commit 786430256a4df7f9dbbf3655e02ad94169b0a546) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 9735571ad7618..2d8bd2e27f695 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -190,7 +190,7 @@ 1.3.0.Final 1.11.0 2.2.4.Final - 0.1.9.Final + 0.1.11.Final 0.8.8 1.17.3 3.2.13 From 5c149984af832eede8c7983873956f1fe85aeb38 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 29 Jun 2022 16:38:06 -0400 Subject: [PATCH 13/26] Set remote address correctly (cherry picked from commit 21306dbabe2e77bd99c5f71b440d9699e24d9c65) --- .../lambda/runtime/MockHttpEventServer.java | 1 + .../amazon/lambda/http/LambdaHttpHandler.java | 21 ++++++++++++------- .../lambda/runtime/MockRestEventServer.java | 3 +++ .../amazon/lambda/http/LambdaHttpHandler.java | 19 ++++++++++------- .../lambda/runtime/AmazonLambdaContext.java | 7 ------- 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/extensions/amazon-lambda-http/http-event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockHttpEventServer.java b/extensions/amazon-lambda-http/http-event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockHttpEventServer.java index 9ee81290fab64..cd6bfb7308cf0 100644 --- a/extensions/amazon-lambda-http/http-event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockHttpEventServer.java +++ b/extensions/amazon-lambda-http/http-event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockHttpEventServer.java @@ -56,6 +56,7 @@ public void handleHttpRequests(RoutingContext ctx) { event.setRequestContext(new APIGatewayV2HTTPEvent.RequestContext()); event.getRequestContext().setHttp(new APIGatewayV2HTTPEvent.RequestContext.Http()); event.getRequestContext().getHttp().setMethod(ctx.request().method().name()); + event.getRequestContext().getHttp().setSourceIp(ctx.request().connection().remoteAddress().hostAddress()); event.setRawPath(ctx.request().path()); event.setRawQueryString(ctx.request().query()); for (String header : ctx.request().headers().names()) { diff --git a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java index 38d19ef9e720e..7136c3825c1f9 100644 --- a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java +++ b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java @@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream; import java.net.InetSocketAddress; -import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; import java.nio.charset.StandardCharsets; @@ -36,7 +35,6 @@ import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.LastHttpContent; import io.netty.util.ReferenceCountUtil; -import io.quarkus.amazon.lambda.runtime.AmazonLambdaContext; import io.quarkus.netty.runtime.virtual.VirtualClientConnection; import io.quarkus.netty.runtime.virtual.VirtualResponseHandler; import io.quarkus.vertx.http.runtime.QuarkusHttpHeaders; @@ -67,7 +65,7 @@ public APIGatewayV2HTTPResponse handleRequest(APIGatewayV2HTTPEvent request, Con } try { - return nettyDispatch(clientAddress, request, (AmazonLambdaContext) context); + return nettyDispatch(clientAddress, request, context); } catch (Exception e) { log.error("Request Failure", e); APIGatewayV2HTTPResponse res = new APIGatewayV2HTTPResponse(); @@ -168,7 +166,7 @@ public void close() { } private APIGatewayV2HTTPResponse nettyDispatch(InetSocketAddress clientAddress, APIGatewayV2HTTPEvent request, - AmazonLambdaContext context) + Context context) throws Exception { QuarkusHttpHeaders quarkusHeaders = new QuarkusHttpHeaders(); quarkusHeaders.setContextObject(Context.class, context); @@ -221,12 +219,19 @@ httpMethod, ofNullable(request.getRawQueryString()) NettyResponseHandler handler = new NettyResponseHandler(request); VirtualClientConnection connection = VirtualClientConnection.connect(handler, VertxHttpRecorder.VIRTUAL_HTTP, clientAddress); - if (connection.peer().remoteAddress().equals(VertxHttpRecorder.VIRTUAL_HTTP)) { - URL requestURL = context.getRequestURL(); + if (request.getRequestContext() != null + && request.getRequestContext().getHttp() != null + && request.getRequestContext().getHttp().getSourceIp() != null + && request.getRequestContext().getHttp().getSourceIp().length() > 0) { + int port = 443; // todo, may be bad to assume 443? + if (request.getHeaders() != null && + request.getHeaders().get("X-Forwarded-Port") != null) { + port = Integer.parseInt(request.getHeaders().get("X-Forwarded-Port")); + } connection.peer().attr(ConnectionBase.REMOTE_ADDRESS_OVERRIDE).set( - SocketAddress.inetSocketAddress(requestURL.getPort(), requestURL.getHost())); + SocketAddress.inetSocketAddress(port, + request.getRequestContext().getHttp().getSourceIp())); } - connection.sendMessage(nettyRequest); connection.sendMessage(requestContent); try { diff --git a/extensions/amazon-lambda-rest/rest-event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockRestEventServer.java b/extensions/amazon-lambda-rest/rest-event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockRestEventServer.java index b19ed5d533b9a..9b2a6e684b6b2 100644 --- a/extensions/amazon-lambda-rest/rest-event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockRestEventServer.java +++ b/extensions/amazon-lambda-rest/rest-event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockRestEventServer.java @@ -16,6 +16,7 @@ import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectWriter; +import io.quarkus.amazon.lambda.http.model.ApiGatewayRequestIdentity; import io.quarkus.amazon.lambda.http.model.AwsProxyRequest; import io.quarkus.amazon.lambda.http.model.AwsProxyRequestContext; import io.quarkus.amazon.lambda.http.model.AwsProxyResponse; @@ -61,6 +62,8 @@ public void handleHttpRequests(RoutingContext ctx) { event.setRequestContext(new AwsProxyRequestContext()); event.getRequestContext().setRequestId(requestId); event.getRequestContext().setHttpMethod(ctx.request().method().name()); + event.getRequestContext().setIdentity(new ApiGatewayRequestIdentity()); + event.getRequestContext().getIdentity().setSourceIp(ctx.request().connection().remoteAddress().hostAddress()); event.setHttpMethod(ctx.request().method().name()); event.setPath(ctx.request().path()); if (ctx.request().query() != null) { diff --git a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java index bc219ffd8843b..54526c685e99a 100644 --- a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java +++ b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java @@ -2,7 +2,6 @@ import java.io.ByteArrayOutputStream; import java.net.InetSocketAddress; -import java.net.URL; import java.net.URLEncoder; import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; @@ -34,7 +33,6 @@ import io.quarkus.amazon.lambda.http.model.AwsProxyRequestContext; import io.quarkus.amazon.lambda.http.model.AwsProxyResponse; import io.quarkus.amazon.lambda.http.model.Headers; -import io.quarkus.amazon.lambda.runtime.AmazonLambdaContext; import io.quarkus.netty.runtime.virtual.VirtualClientConnection; import io.quarkus.netty.runtime.virtual.VirtualResponseHandler; import io.quarkus.vertx.http.runtime.QuarkusHttpHeaders; @@ -62,7 +60,7 @@ public AwsProxyResponse handleRequest(AwsProxyRequest request, Context context) } try { - return nettyDispatch(clientAddress, request, (AmazonLambdaContext) context); + return nettyDispatch(clientAddress, request, context); } catch (Exception e) { log.error("Request Failure", e); return new AwsProxyResponse(500, errorHeaders, "{ \"message\": \"Internal Server Error\" }"); @@ -152,7 +150,7 @@ public void close() { } private AwsProxyResponse nettyDispatch(InetSocketAddress clientAddress, AwsProxyRequest request, - AmazonLambdaContext context) + Context context) throws Exception { String path = request.getPath(); //log.info("---- Got lambda request: " + path); @@ -208,10 +206,17 @@ private AwsProxyResponse nettyDispatch(InetSocketAddress clientAddress, AwsProxy NettyResponseHandler handler = new NettyResponseHandler(request); VirtualClientConnection connection = VirtualClientConnection.connect(handler, VertxHttpRecorder.VIRTUAL_HTTP, clientAddress); - if (connection.peer().remoteAddress().equals(VertxHttpRecorder.VIRTUAL_HTTP)) { - URL requestURL = context.getRequestURL(); + if (request.getRequestContext() != null + && request.getRequestContext().getIdentity() != null + && request.getRequestContext().getIdentity().getSourceIp() != null + && request.getRequestContext().getIdentity().getSourceIp().length() > 0) { + int port = 443; // todo, may be bad to assume 443? + if (request.getMultiValueHeaders() != null && + request.getMultiValueHeaders().getFirst("X-Forwarded-Port") != null) { + port = Integer.parseInt(request.getMultiValueHeaders().getFirst("X-Forwarded-Port")); + } connection.peer().attr(ConnectionBase.REMOTE_ADDRESS_OVERRIDE).set( - SocketAddress.inetSocketAddress(requestURL.getPort(), requestURL.getHost())); + SocketAddress.inetSocketAddress(port, request.getRequestContext().getIdentity().getSourceIp())); } connection.sendMessage(nettyRequest); diff --git a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaContext.java b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaContext.java index 02b006d902482..946bcb46f3ac7 100644 --- a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaContext.java +++ b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaContext.java @@ -13,7 +13,6 @@ import java.io.IOException; import java.net.HttpURLConnection; -import java.net.URL; import com.amazonaws.services.lambda.runtime.ClientContext; import com.amazonaws.services.lambda.runtime.CognitoIdentity; @@ -35,7 +34,6 @@ public class AmazonLambdaContext implements Context { private long runtimeDeadlineMs = 0; private final int memoryLimitInMB; private final LambdaLogger logger; - private final URL requestURL; public AmazonLambdaContext(HttpURLConnection request, ObjectReader cognitoReader, ObjectReader clientCtxReader) throws IOException { @@ -64,7 +62,6 @@ public AmazonLambdaContext(HttpURLConnection request, ObjectReader cognitoReader runtimeDeadlineMs = Long.valueOf(runtimeDeadline); } logger = LambdaRuntime.getLogger(); - requestURL = request.getURL(); } @Override @@ -121,8 +118,4 @@ public int getMemoryLimitInMB() { public LambdaLogger getLogger() { return logger; } - - public URL getRequestURL() { - return requestURL; - } } From 053bd2042931750ad72c1823a90aad458e25c737 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Fri, 24 Jun 2022 20:57:21 +0100 Subject: [PATCH 14/26] Propagate OpenTelemetry context to gRPC services (cherry picked from commit 207504610c33f17b34a543576e78b1dc356223f4) --- .../deployment/GrpcOpenTelemetryTest.java | 32 +++++++++++++++---- .../grpc/GrpcTracingClientInterceptor.java | 18 ++++------- .../grpc/GrpcTracingServerInterceptor.java | 28 +++++++--------- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/GrpcOpenTelemetryTest.java b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/GrpcOpenTelemetryTest.java index d615bcc31e0d2..696a27bc90ff3 100644 --- a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/GrpcOpenTelemetryTest.java +++ b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/GrpcOpenTelemetryTest.java @@ -1,5 +1,6 @@ package io.quarkus.opentelemetry.deployment; +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_PEER_IP; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_PEER_PORT; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_TRANSPORT; @@ -7,6 +8,7 @@ import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.RPC_METHOD; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.RPC_SERVICE; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.RPC_SYSTEM; +import static io.quarkus.opentelemetry.runtime.OpenTelemetryConfig.INSTRUMENTATION_NAME; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -24,7 +26,11 @@ import io.grpc.Status; import io.grpc.stub.StreamObserver; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.extension.annotations.WithSpan; import io.opentelemetry.sdk.trace.data.SpanData; import io.quarkus.grpc.GrpcClient; @@ -67,10 +73,15 @@ void grpc() { .await().atMost(Duration.ofSeconds(5)); assertEquals("Hello Naruto", response); - List spans = spanExporter.getFinishedSpanItems(2); - assertEquals(2, spans.size()); + List spans = spanExporter.getFinishedSpanItems(3); + assertEquals(3, spans.size()); - SpanData server = spans.get(0); + SpanData internal = spans.get(0); + assertEquals("span.internal", internal.getName()); + assertEquals(INTERNAL, internal.getKind()); + assertEquals("value", internal.getAttributes().get(AttributeKey.stringKey("grpc.internal"))); + + SpanData server = spans.get(1); assertEquals("helloworld.Greeter/SayHello", server.getName()); assertEquals(SpanKind.SERVER, server.getKind()); assertEquals("grpc", server.getAttributes().get(RPC_SYSTEM)); @@ -81,7 +92,7 @@ void grpc() { assertNotNull(server.getAttributes().get(NET_PEER_PORT)); assertEquals("ip_tcp", server.getAttributes().get(NET_TRANSPORT)); - SpanData client = spans.get(1); + SpanData client = spans.get(2); assertEquals("helloworld.Greeter/SayHello", client.getName()); assertEquals(SpanKind.CLIENT, client.getKind()); assertEquals("grpc", client.getAttributes().get(RPC_SYSTEM)); @@ -89,6 +100,7 @@ void grpc() { assertEquals("SayHello", client.getAttributes().get(RPC_METHOD)); assertEquals(Status.Code.OK.value(), client.getAttributes().get(RPC_GRPC_STATUS_CODE)); + assertEquals(internal.getTraceId(), server.getTraceId()); assertEquals(server.getTraceId(), client.getTraceId()); } @@ -133,11 +145,12 @@ void error() { void withCdi() { assertEquals("Hello Naruto", helloBean.hello("Naruto")); - List spans = spanExporter.getFinishedSpanItems(3); - assertEquals(3, spans.size()); + List spans = spanExporter.getFinishedSpanItems(4); + assertEquals(4, spans.size()); assertEquals(spans.get(0).getTraceId(), spans.get(1).getTraceId()); assertEquals(spans.get(0).getTraceId(), spans.get(2).getTraceId()); + assertEquals(spans.get(0).getTraceId(), spans.get(3).getTraceId()); } @GrpcService @@ -149,6 +162,13 @@ public void sayHello(final HelloRequest request, final StreamObserver ClientCall interceptCall( GrpcRequest grpcRequest = GrpcRequest.client(method); Context parentContext = Context.current(); - Context spanContext = null; - Scope scope = null; boolean shouldStart = instrumenter.shouldStart(parentContext, grpcRequest); if (shouldStart) { - spanContext = instrumenter.start(parentContext, grpcRequest); - scope = spanContext.makeCurrent(); - } - - try { - ClientCall clientCall = next.newCall(method, callOptions); - return new TracingClientCall<>(clientCall, spanContext, grpcRequest); - } finally { - if (scope != null) { - scope.close(); + Context spanContext = instrumenter.start(parentContext, grpcRequest); + try (Scope ignored = spanContext.makeCurrent()) { + ClientCall clientCall = next.newCall(method, callOptions); + return new TracingClientCall<>(clientCall, spanContext, grpcRequest); } } + + return next.newCall(method, callOptions); } private enum GrpcTextMapSetter implements TextMapSetter { diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/grpc/GrpcTracingServerInterceptor.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/grpc/GrpcTracingServerInterceptor.java index 959188539fe3c..9166bd10329e4 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/grpc/GrpcTracingServerInterceptor.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/grpc/GrpcTracingServerInterceptor.java @@ -53,22 +53,16 @@ public ServerCall.Listener interceptCall( GrpcRequest grpcRequest = GrpcRequest.server(call.getMethodDescriptor(), headers, call.getAttributes()); Context parentContext = Context.current(); - Context spanContext = null; - Scope scope = null; boolean shouldStart = instrumenter.shouldStart(parentContext, grpcRequest); if (shouldStart) { - spanContext = instrumenter.start(parentContext, grpcRequest); - scope = spanContext.makeCurrent(); - } - - try { - TracingServerCall tracingServerCall = new TracingServerCall<>(call, spanContext, grpcRequest); - return new TracingServerCallListener<>(next.startCall(tracingServerCall, headers), spanContext, grpcRequest); - } finally { - if (scope != null) { - scope.close(); + Context spanContext = instrumenter.start(parentContext, grpcRequest); + try (Scope ignored = spanContext.makeCurrent()) { + TracingServerCall tracingServerCall = new TracingServerCall<>(call, spanContext, grpcRequest); + return new TracingServerCallListener<>(next.startCall(tracingServerCall, headers), spanContext, grpcRequest); } } + + return next.startCall(call, headers); } private static class GrpcServerNetServerAttributesGetter extends InetSocketAddressNetServerAttributesGetter { @@ -116,7 +110,7 @@ protected TracingServerCallListener(final ServerCall.Listener delegate, fi @Override public void onHalfClose() { - try { + try (Scope ignored = spanContext.makeCurrent()) { super.onHalfClose(); } catch (Exception e) { instrumenter.end(spanContext, grpcRequest, null, e); @@ -126,18 +120,18 @@ public void onHalfClose() { @Override public void onCancel() { - try { + try (Scope ignored = spanContext.makeCurrent()) { super.onCancel(); + instrumenter.end(spanContext, grpcRequest, Status.CANCELLED, null); } catch (Exception e) { instrumenter.end(spanContext, grpcRequest, null, e); throw e; } - instrumenter.end(spanContext, grpcRequest, Status.CANCELLED, null); } @Override public void onComplete() { - try { + try (Scope ignored = spanContext.makeCurrent()) { super.onComplete(); } catch (Exception e) { instrumenter.end(spanContext, grpcRequest, null, e); @@ -147,7 +141,7 @@ public void onComplete() { @Override public void onReady() { - try { + try (Scope ignored = spanContext.makeCurrent()) { super.onReady(); } catch (Exception e) { instrumenter.end(spanContext, grpcRequest, null, e); From 31a353493558d8b29897d1443f2088993ab20c8c Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 30 Jun 2022 11:56:29 +0300 Subject: [PATCH 15/26] Properly ensure that transfer-encoding is not set when content-length exists Fixes: #26464 (cherry picked from commit 8cf8d6192eb2066877481cb58b360f645b255b7f) --- .../vertx/ResteasyReactiveOutputStream.java | 17 +++++- .../test/response/ContentLengthTest.java | 56 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/response/ContentLengthTest.java diff --git a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java index 90d13ba225ec0..d5cf25c8240fd 100644 --- a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java +++ b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java @@ -6,12 +6,15 @@ import io.vertx.core.Context; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpServerRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; +import javax.ws.rs.core.MultivaluedMap; import org.jboss.logging.Logger; +import org.jboss.resteasy.reactive.server.core.LazyResponse; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; public class ResteasyReactiveOutputStream extends OutputStream { @@ -233,12 +236,24 @@ private void prepareWrite(ByteBuf buffer, boolean finished) throws IOException { } else { context.serverResponse().setResponseHeader(HttpHeaderNames.CONTENT_LENGTH, "" + buffer.readableBytes()); } - } else if (!request.response().headers().contains(HttpHeaderNames.CONTENT_LENGTH)) { + } else if (!contentLengthSet()) { request.response().setChunked(true); } } } + private boolean contentLengthSet() { + if (request.response().headers().contains(HttpHeaderNames.CONTENT_LENGTH)) { + return true; + } + LazyResponse lazyResponse = context.getResponse(); + if (!lazyResponse.isCreated()) { + return false; + } + MultivaluedMap responseHeaders = lazyResponse.get().getHeaders(); + return (responseHeaders != null) && responseHeaders.containsKey(HttpHeaders.CONTENT_LENGTH); + } + /** * {@inheritDoc} */ diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/response/ContentLengthTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/response/ContentLengthTest.java new file mode 100644 index 0000000000000..2faf6d56d628e --- /dev/null +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/response/ContentLengthTest.java @@ -0,0 +1,56 @@ +package org.jboss.resteasy.reactive.server.vertx.test.response; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.core.IsNull.nullValue; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.UUID; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class ContentLengthTest { + + private static final int NUMBER_OF_COPIES = 500; + + @RegisterExtension + static ResteasyReactiveUnitTest runner = new ResteasyReactiveUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(FileResource.class)); + + @Test + void testResponseHeaders() { + when() + .get("/file") + .then() + .statusCode(200) + .header(HttpHeaders.CONTENT_LENGTH, + greaterThan( + "" + (NUMBER_OF_COPIES * UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8).length))) + .header("transfer-encoding", nullValue()); + } + + @Path("/file") + public static class FileResource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public Response hello() { + byte[] bytes = String.join(";", Collections.nCopies(NUMBER_OF_COPIES, UUID.randomUUID().toString())) + .getBytes(StandardCharsets.UTF_8); + return Response.ok(new ByteArrayInputStream(bytes), "text/plain") + .header(HttpHeaders.CONTENT_LENGTH, bytes.length) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename = " + "uuid.txt") + .build(); + } + } +} From 6e86f1cc66747ccfba99ce37a8f376c2ee4c1786 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 30 Jun 2022 14:12:45 +0300 Subject: [PATCH 16/26] Ensure that getting server name in opentelemetry won't throw a NPE See https://github.com/quarkusio/quarkus/issues/25708#issuecomment-1170161764 for more details (cherry picked from commit e31677dc458d2bfc1e9f19ab1cb5318697a79c4e) --- .../runtime/tracing/vertx/HttpInstrumenterVertxTracer.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java index 4ef7f25217086..949af88149a2c 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/HttpInstrumenterVertxTracer.java @@ -201,7 +201,11 @@ public String scheme(final HttpRequest request) { @Override public String serverName(final HttpRequest request) { - return request.remoteAddress().hostName(); + SocketAddress remoteAddress = request.remoteAddress(); + if (remoteAddress != null) { + return remoteAddress.hostName(); + } + return null; } @Override From 6a29397ff2f5f89cf4a3175b6bd73c48505c16f6 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Thu, 30 Jun 2022 09:56:41 +0200 Subject: [PATCH 17/26] Properly initialize elements from the datasource configs When using named datasources, we might create these objects directly instead of relying on the config framework. In this case, we need the objects to be fully initialized. Fix #26455 (cherry picked from commit 7891b61b18e12d5a5ffaa246b87fcff81927f817) --- .../quarkus/agroal/runtime/DataSourceJdbcRuntimeConfig.java | 5 +++-- .../datasource/runtime/DataSourceReactiveRuntimeConfig.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourceJdbcRuntimeConfig.java b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourceJdbcRuntimeConfig.java index 15df67a73d5fc..0decc4e6d3856 100644 --- a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourceJdbcRuntimeConfig.java +++ b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourceJdbcRuntimeConfig.java @@ -1,6 +1,7 @@ package io.quarkus.agroal.runtime; import java.time.Duration; +import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.OptionalInt; @@ -130,12 +131,12 @@ public class DataSourceJdbcRuntimeConfig { * validation. Setting this setting to STRICT may lead to failures in those cases. */ @ConfigItem - public Optional transactionRequirement; + public Optional transactionRequirement = Optional.empty(); /** * Other unspecified properties to be passed to the JDBC driver when creating new connections. */ @ConfigItem - public Map additionalJdbcProperties; + public Map additionalJdbcProperties = Collections.emptyMap(); } diff --git a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java index 831a2bf172e2e..5a8b64802039a 100644 --- a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java +++ b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java @@ -1,6 +1,7 @@ package io.quarkus.reactive.datasource.runtime; import java.time.Duration; +import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.OptionalInt; @@ -145,12 +146,12 @@ public class DataSourceReactiveRuntimeConfig { * Set the pool name, used when the pool is shared among datasources, otherwise ignored. */ @ConfigItem - public Optional name; + public Optional name = Optional.empty(); /** * Other unspecified properties to be passed through the Reactive SQL Client directly to the database when new connections * are initiated. */ @ConfigItem - public Map additionalProperties; + public Map additionalProperties = Collections.emptyMap(); } From a5614bee1ad1df96b7505642b9a6ec494da3628e Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Fri, 1 Jul 2022 00:43:27 +0200 Subject: [PATCH 18/26] Fix spring-data-jpa field lookup in parameterized superclasses and for typed fields (cherry picked from commit 1a32fc763c86e69b088896fa9ae230472cdf3189) --- .../data/deployment/MethodNameParser.java | 77 ++++++++++++++++--- .../spring/data/jpa/AbstractPhoneEntity.java | 12 +++ .../data/jpa/AbstractTypedIdEntity.java | 22 ++++++ .../quarkus/it/spring/data/jpa/PhoneCall.java | 17 ++-- .../it/spring/data/jpa/PhoneCallId.java | 14 ++++ .../spring/data/jpa/PhoneCallRepository.java | 4 +- .../it/spring/data/jpa/PhoneCallResource.java | 4 +- .../it/spring/data/jpa/PhoneNumberId.java | 7 +- 8 files changed, 126 insertions(+), 31 deletions(-) create mode 100644 integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/AbstractPhoneEntity.java create mode 100644 integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/AbstractTypedIdEntity.java create mode 100644 integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallId.java diff --git a/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/MethodNameParser.java b/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/MethodNameParser.java index 0be30eee83b5e..c5886556091dd 100644 --- a/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/MethodNameParser.java +++ b/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/MethodNameParser.java @@ -15,10 +15,10 @@ import org.jboss.jandex.FieldInfo; import org.jboss.jandex.IndexView; import org.jboss.jandex.MethodInfo; -import org.jboss.jandex.ParameterizedType; import org.jboss.jandex.Type; -import org.jboss.jandex.Type.Kind; +import org.jboss.jandex.TypeVariable; +import io.quarkus.deployment.util.JandexUtil; import io.quarkus.panache.common.Sort; public class MethodNameParser { @@ -351,6 +351,7 @@ private FieldInfo resolveNestedField(String repositoryMethodDescription, String ClassInfo parentClassInfo = this.entityClass; FieldInfo fieldInfo = null; + MutableReference> parentSuperClassInfos = new MutableReference<>(); int fieldStartIndex = 0; while (fieldStartIndex < fieldPathExpression.length()) { if (fieldPathExpression.charAt(fieldStartIndex) == '_') { @@ -359,7 +360,6 @@ private FieldInfo resolveNestedField(String repositoryMethodDescription, String throw new UnableToParseMethodException(fieldNotResolvableMessage + offendingMethodMessage); } } - MutableReference> parentSuperClassInfos = new MutableReference<>(); // the underscore character is treated as reserved character to manually define traversal points. int firstSeparator = fieldPathExpression.indexOf('_', fieldStartIndex); int fieldEndIndex = firstSeparator == -1 ? fieldPathExpression.length() : firstSeparator; @@ -385,17 +385,28 @@ private FieldInfo resolveNestedField(String repositoryMethodDescription, String } fieldPathBuilder.append(fieldInfo.name()); if (!isHibernateProvidedBasicType(fieldInfo.type().name())) { - parentClassInfo = indexView.getClassByName(fieldInfo.type().name()); + DotName parentClassName; + boolean typed = false; + if (fieldInfo.type().kind() == Type.Kind.TYPE_VARIABLE) { + typed = true; + parentClassName = getParentNameFromTypedFieldViaHierarchy(fieldInfo, mappedSuperClassInfos); + } else { + parentClassName = fieldInfo.type().name(); + } + parentClassInfo = indexView.getClassByName(parentClassName); + parentSuperClassInfos.set(null); if (parentClassInfo == null) { throw new IllegalStateException( "Entity class " + fieldInfo.type().name() + " referenced by " + this.entityClass + "." + fieldPathBuilder - + " was not part of the Quarkus index. " + offendingMethodMessage); + + " was not part of the Quarkus index" + + (typed ? " or typed field could not be resolved properly. " : ". ") + + offendingMethodMessage); } + } fieldStartIndex = fieldEndIndex; } - return fieldInfo; } @@ -543,12 +554,7 @@ private List getSuperClassInfos(IndexView indexView, ClassInfo entity mappedSuperClassInfoElements.add(superClass); } - if (superClassType.kind() == Kind.CLASS) { - superClassType = superClass.superClassType(); - } else if (superClassType.kind() == Kind.PARAMETERIZED_TYPE) { - ParameterizedType parameterizedType = superClassType.asParameterizedType(); - superClassType = parameterizedType.owner(); - } + superClassType = superClass.superClassType(); } return mappedSuperClassInfoElements; } @@ -557,6 +563,53 @@ private boolean isHibernateProvidedBasicType(DotName dotName) { return DotNames.HIBERNATE_PROVIDED_BASIC_TYPES.contains(dotName); } + // Tries to get the parent (name) of a field that is typed, e.g.: + // class Foo { @EmbeddedId ID id; } + // class Bar extends FOO { } + // class Baz extends Bar { } + // @Embeddable class BazId extends SomeMoreSpecificBaseId { @Column String a; @Column String b; } + // + // Without this method, type of Foo.id would be Serializable and therefore Foo.id.a (or b) would not be found. + // + // Note: This method is lenient in that it doesn't throw exceptions aggressively when an assumption is not met. + private DotName getParentNameFromTypedFieldViaHierarchy(FieldInfo fieldInfo, List parentSuperClassInfos) { + // find in the hierarchy the position of the class the fieldInfo belongs to + int superClassIndex = parentSuperClassInfos.indexOf(fieldInfo.declaringClass()); + if (superClassIndex == -1) { + // field seems to belong to concrete entity class; no use narrowing it down via class hierarchy + return fieldInfo.type().name(); + } + TypeVariable typeVariable = fieldInfo.type().asTypeVariable(); + // entire hierarchy as list: entityClass, superclass of entityClass, superclass of the latter, ... + List classInfos = new ArrayList<>(); + classInfos.add(entityClass); + classInfos.addAll(parentSuperClassInfos.subList(0, superClassIndex + 1)); + // go down the hierarchy until ideally a concrete class is found that specifies the actual type of the field + for (int i = classInfos.size() - 1; i > 0; i--) { + ClassInfo currentClassInfo = classInfos.get(i); + ClassInfo childClassInfo = classInfos.get(i - 1); + int typeParameterIndex = currentClassInfo.typeParameters().indexOf(typeVariable); + if (typeParameterIndex >= 0) { + List resolveTypeParameters = JandexUtil.resolveTypeParameters(childClassInfo.name(), + currentClassInfo.name(), indexView); + if (resolveTypeParameters.size() <= typeParameterIndex) { + // edge case; subclass without or with incomplete parameterization? raw types? + break; + } + Type type = resolveTypeParameters.get(typeParameterIndex); + if (type.kind() == Type.Kind.TYPE_VARIABLE) { + // go on with the type variable from the child class (which is potentially more specific that the previous one) + typeVariable = type.asTypeVariable(); + } else if (type.kind() == Type.Kind.CLASS) { + // ideal outcome: concrete class, doesn't get more specific than this + return type.name(); + } + } + } + // return the most specific type variable we were able to get + return typeVariable.name(); + } + private static class MutableReference { private T reference; diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/AbstractPhoneEntity.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/AbstractPhoneEntity.java new file mode 100644 index 0000000000000..e67bd3dd0a0cf --- /dev/null +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/AbstractPhoneEntity.java @@ -0,0 +1,12 @@ +package io.quarkus.it.spring.data.jpa; + +import javax.persistence.MappedSuperclass; + +// demonstrates that @MappedSuperclass detection works for more than one level and for parameterized types +@MappedSuperclass +public abstract class AbstractPhoneEntity extends AbstractTypedIdEntity { + + protected AbstractPhoneEntity(ID id) { + super(id); + } +} diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/AbstractTypedIdEntity.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/AbstractTypedIdEntity.java new file mode 100644 index 0000000000000..d105ceea4978a --- /dev/null +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/AbstractTypedIdEntity.java @@ -0,0 +1,22 @@ +package io.quarkus.it.spring.data.jpa; + +import java.io.Serializable; + +import javax.persistence.EmbeddedId; +import javax.persistence.MappedSuperclass; + +// example "base entity" using strongly typed ids (instead of just long) +@MappedSuperclass +public abstract class AbstractTypedIdEntity { + + @EmbeddedId + private ID id; + + protected AbstractTypedIdEntity(ID id) { + this.id = id; + } + + public ID getId() { + return id; + } +} diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCall.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCall.java index ae6d95ab7c73d..a3c5deef117b5 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCall.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCall.java @@ -2,30 +2,23 @@ import javax.persistence.Column; import javax.persistence.Embeddable; -import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.Table; @Entity @Table(name = "phone_call") -public class PhoneCall { - - @EmbeddedId - private PhoneNumberId id; +public class PhoneCall extends AbstractPhoneEntity { private int duration; private CallAgent callAgent; - PhoneCall() { - } - - public PhoneCall(PhoneNumberId id) { - this.id = id; + PhoneCall() { // only for hibernate + super(null); } - public PhoneNumberId getId() { - return id; + public PhoneCall(PhoneCallId id) { + super(id); } public int getDuration() { diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallId.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallId.java new file mode 100644 index 0000000000000..5322c29edb989 --- /dev/null +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallId.java @@ -0,0 +1,14 @@ +package io.quarkus.it.spring.data.jpa; + +import javax.persistence.Embeddable; + +@Embeddable +public class PhoneCallId extends PhoneNumberId { + + PhoneCallId() { + } + + public PhoneCallId(String areaCode, String number) { + super(areaCode, number); + } +} diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallRepository.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallRepository.java index 51fbb08c61763..24424e88d9cdb 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallRepository.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallRepository.java @@ -7,12 +7,12 @@ import io.quarkus.it.spring.data.jpa.PhoneCall.CallAgent; -public interface PhoneCallRepository extends JpaRepository { +public interface PhoneCallRepository extends JpaRepository { PhoneCall findByIdAreaCode(String areaCode); @Query("select p.id from PhoneCall p") - Set findAllIds(); + Set findAllIds(); @Query("select p.callAgent from PhoneCall p") Set findAllCallAgents(); diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallResource.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallResource.java index 5fba7b4150df3..0a27f60c2e8c2 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallResource.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneCallResource.java @@ -20,7 +20,7 @@ public class PhoneCallResource { @GET @Produces("application/json") public PhoneCall phoneCallById(@PathParam("areaCode") String areaCode, @PathParam("number") String number) { - return repository.findById(new PhoneNumberId(areaCode, number)).orElse(null); + return repository.findById(new PhoneCallId(areaCode, number)).orElse(null); } @Path("{areaCode}") @@ -33,7 +33,7 @@ public PhoneCall phoneCallByAreaCode(@PathParam("areaCode") String areaCode) { @Path("ids") @GET @Produces("application/json") - public Set allIds() { + public Set allIds() { return repository.findAllIds(); } diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneNumberId.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneNumberId.java index 901f4395a344b..c87dcae5aeed4 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneNumberId.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/PhoneNumberId.java @@ -4,10 +4,11 @@ import java.util.Objects; import javax.persistence.Column; -import javax.persistence.Embeddable; +import javax.persistence.MappedSuperclass; -@Embeddable -public class PhoneNumberId implements Serializable { +// this is a bit artificial, but next to PhoneCallId there could be e.g. a PhoneBookEntryId subclass +@MappedSuperclass +public abstract class PhoneNumberId implements Serializable { @Column(name = "area_code") private String areaCode; From 461a94d15a2d1e429d1e535d95332a4e706d5f9a Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Thu, 30 Jun 2022 17:59:30 +0100 Subject: [PATCH 19/26] Upgrade Hibernate Reactive to 1.1.7.Final (cherry picked from commit 9e153c851efefb5e2ba7dd5bc1f2e9e462cd3d4c) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 2d8bd2e27f695..6f4fe9f15ff20 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -90,7 +90,7 @@ 1.5.1 5.6.9.Final 1.12.9 - 1.1.6.Final + 1.1.7.Final 6.2.3.Final 6.1.5.Final 5.12.6.Final From 0b268bc9f9dec4c24780545b1bb611d9eff10dbb Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 1 Jul 2022 07:32:24 +0300 Subject: [PATCH 20/26] Use proper header name Follows up on #26467 which seems to have introduced flakyness (cherry picked from commit a6c4511391a187a583f139e23c663c2b419cfb36) --- .../reactive/server/vertx/ResteasyReactiveOutputStream.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java index d5cf25c8240fd..824560d0f5d41 100644 --- a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java +++ b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java @@ -6,12 +6,12 @@ import io.vertx.core.Context; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpServerRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MultivaluedMap; import org.jboss.logging.Logger; import org.jboss.resteasy.reactive.server.core.LazyResponse; From fdef99b88f900522a5ef3ba9bd2c0150139d83b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jun 2022 21:44:38 +0000 Subject: [PATCH 21/26] Bump mariadb-java-client from 3.0.5 to 3.0.6 Bumps [mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 3.0.5 to 3.0.6. - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/3.0.5...3.0.6) --- updated-dependencies: - dependency-name: org.mariadb.jdbc:mariadb-java-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] (cherry picked from commit a7557f1a5ed1ec78897a50fe57bca2dbebb58b82) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 6f4fe9f15ff20..d634181d9406c 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -117,7 +117,7 @@ 2.3.2 2.1.210 42.3.6 - 3.0.5 + 3.0.6 8.0.29 7.2.2.jre8 1.6.7 From 3a621edf1468a305fe04c07299e89fcfe95ed1c6 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Thu, 30 Jun 2022 17:50:16 +0200 Subject: [PATCH 22/26] Register build-time configured fault tolerance exceptions for reflection (cherry picked from commit b44145477270276987d89930e1a4c0aa6fc6b37f) --- .../SmallRyeFaultToleranceProcessor.java | 29 +++++++++++++++++++ .../FaultToleranceTestResource.java | 8 +++++ .../faulttolerance/MyFaultToleranceError.java | 6 ++++ .../io/quarkus/it/faulttolerance/Service.java | 9 ++++++ .../src/main/resources/application.properties | 2 ++ .../it/main/FaultToleranceTestCase.java | 5 ++++ 6 files changed, 59 insertions(+) create mode 100644 integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/MyFaultToleranceError.java diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java index 1a25965157bce..c6b20949ef6ba 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java @@ -251,8 +251,21 @@ void validateFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, BeanArchiveIndexBuildItem beanArchiveIndexBuildItem, AnnotationProxyBuildItem annotationProxy, BuildProducer generatedClasses, + BuildProducer reflectiveClass, BuildProducer errors) { + Config config = ConfigProvider.getConfig(); + + Set exceptionConfigs = Set.of("CircuitBreaker/failOn", "CircuitBreaker/skipOn", + "Fallback/applyOn", "Fallback/skipOn", "Retry/retryOn", "Retry/abortOn"); + + for (String exceptionConfig : exceptionConfigs) { + Optional exceptionNames = config.getOptionalValue(exceptionConfig, String[].class); + if (exceptionNames.isPresent()) { + reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, exceptionNames.get())); + } + } + AnnotationStore annotationStore = validationPhase.getContext().get(BuildExtension.Key.ANNOTATION_STORE); IndexView index = beanArchiveIndexBuildItem.getIndex(); // only generating annotation literal classes for MicroProfile/SmallRye Fault Tolerance annotations, @@ -271,6 +284,14 @@ void validateFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, continue; } + for (String exceptionConfig : exceptionConfigs) { + Optional exceptionNames = config.getOptionalValue(beanClass.name().toString() + + "/" + exceptionConfig, String[].class); + if (exceptionNames.isPresent()) { + reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, exceptionNames.get())); + } + } + if (scaner.hasFTAnnotations(beanClass)) { scaner.forEachMethod(beanClass, method -> { FaultToleranceMethod ftMethod = scaner.createFaultToleranceMethod(beanClass, method); @@ -281,6 +302,14 @@ void validateFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, exceptions.add( new DefinitionException("Both @Blocking and @NonBlocking present on '" + method + "'")); } + + for (String exceptionConfig : exceptionConfigs) { + Optional exceptionNames = config.getOptionalValue(beanClass.name().toString() + + "/" + method.name() + "/" + exceptionConfig, String[].class); + if (exceptionNames.isPresent()) { + reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, exceptionNames.get())); + } + } } }); diff --git a/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/FaultToleranceTestResource.java b/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/FaultToleranceTestResource.java index 08a71fbf6afad..a7dfa837d8505 100644 --- a/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/FaultToleranceTestResource.java +++ b/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/FaultToleranceTestResource.java @@ -19,4 +19,12 @@ public String getName() { return counter + ":" + name; } + @GET + @Path("/retried") + public String retried() { + AtomicInteger counter = new AtomicInteger(); + String name = service.retriedMethod(counter); + return counter + ":" + name; + } + } diff --git a/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/MyFaultToleranceError.java b/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/MyFaultToleranceError.java new file mode 100644 index 0000000000000..a35f4ff849a9d --- /dev/null +++ b/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/MyFaultToleranceError.java @@ -0,0 +1,6 @@ +package io.quarkus.it.faulttolerance; + +public class MyFaultToleranceError extends Error { + public MyFaultToleranceError() { + } +} diff --git a/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/Service.java b/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/Service.java index 2df1cd2e63433..a9718e90a9727 100644 --- a/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/Service.java +++ b/integration-tests/main/src/main/java/io/quarkus/it/faulttolerance/Service.java @@ -5,6 +5,8 @@ import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; +import org.eclipse.microprofile.faulttolerance.Retry; + import io.smallrye.faulttolerance.api.ApplyFaultTolerance; @ApplicationScoped @@ -27,4 +29,11 @@ public String getName(AtomicInteger counter) { throw new IllegalStateException("Counter=" + counter.get()); } + @Retry // set of `retryOn` exceptions is configured in application.properties + public String retriedMethod(AtomicInteger counter) { + if (counter.incrementAndGet() >= THRESHOLD) { + return name; + } + throw new MyFaultToleranceError(); + } } diff --git a/integration-tests/main/src/main/resources/application.properties b/integration-tests/main/src/main/resources/application.properties index a6e7df99951e9..32124b591eb6b 100644 --- a/integration-tests/main/src/main/resources/application.properties +++ b/integration-tests/main/src/main/resources/application.properties @@ -7,6 +7,8 @@ restClientConfigKey/mp-rest/url=${test.url} restClientBaseUriConfigKey/mp-rest/url=${test.url} loopback/mp-rest/url=${test.url}/loopback +io.quarkus.it.faulttolerance.Service/retriedMethod/Retry/retryOn=io.quarkus.it.faulttolerance.MyFaultToleranceError + org.eclipse.microprofile.rest.client.propagateHeaders=header-name # Disabled by default as it establishes external connections. # Uncomment when you want to test SSL support. diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/FaultToleranceTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/FaultToleranceTestCase.java index 3851afe22fa46..4e59aa209f987 100644 --- a/integration-tests/main/src/test/java/io/quarkus/it/main/FaultToleranceTestCase.java +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/FaultToleranceTestCase.java @@ -25,5 +25,10 @@ public void testRetry() throws Exception { .given().baseUri(uri.toString()) .when().get() .then().body(is("2:Lucie")); + + RestAssured + .given().baseUri(uri.toString() + "/retried") + .when().get() + .then().body(is("2:Lucie")); } } From 1b7a843d270ee0f297158e580dea3165af5f3c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Fri, 1 Jul 2022 16:03:47 +0200 Subject: [PATCH 23/26] Stork guide minor improvements and cross linking (cherry picked from commit 0edabca1810674623e66df0ef87da3d88903e4e9) --- docs/src/main/asciidoc/stork-kubernetes.adoc | 13 +++---------- docs/src/main/asciidoc/stork-reference.adoc | 5 +++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/docs/src/main/asciidoc/stork-kubernetes.adoc b/docs/src/main/asciidoc/stork-kubernetes.adoc index da075a7d007db..77b7dc6ae309d 100644 --- a/docs/src/main/asciidoc/stork-kubernetes.adoc +++ b/docs/src/main/asciidoc/stork-kubernetes.adoc @@ -3,21 +3,14 @@ This guide is maintained in the main Quarkus repository and pull requests should be submitted there: https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// -= Getting Started with SmallRye Stork += Using Stork with Kubernetes :extension-status: preview include::./attributes.adoc[] -The essence of distributed systems resides in the interaction between services. -In modern architecture, you often have multiple instances of your service to share the load or improve the resilience by redundancy. -But how do you select the best instance of your service? -That's where https://smallrye.io/smallrye-stork[SmallRye Stork] helps. -Stork is going to choose the most appropriate instance. -It offers: +This guide explains how to use Stork with Kubernetes for service discovery and load balancing. -* Extensible service discovery mechanisms -* Built-in support for Consul and Kubernetes -* Customizable client load-balancing strategies +If you are new to Stork, please read the xref:stork.adoc[Stork Getting Started Guide]. include::{includes}/extension-status.adoc[] diff --git a/docs/src/main/asciidoc/stork-reference.adoc b/docs/src/main/asciidoc/stork-reference.adoc index c4086c3fa9306..07f8f45f461a5 100644 --- a/docs/src/main/asciidoc/stork-reference.adoc +++ b/docs/src/main/asciidoc/stork-reference.adoc @@ -4,12 +4,15 @@ and pull requests should be submitted there: https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// = Stork Reference Guide +:extension-status: preview include::./attributes.adoc[] This guide is the companion from the xref:stork.adoc[Stork Getting Started Guide]. It explains the configuration and usage of SmallRye Stork integration in Quarkus. +include::{includes}/extension-status.adoc[] + == Supported clients The current integration of Stork supports: @@ -56,6 +59,8 @@ quarkus.stork.my-service.service-discovery.k8s-namespace=my-namespace Stork looks for the Kubernetes Service with the given name (`my-service` in the previous example) in the specified namespace. Instead of using the Kubernetes Service IP directly and let Kubernetes handle the selection and balancing, Stork inspects the service and retrieves the list of pods providing the service. Then, it can select the instance. +For a full example of using Stork with Kubernetes, please read the xref:stork-kubernetes.adoc[Using Stork with Kubernetes guide]. + == Implementing a custom service discovery Stork is extensible, and you can implement your own service discovery mechanism. From 1e237bd1a5f36d374fb40788982b3949806a992a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Jun 2022 12:55:23 +0000 Subject: [PATCH 24/26] Bump proto-google-common-protos from 2.0.1 to 2.9.1 Bumps [proto-google-common-protos](https://github.com/googleapis/java-iam) from 2.0.1 to 2.9.1. - [Release notes](https://github.com/googleapis/java-iam/releases) - [Changelog](https://github.com/googleapis/java-iam/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/java-iam/commits) --- updated-dependencies: - dependency-name: com.google.api.grpc:proto-google-common-protos dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] (cherry picked from commit 6fd7255fb7e65d782cc8bb3e8f39ef3babce5547) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4e48369c3b9e6..4e07464a91eca 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ 1.2.1 3.19.3 ${protoc.version} - 2.0.1 + 2.9.1 From 6f424e580d919c71a7b49745edc80bdccfddde26 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 1 Jul 2022 18:56:56 +0200 Subject: [PATCH 25/26] Upgrade JReleaser to 1.1.0 (cherry picked from commit b254cc27c59cd3e2da4ed906f74395e91e81e06c) --- devtools/cli/distribution/release-cli.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/cli/distribution/release-cli.sh b/devtools/cli/distribution/release-cli.sh index 786b207f485b2..1867efa18d730 100755 --- a/devtools/cli/distribution/release-cli.sh +++ b/devtools/cli/distribution/release-cli.sh @@ -45,7 +45,7 @@ export JRELEASER_PROJECT_VERSION=${VERSION} export JRELEASER_BRANCH=${BRANCH} export JRELEASER_CHOCOLATEY_GITHUB_BRANCH=${BRANCH} -jbang org.jreleaser:jreleaser:1.0.0 full-release \ +jbang org.jreleaser:jreleaser:1.1.0 full-release \ --git-root-search \ -od target From 4853f19e266a259b242e44cc3e183266bb938f86 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Thu, 23 Jun 2022 22:30:07 +0100 Subject: [PATCH 26/26] Always create a duplicated context in OpenTelemetry when executing client requests (cherry picked from commit 6e095f49ee7660de87ffc9b7c6e64429027df7ae) --- .../VertxClientOpenTelemetryTest.java | 29 +++++++++++++++++++ .../restclient/OpenTelemetryClientFilter.java | 8 +++-- .../vertx/InstrumenterVertxTracer.java | 2 +- .../client/impl/ClientRequestContextImpl.java | 5 ++-- .../reactive/ReactiveResource.java | 12 ++++++++ .../reactive/ReactiveRestClient.java | 20 +++++++++++++ .../resources/application.properties | 0 .../OpenTelemetryReactiveClientTest.java | 13 --------- .../reactive/OpenTelemetryReactiveIT.java | 7 +++++ .../reactive/OpenTelemetryReactiveTest.java | 18 ++++++++++++ 10 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveRestClient.java rename integration-tests/opentelemetry-reactive/src/{test => main}/resources/application.properties (100%) create mode 100644 integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveIT.java diff --git a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxClientOpenTelemetryTest.java b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxClientOpenTelemetryTest.java index 1760daff376a2..e291fdbc71482 100644 --- a/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxClientOpenTelemetryTest.java +++ b/extensions/opentelemetry/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/VertxClientOpenTelemetryTest.java @@ -9,6 +9,7 @@ import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_TARGET; import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_URL; import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.stream.Collectors.toSet; import static org.junit.jupiter.api.Assertions.assertEquals; import java.net.URI; @@ -27,6 +28,8 @@ import io.quarkus.runtime.StartupEvent; import io.quarkus.test.QuarkusUnitTest; import io.quarkus.test.common.http.TestHTTPResource; +import io.vertx.core.CompositeFuture; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.Router; @@ -114,14 +117,40 @@ void path() throws Exception { assertEquals(server.getParentSpanId(), client.getSpanId()); } + @Test + void multiple() throws Exception { + HttpResponse response = WebClient.create(vertx) + .get(uri.getPort(), uri.getHost(), "/multiple") + .putHeader("host", uri.getHost()) + .putHeader("port", uri.getPort() + "") + .send() + .toCompletionStage().toCompletableFuture() + .get(); + + assertEquals(HTTP_OK, response.statusCode()); + + List spans = spanExporter.getFinishedSpanItems(6); + assertEquals(1, spans.stream().map(SpanData::getTraceId).collect(toSet()).size()); + } + @ApplicationScoped public static class HelloRouter { @Inject Router router; + @Inject + Vertx vertx; public void register(@Observes StartupEvent ev) { router.get("/hello").handler(rc -> rc.response().end("hello")); router.get("/hello/:name").handler(rc -> rc.response().end("hello " + rc.pathParam("name"))); + router.get("/multiple").handler(rc -> { + String host = rc.request().getHeader("host"); + int port = Integer.parseInt(rc.request().getHeader("port")); + WebClient webClient = WebClient.create(vertx); + Future> one = webClient.get(port, host, "/hello/naruto").send(); + Future> two = webClient.get(port, host, "/hello/goku").send(); + CompositeFuture.join(one, two).onComplete(event -> rc.response().end()); + }); } } } diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/restclient/OpenTelemetryClientFilter.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/restclient/OpenTelemetryClientFilter.java index e6e07d13d028d..0289b381e5e29 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/restclient/OpenTelemetryClientFilter.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/restclient/OpenTelemetryClientFilter.java @@ -72,10 +72,14 @@ public OpenTelemetryClientFilter(final OpenTelemetry openTelemetry) { @Override public void filter(final ClientRequestContext request) { - Context parentContext = Context.current(); + io.vertx.core.Context vertxContext = getVertxContext(request); + io.opentelemetry.context.Context parentContext = QuarkusContextStorage.getContext(vertxContext); + if (parentContext == null) { + parentContext = io.opentelemetry.context.Context.current(); + } if (instrumenter.shouldStart(parentContext, request)) { Context spanContext = instrumenter.start(parentContext, request); - Scope scope = QuarkusContextStorage.INSTANCE.attach(getVertxContext(request), spanContext); + Scope scope = QuarkusContextStorage.INSTANCE.attach(vertxContext, spanContext); request.setProperty(REST_CLIENT_OTEL_SPAN_CLIENT_CONTEXT, spanContext); request.setProperty(REST_CLIENT_OTEL_SPAN_CLIENT_PARENT_CONTEXT, parentContext); request.setProperty(REST_CLIENT_OTEL_SPAN_CLIENT_SCOPE, scope); diff --git a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/InstrumenterVertxTracer.java b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/InstrumenterVertxTracer.java index 294c020516213..272c1a83bb9fd 100644 --- a/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/InstrumenterVertxTracer.java +++ b/extensions/opentelemetry/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/vertx/InstrumenterVertxTracer.java @@ -92,7 +92,7 @@ default SpanOperation sendRequest( if (instrumenter.shouldStart(parentContext, (REQ) request)) { io.opentelemetry.context.Context spanContext = instrumenter.start(parentContext, writableHeaders((REQ) request, headers)); - Context duplicatedContext = VertxContext.getOrCreateDuplicatedContext(context); + Context duplicatedContext = VertxContext.createNewDuplicatedContext(context); setContextSafe(duplicatedContext, true); Scope scope = QuarkusContextStorage.INSTANCE.attach(duplicatedContext, spanContext); return spanOperation(duplicatedContext, (REQ) request, toMultiMap(headers), spanContext, scope); diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientRequestContextImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientRequestContextImpl.java index faff2cfa99bf1..d31f5eba7ee00 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientRequestContextImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientRequestContextImpl.java @@ -54,9 +54,10 @@ public ClientRequestContextImpl(RestClientRequestContext restClientRequestContex this.configuration = configuration; this.headersMap = new ClientRequestHeadersMap(); //restClientRequestContext.requestHeaders.getHeaders() - // Capture or create a duplicated context, and store it. + // Always create a duplicated context because each REST Client invocation must have its own context + // A separate context allows integrations like OTel to create a separate Span for each invocation (expected) Context current = client.vertx.getOrCreateContext(); - this.context = VertxContext.getOrCreateDuplicatedContext(current); + this.context = VertxContext.createNewDuplicatedContext(current); restClientRequestContext.properties.put(VERTX_CONTEXT_PROPERTY, context); } diff --git a/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveResource.java b/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveResource.java index 31b78a13405f2..a0f6bc2099bb6 100644 --- a/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveResource.java +++ b/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveResource.java @@ -8,6 +8,8 @@ import javax.ws.rs.Path; import javax.ws.rs.QueryParam; +import org.eclipse.microprofile.rest.client.inject.RestClient; + import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.smallrye.mutiny.Uni; @@ -16,6 +18,9 @@ public class ReactiveResource { @Inject Tracer tracer; + @Inject + @RestClient + ReactiveRestClient client; @GET public Uni helloGet(@QueryParam("name") String name) { @@ -24,6 +29,13 @@ public Uni helloGet(@QueryParam("name") String name) { .eventually((Runnable) span::end); } + @GET + @Path("/multiple") + public Uni helloMultiple() { + return Uni.combine().all().unis(client.helloGet("Naruto"), client.helloGet("Goku")) + .combinedWith((s, s2) -> s + " and " + s2); + } + @POST public Uni helloPost(String body) { Span span = tracer.spanBuilder("helloPost").startSpan(); diff --git a/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveRestClient.java b/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveRestClient.java new file mode 100644 index 0000000000000..ac0d8deb06b43 --- /dev/null +++ b/integration-tests/opentelemetry-reactive/src/main/java/io/quarkus/it/opentelemetry/reactive/ReactiveRestClient.java @@ -0,0 +1,20 @@ +package io.quarkus.it.opentelemetry.reactive; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +import io.smallrye.mutiny.Uni; + +@RegisterRestClient(configKey = "client") +@Path("/reactive") +interface ReactiveRestClient { + @GET + Uni helloGet(@QueryParam("name") String name); + + @POST + Uni helloPost(String body); +} diff --git a/integration-tests/opentelemetry-reactive/src/test/resources/application.properties b/integration-tests/opentelemetry-reactive/src/main/resources/application.properties similarity index 100% rename from integration-tests/opentelemetry-reactive/src/test/resources/application.properties rename to integration-tests/opentelemetry-reactive/src/main/resources/application.properties diff --git a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveClientTest.java b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveClientTest.java index 6c68ee2098f2f..f130d7f116b1c 100644 --- a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveClientTest.java +++ b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveClientTest.java @@ -17,10 +17,7 @@ import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; -import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -111,16 +108,6 @@ void post() { assertEquals(HttpMethod.POST.name(), ((Map) client.get("attributes")).get(HTTP_METHOD.getKey())); } - @RegisterRestClient(configKey = "client") - @Path("/reactive") - interface ReactiveRestClient { - @GET - Uni helloGet(@QueryParam("name") String name); - - @POST - Uni helloPost(String body); - } - private static List> getSpans() { return when().get("/export").body().as(new TypeRef<>() { }); diff --git a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveIT.java b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveIT.java new file mode 100644 index 0000000000000..2103579c81eee --- /dev/null +++ b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveIT.java @@ -0,0 +1,7 @@ +package io.quarkus.it.opentelemetry.reactive; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class OpenTelemetryReactiveIT extends OpenTelemetryReactiveTest { +} diff --git a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java index 275288a35b1b6..277ae2fcb5101 100644 --- a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java +++ b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java @@ -3,6 +3,7 @@ import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.when; import static java.net.HttpURLConnection.HTTP_OK; +import static java.util.stream.Collectors.toSet; import static org.awaitility.Awaitility.await; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -59,6 +60,23 @@ void post() { assertEquals(spans.get(0).get("traceId"), spans.get(1).get("traceId")); } + @Test + void multiple() { + given() + .contentType("application/json") + .when() + .get("/reactive/multiple") + .then() + .statusCode(200) + .body(equalTo("Hello Naruto and Hello Goku")); + + await().atMost(5, TimeUnit.SECONDS).until(() -> getSpans().size() == 7); + + List> spans = getSpans(); + assertEquals(7, spans.size()); + assertEquals(1, spans.stream().map(map -> map.get("traceId")).collect(toSet()).size()); + } + private static List> getSpans() { return when().get("/export").body().as(new TypeRef<>() { });