fix oAuth bearer and set openshift container for openshift deployment (#47)
* fix oAuth bearer and set openshift container for openshift deployment
fixes #2872
* Update kafka/README.adoc
Co-authored-by: Peter Palaga <ppalaga@redhat.com>
* Update kafka/README.adoc
Co-authored-by: Peter Palaga <ppalaga@redhat.com>
* Update kafka/README.adoc
Co-authored-by: Peter Palaga <ppalaga@redhat.com>
* Update kafka/README.adoc
Co-authored-by: Peter Palaga <ppalaga@redhat.com>
* remove oAuth2 + Strimzi testcontainers already managed by dev services
Co-authored-by: Peter Palaga <ppalaga@redhat.com>
diff --git a/docs/modules/ROOT/attachments/examples.json b/docs/modules/ROOT/attachments/examples.json
index 51c6a35..6875aa8 100644
--- a/docs/modules/ROOT/attachments/examples.json
+++ b/docs/modules/ROOT/attachments/examples.json
@@ -26,7 +26,7 @@
},
{
"title": "Kafka example ",
- "description": "Shows how to produce and consume messages in a Kafka topic",
+ "description": "Shows how to produce and consume messages in a Kafka topic, using Strimzi Operator",
"link": "https://github.com/apache/camel-quarkus-examples/tree/main/kafka"
},
{
diff --git a/kafka/README.adoc b/kafka/README.adoc
index 9e61b10..51b2034 100644
--- a/kafka/README.adoc
+++ b/kafka/README.adoc
@@ -1,5 +1,5 @@
= Kafka example : A Camel Quarkus example
-:cq-example-description: An example that shows how to produce and consume messages in a Kafka topic
+:cq-example-description: An example that shows how to produce and consume messages in a Kafka topic, using Strimzi Operator
{cq-description}
@@ -9,27 +9,16 @@
== Prerequisites
-The example application requires a running Kafka instance. For simplicity, you can launch the Kafka instance using the docker-compose.yaml.
+The example application requires a running Kafka instance.
-----
-$ cd conf && docker-compose up
-----
-
-Next : uncomment the The section Kafka instance without Authentication in `src/main/resources/application.properties` and set :
-----
-camel.component.kafka.brokers=localhost:9092
-----
-
-If you prefer to use a different Kafka instance uncomment and adjust the corresponding commented section in `src/main/resources/application.properties`.
-
-- The section Kafka instance without Authentication if no Authentication required.
-- The section Kafka instance with SASL Plain is using SASL.
-- The section Kafka instance with SASL Oauth Bearer if using Oauth Bearer.
+For simplicity, this example uses Quarkus DevServices in dev mode. It will automatically start Strimzi container for your tests, and you don’t even need to configure anything: the container will be automatically wired to the Quarkus dev mode configuration.
== Start in Development mode
Run the application in development mode.
+TIP: If you want to use another running instance, in dev mode. Uncomment the corresponding Kafka configuration section in `src/main/resources/application.properties` and change `%prod` profile to `%dev`.
+
[source,shell]
----
$ mvn clean compile quarkus:dev
@@ -64,13 +53,48 @@
----
-=== Package and run the application
+=== Configure Kafka client, package and run the application
-Once you are done with developing you may want to package and run the application.
+Once you are done with developing you may want to configure your kafka client, package and run the application.
TIP: Find more details about the JVM mode and Native mode in the Package and run section of
https://camel.apache.org/camel-quarkus/latest/first-steps.html#_package_and_run_the_application[Camel Quarkus User guide]
+==== Configure kafka client
+Uncomment the corresponding commented section in `src/main/resources/application.properties`.
+
+- The section Kafka instance without Authentication if no Authentication required.
+- The section Kafka instance with SASL Plain if using SASL.
+- The section Kafka instance with SASL Oauth Bearer if using Oauth Bearer.
+
+You need to set the corresponding environment variables:
+- Without Authentication
+[source,shell]
+----
+$ export brokers=<YOUR_KAFKA_BROKERS_URL>
+----
+- SASL Plain
+[source,shell]
+----
+$ export brokers=<YOUR_KAFKA_BROKERS_URL>
+$ export id=<YOUR_KAFKA_SASL_CLIENT_ID>
+$ export secret=<YOUR_KAFKA_SASL_CLIENT_SECRET>
+----
+-SASL Oauth Bearer
+[source,shell]
+----
+$ export brokers=<YOUR_KAFKA_BROKERS_URL>
+$ export id=<YOUR_KAFKA_SASL_CLIENT_ID>
+$ export secret=<YOUR_KAFKA_SASL_CLIENT_SECRET>
+$ export token=<YOUR_KAFKA_SASL_OAUTHBEARER_TOKEN_URL>
+----
+
+If you want to deploy on Kubernetes or Openshift, you'd need to define those in a secret named `camel-kafka`. Set the needed values in the `kubefiles/secret-example.yml`, then add the secret :
+[source,shell]
+----
+$ kubectl apply -f kubefiles/secret-example.yml
+----
+
==== JVM mode
[source,shell]
@@ -96,18 +120,38 @@
You can build a container image for the application like this. Refer to the https://quarkus.io/guides/deploying-to-kubernetes[Quarkus Kubernetes guide] for options around customizing image names, registries etc.
-Uncomment the container build section. Set the proper image group.
+This example uses Jib to create the container image for Kubernetes deployment.
+
+Uncomment the creating container with jib and secrets, in the Kubernetes specific section in `src/main/resources/application.properties`. Set image group and image registry.
+
+Build the application using the `kubernetes` profile.
[source,shell]
----
-$ mvn clean package -DskipTests
+$ mvn clean package -DskipTests -Dkubernetes
+----
+
+The `kubernetes` profile uses quarkus kubernetes and jib container extensions, as described in the `pom.xml`.
+
+[source,shell]
+----
+<dependencies>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-kubernetes</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-container-image-jib</artifactId>
+ </dependency>
+</dependencies>
----
If you are using a local development cluster like Kind or k3s, you can use host the container image on your local host. Or, with minikube, use the Docker daemon from the cluster virtual machine `eval $(minikube docker-env)`. Otherwise, you'll need to push the image to a registry of your choosing.
-TIP: You can build & deploy in one single step by doing `mvn clean package -DskipTests -Dquarkus.kubernetes.deploy=true`
+TIP: You can build & deploy in one single step by doing `mvn clean package -DskipTests -Dkubernetes -Dquarkus.kubernetes.deploy=true`
-Check pods are running.
+Check that the pods are running.
Example when using Strimzi operator, with a Kafka instance named `Test` :
@@ -138,6 +182,7 @@
[source,shell]
----
$ kubectl delete all -l app.kubernetes.io/name=camel-quarkus-examples-kafka
+$ kubectl delete secret camel-kafka
----
[NOTE]
@@ -145,13 +190,33 @@
If you need to configure container resource limits & requests, or enable the Quarkus Kubernetes client to trust self signed certificates, you can find these configuration options in `src/main/resources/application.properties`. Simply uncomment them and set your desired values.
====
+
==== Deploying to OpenShift
+Uncomment the creating container with openshift and secrets, in the Openshift specific section in `src/main/resources/application.properties`.
+
+
[source,shell]
----
$ mvn clean package -DskipTests -Dquarkus.kubernetes.deploy=true -Dopenshift
----
+The `openshift` profile uses quarkus openshift and openshift-container extensions, as described in the `pom.xml`.
+
+[source,shell]
+----
+<dependencies>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-openshift</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-container-image-openshift</artifactId>
+ </dependency>
+</dependencies>
+----
+
You can check the pod status and tail logs using the commands mentioned above in the Kubernetes section. Use the `oc` binary instead of `kubectl` if preferred.
== Feedback
diff --git a/kafka/conf/docker-compose.yaml b/kafka/conf/docker-compose.yaml
deleted file mode 100644
index de99cae..0000000
--- a/kafka/conf/docker-compose.yaml
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-version: '2'
-
-services:
-
- zookeeper:
- image: quay.io/strimzi/kafka:0.21.1-kafka-2.7.0
- command: [
- "sh", "-c",
- "bin/zookeeper-server-start.sh config/zookeeper.properties"
- ]
- ports:
- - "2181:2181"
- environment:
- LOG_DIR: /tmp/logs
-
- kafka:
- image: quay.io/strimzi/kafka:0.21.1-kafka-2.7.0
- command: [
- "sh", "-c",
- "bin/kafka-server-start.sh config/server.properties --override listeners=$${KAFKA_LISTENERS} --override advertised.listeners=$${KAFKA_ADVERTISED_LISTENERS} --override zookeeper.connect=$${KAFKA_ZOOKEEPER_CONNECT}"
- ]
- depends_on:
- - zookeeper
- ports:
- - "9092:9092"
- environment:
- LOG_DIR: "/tmp/logs"
- KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
- KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
- KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
\ No newline at end of file
diff --git a/kafka/kubefiles/secret-example.yml b/kafka/kubefiles/secret-example.yml
new file mode 100644
index 0000000..72499b2
--- /dev/null
+++ b/kafka/kubefiles/secret-example.yml
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+apiVersion: v1
+kind: Secret
+metadata:
+ name: camel-kafka
+ namespace: test
+type: Opaque
+stringData:
+ brokers: "<YOUR_KAFKA_BROKERS_URL>"
+ id: "<YOUR_KAFKA_SASL_CLIENT_ID>"
+ secret: "<YOUR_KAFKA_SASL_CLIENT_SECRET>"
+ token: "<YOUR_KAFKA_SASL_OAUTHBEARER_TOKEN_URL>"
\ No newline at end of file
diff --git a/kafka/pom.xml b/kafka/pom.xml
index 405bf17..7cc2742 100644
--- a/kafka/pom.xml
+++ b/kafka/pom.xml
@@ -45,7 +45,7 @@
<maven-resources-plugin.version>3.1.0</maven-resources-plugin.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<mycila-license.version>3.0</mycila-license.version>
- <strimzi.testcontainers.version>0.20.1</strimzi.testcontainers.version>
+ <kafka-oauth-client.version>0.7.2</kafka-oauth-client.version>
</properties>
<dependencyManagement>
@@ -65,6 +65,11 @@
<type>pom</type>
<scope>import</scope>
</dependency>
+ <dependency>
+ <groupId>io.strimzi</groupId>
+ <artifactId>kafka-oauth-client</artifactId>
+ <version>${kafka-oauth-client.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -95,11 +100,13 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
- <artifactId>quarkus-kubernetes</artifactId>
+ <artifactId>quarkus-kubernetes-config</artifactId>
</dependency>
+
+ <!-- For oauth use case -->
<dependency>
- <groupId>io.quarkus</groupId>
- <artifactId>quarkus-container-image-docker</artifactId>
+ <groupId>io.strimzi</groupId>
+ <artifactId>kafka-oauth-client</artifactId>
</dependency>
<!-- Test -->
@@ -123,12 +130,6 @@
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>io.strimzi</groupId>
- <artifactId>test-container</artifactId>
- <version>${strimzi.testcontainers.version}</version>
- <scope>test</scope>
- </dependency>
</dependencies>
<build>
@@ -305,7 +306,6 @@
<profile>
<id>kubernetes</id>
<activation>
- <activeByDefault>true</activeByDefault>
<property>
<name>kubernetes</name>
</property>
@@ -315,6 +315,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-container-image-jib</artifactId>
+ </dependency>
</dependencies>
</profile>
<profile>
@@ -329,6 +333,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-openshift</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-container-image-openshift</artifactId>
+ </dependency>
</dependencies>
</profile>
</profiles>
diff --git a/kafka/src/main/resources/application.properties b/kafka/src/main/resources/application.properties
index 12c8d81..3d39dd6 100644
--- a/kafka/src/main/resources/application.properties
+++ b/kafka/src/main/resources/application.properties
@@ -23,52 +23,69 @@
timer.delay = 10000
#uncomment to set Kafka instance without Authentication
-#camel.component.kafka.brokers=<YOUR-KAFKA-BOOTSTRAP-URL-HERE>
+#camel.component.kafka.brokers=${brokers}
# uncomment to set Kafka instance with SASL Plain
-#camel.component.kafka.brokers=<YOUR-KAFKA-BOOTSTRAP-URL-HERE>
+#camel.component.kafka.brokers=${brokers}
#camel.component.kafka.security-protocol=SASL_SSL
#camel.component.kafka.sasl-mechanism=PLAIN
-#camel.component.kafka.sasl-jaas-config=org.apache.kafka.common.security.plain.PlainLoginModule required username="<YOUR-SERVICE-ACCOUNT-ID-HERE>" password="<YOUR-SERVICE-ACCOUNT-SECRET-HERE>";
+#camel.component.kafka.sasl-jaas-config=org.apache.kafka.common.security.plain.PlainLoginModule required username="${id}" password="${secret}";
# uncomment to set Kafka instance with SASL Oauth Bearer
-#camel.component.kafka.brokers = <YOUR-KAFKA-BOOTSTRAP-URL-HERE>
+#camel.component.kafka.brokers = ${brokers}
#camel.component.kafka.security-protocol = SASL_SSL
#camel.component.kafka.sasl-mechanism = OAUTHBEARER
#camel.component.kafka.sasl-jaas-config = org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required \
-# oauth.client.id=<YOUR-SERVICE-ACCOUNT-ID-HERE> \
-# oauth.client.secret=<YOUR-SERVICE-ACCOUNT-SECRET-HERE> \
-# oauth.token.endpoint.uri="<TOKEN_ENDPOINT_URI>" ;
+# oauth.client.id="${id}" \
+# oauth.client.secret="${secret}" \
+# oauth.token.endpoint.uri="${token}" ;
#camel.component.kafka.additional-properties[sasl.login.callback.handler.class] = io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler
-# Kubernetes
+###################################
+# Kubernetes specific
+###################################
+# secrets
+#quarkus.kubernetes-config.enabled=true
+#getting secrets while deploying to kubernetes
+#quarkus.kubernetes-config.namespace=test
+#quarkus.kubernetes-config.secrets.enabled=true
+#quarkus.kubernetes-config.secrets=camel-kafka
+
+# creating container with jib
+#quarkus.container-image.build=true
+#quarkus.kubernetes.deployment-target=kubernetes
+#quarkus.container-image.group=<YOUR_IMAGE_GROUP>
+#quarkus.container-image.registry=<YOUR_REGISTRY_URL>
# Uncomment to trust self signed certificates if they are presented by the Kubernetes API server
#quarkus.kubernetes-client.trust-certs=true
-quarkus.kubernetes.image-pull-policy=IfNotPresent
-
# Uncomment to set resource limits
#quarkus.kubernetes.resources.requests.memory=64Mi
#quarkus.kubernetes.resources.requests.cpu=250m
#quarkus.kubernetes.resources.limits.memory=512Mi
#quarkus.kubernetes.resources.limits.cpu=1000m
-# OpenShift
-quarkus.openshift.image-pull-policy=IfNotPresent
+###################################
+# OpenShift specific
+###################################
+# secrets
+#quarkus.kubernetes-config.enabled=true
+#getting secrets while deploying to kubernetes
+#quarkus.kubernetes-config.namespace=test
+#quarkus.kubernetes-config.secrets.enabled=true
+#quarkus.kubernetes-config.secrets=camel-kafka
+# creating container for openshift
+#quarkus.container-image.build=true
+#quarkus.kubernetes.deployment-target=openshift
+
+# OpenShift
+#quarkus.openshift.image-pull-policy=IfNotPresent
# Uncomment to set resource limits
#quarkus.openshift.resources.requests.memory=64Mi
#quarkus.openshift.resources.requests.cpu=250m
#quarkus.openshift.resources.limits.memory=512Mi
#quarkus.openshift.resources.limits.cpu=1000m
-
-
-#uncomment to set container build
-#quarkus.container-image.builder=docker
-#quarkus.kubernetes.deployment-target=kubernetes
-#quarkus.container-image.push=true
-#quarkus.container-image.group=<YOUR_IMAGE_GROUP>
-
diff --git a/kafka/src/test/java/org/apache/camel/example/KafkaTest.java b/kafka/src/test/java/org/apache/camel/example/KafkaTest.java
index 235ea9b..bc5cf9f 100644
--- a/kafka/src/test/java/org/apache/camel/example/KafkaTest.java
+++ b/kafka/src/test/java/org/apache/camel/example/KafkaTest.java
@@ -16,22 +16,22 @@
*/
package org.apache.camel.example;
-import io.quarkus.test.common.QuarkusTestResource;
+import java.util.concurrent.TimeUnit;
+
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
-import static org.hamcrest.Matchers.containsString;
+import static org.awaitility.Awaitility.await;
@QuarkusTest
-@QuarkusTestResource(StrimziTestResource.class)
public class KafkaTest {
@Test
public void testKafka() {
- RestAssured.get("/example")
- .then()
- .statusCode(200)
- .body(containsString("Message #"));
+ await().atMost(10, TimeUnit.SECONDS).until(() -> {
+ String message = RestAssured.get("/example").asString();
+ return message != null && message.contains("Message #");
+ });
}
}
diff --git a/kafka/src/test/java/org/apache/camel/example/StrimziTestResource.java b/kafka/src/test/java/org/apache/camel/example/StrimziTestResource.java
deleted file mode 100644
index 12e0552..0000000
--- a/kafka/src/test/java/org/apache/camel/example/StrimziTestResource.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.example;
-
-import java.util.Map;
-
-import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
-import io.strimzi.StrimziKafkaContainer;
-import org.apache.camel.util.CollectionHelper;
-
-public class StrimziTestResource implements QuarkusTestResourceLifecycleManager {
-
- private StrimziKafkaContainer strimziKafkaContainer;
- private static final int KAFKA_PORT = 9092;
- private static final String KAFKA_STRIMZI_VERSION = "0.20.1-kafka-2.5.0";
-
- @Override
- public Map<String, String> start() {
- strimziKafkaContainer = new StrimziKafkaContainer(KAFKA_STRIMZI_VERSION);
- strimziKafkaContainer.start();
-
- String bootstrap_servers = strimziKafkaContainer.getContainerIpAddress() + ":"
- + strimziKafkaContainer.getMappedPort(KAFKA_PORT);
-
- return CollectionHelper.mapOf(
- "camel.component.kafka.brokers", bootstrap_servers);
- }
-
- @Override
- public void stop() {
- if (strimziKafkaContainer != null) {
- strimziKafkaContainer.stop();
- }
- }
-}