Skip to content

Commit

Permalink
Merge branch 'main' into issue-30101
Browse files Browse the repository at this point in the history
  • Loading branch information
glefloch authored Jan 10, 2023
2 parents eace140 + 8ce4d3f commit 4c659a6
Show file tree
Hide file tree
Showing 42 changed files with 1,733 additions and 220 deletions.
97 changes: 97 additions & 0 deletions .github/workflows/ci-istio.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Quarkus CI - Istio

on:
workflow_dispatch:
schedule:
# 2am every weekday + saturday
- cron: '0 2 * * 1-6'

env:
MAVEN_ARGS: -B -e

jobs:
cache:
name: Build and save artifacts
runs-on: ubuntu-latest
if: "github.repository == 'quarkusio/quarkus' || github.event_name == 'workflow_dispatch'"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Install artifacts
run: ./mvnw ${MAVEN_ARGS} -DskipTests -DskipITs -Dinvoker.skip clean install -pl :quarkus-integration-test-istio-invoker -am
- name: Tar Maven repository
shell: bash
run: tar -I 'pigz -9' -cf maven-repo.tgz -C ~ .m2/repository
- name: Persist Maven repository
uses: actions/upload-artifact@v3
with:
name: maven-repo
path: maven-repo.tgz
retention-days: 1

kubernetes:
name: Istio + Kubernetes Integration Tests
needs: cache
runs-on: ubuntu-latest
if: "github.repository == 'quarkusio/quarkus' || github.event_name == 'workflow_dispatch'"
strategy:
fail-fast: false
matrix:
kubernetes: [v1.20.1]
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Download Maven repository
uses: actions/download-artifact@v3
with:
name: maven-repo
path: .
- name: Extract Maven repository
shell: bash
run: tar -xzf maven-repo.tgz -C ~
- name: Set up Minikube-Kubernetes
uses: manusa/[email protected]
with:
minikube version: v1.16.0
kubernetes version: ${{ matrix.kubernetes }}
github token: ${{ secrets.GITHUB_TOKEN }}
start args: '--addons=metrics-server --force'
- name: Quay login
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.QUAY_QUARKUSCI_USERNAME }}
password: ${{ secrets.QUAY_QUARKUSCI_PASSWORD }}
- name: Get kubeconfig
id: kubeconfig
run: a="$(cat ~/.kube/config)"; a="${a//'%'/'%25'}"; a="${a//$'\n'/'%0A'}"; a="${a//$'\r'/'%0D'}"; echo "::set-output name=config::$a"
- name: Install Istio
uses: huang195/[email protected]
with:
kubeconfig: "${{steps.kubeconfig.outputs.config}}"
istio version: '1.15.2'
- name: Run Istio Invoker Tests
run: |
export QUARKUS_CONTAINER_IMAGE_GROUP=quarkustesting
export QUARKUS_CONTAINER_IMAGE_TAG=${{ github.sha }}
export QUARKUS_CONTAINER_IMAGE_REGISTRY=quay.io
./mvnw ${MAVEN_ARGS} clean install -pl :quarkus-integration-test-istio-invoker -De2e-tests -Dkubernetes-e2e-tests
- name: Report status
if: "always() && github.repository == 'quarkusio/quarkus'"
shell: bash
run: |
curl -Ls https://sh.jbang.dev | bash -s - app setup
~/.jbang/bin/jbang .github/NativeBuildReport.java \
issueNumber=29536 \
runId=${{ github.run_id }} \
status=${{ job.status }} \
token=${{ secrets.GITHUB_API_TOKEN }} \
issueRepo=${{ github.repository }} \
thisRepo=${{ github.repository }}
7 changes: 6 additions & 1 deletion bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@
<docker-java.version>3.2.13</docker-java.version> <!-- must be the version Testcontainers use -->
<com.dajudge.kindcontainer>1.3.0</com.dajudge.kindcontainer>
<aesh-readline.version>2.2</aesh-readline.version>
<aesh.version>2.6</aesh.version>
<aesh.version>2.7</aesh.version>
<!-- these two artifacts needs to be compatible together -->
<strimzi-oauth.version>0.11.0</strimzi-oauth.version>
<strimzi-oauth.nimbus.version>9.27</strimzi-oauth.nimbus.version>
Expand Down Expand Up @@ -1909,6 +1909,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc-xds</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.cli.image;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
Expand Down Expand Up @@ -94,6 +95,10 @@ public void testUsage() throws Exception {
// 1 image --dry-run
result = CliDriver.execute(project, "image", "--dry-run");
assertEquals(CommandLine.ExitCode.OK, result.getExitCode(), "Expected OK return code." + result);
assertFalse(result.getStdout().contains("-Dquarkus.package.type=native"));
result = CliDriver.execute(project, "image", "--native", "--dry-run");
assertEquals(CommandLine.ExitCode.OK, result.getExitCode(), "Expected OK return code." + result);
assertTrue(result.getStdout().contains("-Dquarkus.package.type=native"));

// 2 image build --dry-run
result = CliDriver.execute(project, "image", "build", "--dry-run");
Expand Down Expand Up @@ -121,11 +126,13 @@ public void testUsage() throws Exception {
assertTrue(result.getStdout().contains("--builder=openshift"));
assertTrue(result.getStdout().contains("--init-script="));

result = CliDriver.execute(project, "image", "build", "--group=mygroup", "--name=myname", "--tag=1.0", "--dry-run");
result = CliDriver.execute(project, "image", "build", "--group=mygroup", "--name=myname", "--tag=1.0", "--native",
"--dry-run");
assertEquals(CommandLine.ExitCode.OK, result.getExitCode(), "Expected OK return code." + result);
assertTrue(result.getStdout().contains("-Dquarkus.container-image.group=mygroup"));
assertTrue(result.getStdout().contains("-Dquarkus.container-image.name=myname"));
assertTrue(result.getStdout().contains("-Dquarkus.container-image.tag=1.0"));
assertTrue(result.getStdout().contains("-Dquarkus.package.type=native"));

// 3 image push --dry-run
result = CliDriver.execute(project, "image", "push", "--dry-run");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.cli.image;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.nio.file.Path;
Expand Down Expand Up @@ -47,14 +48,21 @@ public void testUsage() throws Exception {
// 1 image --dry-run
result = CliDriver.execute(project, "image", "--dry-run");
assertEquals(CommandLine.ExitCode.OK, result.getExitCode(), "Expected OK return code." + result);
assertTrue(result.getStdout().contains("quarkus:image-build"));
assertFalse(result.getStdout().contains("-Dnative"));
result = CliDriver.execute(project, "image", "--native", "--dry-run");
assertTrue(result.getStdout().contains("-Dnative"));

// 2 image build --dry-run
result = CliDriver.execute(project, "image", "build", "--dry-run");
assertEquals(CommandLine.ExitCode.OK, result.getExitCode(), "Expected OK return code." + result);
result = CliDriver.execute(project, "image", "build", "--group=mygroup", "--name=myname", "--tag=1.0", "--dry-run");
result = CliDriver.execute(project, "image", "build", "--group=mygroup", "--name=myname", "--tag=1.0", "--native",
"--dry-run");
assertEquals(CommandLine.ExitCode.OK, result.getExitCode(), "Expected OK return code." + result);
assertTrue(result.getStdout().contains("-Dquarkus.container-image.group=mygroup"));
assertTrue(result.getStdout().contains("-Dquarkus.container-image.name=myname"));
assertTrue(result.getStdout().contains("-Dquarkus.container-image.tag=1.0"));
assertTrue(result.getStdout().contains("-Dnative"));

// 3 image push --dry-run
result = CliDriver.execute(project, "image", "push", "--dry-run");
Expand Down
10 changes: 10 additions & 0 deletions docs/src/main/asciidoc/grpc-getting-started.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@ quarkus.generate-code.grpc.scan-for-proto=<groupId>:<artifactId>
----
The value of the property may be `none`, which is the default value, or a comma separated list of `groupId:artifactId` coordinates.

== Different gRPC implementations / types

Another thing to take note as well is that Quarkus' gRPC support currently includes 3 different types of gRPC usage:

a. old Vert.x gRPC implementation with a separate gRPC server (default)
b. new Vert.x gRPC implementation on top of the existing HTTP server
c. https://grpc.github.io/grpc/core/md_doc_grpc_xds_features.html[xDS gRPC] wrapper over https://github.com/grpc/grpc-java[grpc-java] with a separate Netty based gRPC server

Further docs explain how to enable and use each of them.

== Implementing a gRPC service

Now that we have the generated classes let's implement our _hello_ service.
Expand Down
45 changes: 45 additions & 0 deletions docs/src/main/asciidoc/grpc-service-consumption.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ The `client-name` is the name set in the `@GrpcClient` or derived from the injec
The following examples uses _hello_ as the client name.
Don't forget to replace it with the name you used in the `@GrpcClient` annotation.

IMPORTANT: When you enable `quarkus.grpc.clients."client-name".use-quarkus-grpc-client`, you are then using the new Vert.x gRPC channel implementation, so not all configuration properties can still be applied. And currently there is no Stork support yet.

IMPORTANT: When you enable `quarkus.grpc.clients."client-name".xds.enabled`, it's the xDS that should handle most of the configuration above.

=== Enabling TLS

To enable TLS, use the following configuration.
Expand Down Expand Up @@ -401,6 +405,47 @@ To disable the gRPC client metrics when `quarkus-micrometer` is used, add the fo
quarkus.micrometer.binder.grpc-client.enabled=false
----

== Custom exception handling

If any of the gRPC services or server interceptors throw an (custom) exception, you can add your own https://github.com/quarkusio/quarkus/extensions/grpc/api/src/main/java/io/quarkus/grpc/ExceptionHandlerProvider.java[ExceptionHandlerProvider]
as a CDI bean in your application, to provide a custom handling of those exceptions.

e.g.

[source, java]
----
@ApplicationScoped
public class HelloExceptionHandlerProvider implements ExceptionHandlerProvider {
@Override
public <ReqT, RespT> ExceptionHandler<ReqT, RespT> createHandler(ServerCall.Listener<ReqT> listener,
ServerCall<ReqT, RespT> serverCall, Metadata metadata) {
return new HelloExceptionHandler<>(listener, serverCall, metadata);
}
@Override
public Throwable transform(Throwable t) {
if (t instanceof HelloException he) {
return new StatusRuntimeException(Status.ABORTED.withDescription(he.getName()));
} else {
return ExceptionHandlerProvider.toStatusException(t, true);
}
}
private static class HelloExceptionHandler<A, B> extends ExceptionHandler<A, B> {
public HelloExceptionHandler(ServerCall.Listener<A> listener, ServerCall<A, B> call, Metadata metadata) {
super(listener, call, metadata);
}
@Override
protected void handleException(Throwable t, ServerCall<A, B> call, Metadata metadata) {
StatusRuntimeException sre = (StatusRuntimeException) ExceptionHandlerProvider.toStatusException(t, true);
Metadata trailers = sre.getTrailers() != null ? sre.getTrailers() : metadata;
call.close(sre.getStatus(), trailers);
}
}
}
----

== Dev Mode

By default, when starting the application in dev mode, a gRPC server is started, even if no services are configured.
Expand Down
6 changes: 6 additions & 0 deletions docs/src/main/asciidoc/grpc-service-implementation.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ If you wish to scale your server, you can set the number of server instances by

include::{generated-dir}/config/quarkus-grpc-config-group-config-grpc-server-configuration.adoc[opts=optional, leveloffset=+1]

IMPORTANT: When you disable `quarkus.grpc.server.use-separate-server`, you are then using the new Vert.x gRPC server implementation
which uses the existing HTTP server. Which means that the server port is now `8080` (or the port configured with `quarkus.http.port`).
Also, most of the other configuration properties are no longer applied, since it's the HTTP server that should already be properly configured.

IMPORTANT: When you enable `quarkus.grpc.server.xds.enabled`, it's the xDS that should handle most of the configuration above.

== Example of Configuration

=== Enabling TLS
Expand Down
83 changes: 83 additions & 0 deletions docs/src/main/asciidoc/grpc-xds.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
////
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
////
= Using xDS gRPC
include::_attributes.adoc[]
:categories: serialization
:summary: This page explains how to enable xDS gRPC usage in your Quarkus application.

This page explains how to enable xDS gRPC usage in your Quarkus application.

IMPORTANT: This Quarkus xDS gRPC integration currently doesn't support building native executables due to the issues
with shaded grpc-netty library while running native IT tests.

== Configuring your project

Edit the `pom.xml` file to add the Quarkus gRPC xDS dependency (just under `<dependencies>`):

[source,xml]
----
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc-xds</artifactId>
</dependency>
----

NOTE: This transitively adds `io.quarkus:quarkus-grpc` extension dependency.

== Server configuration

include::{generated-dir}/config/quarkus-grpc-config-group-config-xds.adoc[opts=optional, leveloffset=+1]

== Server configuration example

To enable server xDS, use the following configuration.

xDS must be explicitly enabled on the server, then verify you use it on the right xDS server port (default is 9000).
If you want to use `XdsServerCredentials` set `xds.secure` to `true`.

[source,properties]
----
quarkus.grpc.server.xds.enabled=true
#quarkus.grpc.server.xds.secure=true
quarkus.grpc.server.port=30051
----

NOTE: When xDS is configured, `plain-text` is automatically disabled.

== Client configuration

include::{generated-dir}/config/quarkus-grpc-config-group-config-client-xds.adoc[opts=optional, leveloffset=+1]

NOTE: When xDS target property is used, name resolver, host, and port are not used

== Client configuration example

To enable client xDS, use the following configuration.

You can either explicitly enable xDS or you use `xds` name resolver,
and make sure you point it to the right xDS server port (default is 9000).
If you want to use `XdsChannelCredentials` set `xds.secure` to `true`.

[source,properties]
----
#quarkus.grpc.clients.<client-name>.xds.enabled=true
#quarkus.grpc.clients.<client-name>.xds.secure=true
quarkus.grpc.clients.<client-name>.name-resolver=xds
quarkus.grpc.clients.<client-name>.port=30051
----

NOTE: When xDS is configured, `plain-text` is automatically disabled.

== Kubernetes configuration example

Below is an example of (required) additional configuration when using xDS gRPC with the Istio Service Mesh in Kubernetes.

[source,properties]
----
quarkus.kubernetes.ports.grpc.container-port=30051
quarkus.kubernetes.annotations."inject.istio.io/templates"=grpc-agent
quarkus.kubernetes.annotations."proxy.istio.io/config"={"holdApplicationUntilProxyStarts": true}
----
2 changes: 2 additions & 0 deletions docs/src/main/asciidoc/grpc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ It:
* supports consuming gRPC services
* integrates with the reactive engine from Quarkus as well as the reactive development model
* allows plain-text communication as well as TLS, and TLS with mutual authentication
* supports https://grpc.github.io/grpc/core/md_doc_grpc_xds_features.html[xDS gRPC] integration
Quarkus gRPC is based on https://vertx.io/docs/vertx-grpc/java/[Vert.x gRPC].

* xref:grpc-getting-started.adoc[Getting Started]
* xref:grpc-service-implementation.adoc[Implementing a gRPC Service]
* xref:grpc-service-consumption.adoc[Consuming a gRPC Service]
* xref:grpc-xds.adoc[Enabling xDS gRPC support]
2 changes: 2 additions & 0 deletions docs/src/main/asciidoc/rest-client-reactive.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,8 @@ public interface ExtensionsService {

Naturally this handling is per REST Client. `@ClientExceptionMapper` uses the default priority if the `priority` attribute is not set and the normal rules of invoking all handlers in turn apply.

NOTE: Methods annotated with `@ClientExceptionMapper` can also take a `java.lang.reflect.Method` parameter which is useful if the exception mapping code needs to know the REST Client method that was invoked and caused the exception mapping code to engage.

[[multipart]]
== Multipart Form support

Expand Down
1 change: 1 addition & 0 deletions extensions/grpc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
<module>stubs</module>
<module>deployment</module>
<module>runtime</module>
<module>xds</module>
</modules>
</project>
Loading

0 comments on commit 4c659a6

Please sign in to comment.