Merge pull request #12 from manusa/feat/update-cassandra-kubernetes

Updated Cassandraql example to use Eclipse JKube
diff --git a/examples/camel-example-cassandra-kubernetes/README.adoc b/examples/camel-example-cassandra-kubernetes/README.adoc
index 33a5240..82d47a4 100644
--- a/examples/camel-example-cassandra-kubernetes/README.adoc
+++ b/examples/camel-example-cassandra-kubernetes/README.adoc
@@ -5,47 +5,52 @@
 
 This example is based on:
 
-* Minikube 0.21.0 (Kubernetes version >= 1.7)
-* Fabric8 Maven Plugin (version >= 3.5)
+* Minikube 1.11.0 (Kubernetes version >= 1.17)
+* https://www.eclipse.org/jkube[Eclipse JKube]
 
-First thing you'll need to do is preparing the environment.
+First thing you'll need to do is to prepare the environment.
 
-Don't forget to use a bit more memory for your Minikube for running this
-example:
+Don't forget to use a bit more memory for your Minikube setup to run this
+example smoothly:
 
-....
+[source,sh]
+----
 $ minikube start --memory 5120 --cpus=4
-....
+----
 
 Once your Minikube node is up and running you'll need to run the
-following command. In your src/main/resource/fabric8/ folder you'll find
-two yaml file. Run the following command using them:
+following command. In your `src/main/resource/jkube/` folder you'll find
+two yaml files. Run the following commands using them to prepare the Cassandra cluster:
 
-....
-$ kubectl create -f src/main/resources/fabric8/cassandra-service.yaml
-$ kubectl create -f src/main/resources/fabric8/cassandra-statefulset.yaml
-....
+[source,sh]
+----
+$ kubectl create -f src/main/resources/jkube/cassandra-service.yaml
+$ kubectl create -f src/main/resources/jkube/cassandra-statefulset.yaml
+----
 
 To check the correct startup of the cluster run the following command:
 
-....
-$ kubectl get statefulsets
-NAME        DESIRED   CURRENT   AGE
-cassandra   2         2         2h
-....
+[source,sh]
+----
+$ kubectl get statefulsets.apps
+NAME        READY   AGE
+cassandra   2/2     3h44m
+----
 
 and check the status of the pods
 
-....
+[source,sh]
+----
 $ kubectl get pods
 NAME                                       READY     STATUS    RESTARTS   AGE
 cassandra-0                                1/1       Running   0          2h
 cassandra-1                                1/1       Running   0          2h
-....
+----
 
 You can also verify the health of your cluster by running
 
-....
+[source,sh]
+----
 $ kubectl exec <pod_name> -it nodetool status
 Datacenter: DC1-K8Demo
 ======================
@@ -54,76 +59,81 @@
 --  Address     Load       Tokens       Owns (effective)  Host ID                               Rack
 UN  172.17.0.4  212.14 KiB  32           53.1%             9bf81ccd-4aa1-451b-b56e-c16c5ee04836  Rack1-K8Demo
 UN  172.17.0.6  170.08 KiB  32           46.9%             69cc6f60-9ccf-439d-a298-b79b643c1586  Rack1-K8Demo
-....
+----
 
 === Building and running
 
-Navigate to the project folder and the example can be built with
+Navigate to the project folder where the example can be built with
 
-....
-mvn clean -Pkubernetes-install fabric8:deploy
-....
+[source,sh]
+----
+$ mvn clean -Pkubernetes-install k8s:deploy
+----
 
-When the example runs in fabric8, you can use the Kubectl command tool
+When the example runs in Kubernetes, you can use the Kubectl command tool
 to inspect the status
 
 To list all the running pods:
 
-....
-kubectl get pods
-....
+[source,sh]
+----
+$ kubectl get pods
+----
 
-Then find the name of the pod that runs this quickstart, and output the
-logs from the running pods with:
+You can follow the log for the created Pod by running:
 
-....
-kubectl logs <name of pod>
-....
+[source,sh]
+----
+$ mvn -Pkubernetes-install k8s:log
+----
 
-and you should see something like this:
+You should then see an output similar to this:
 
-....
-2017-08-06 10:43:52,209 [main           ] INFO  ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1068e947: startup date [Sun Aug 06 10:43:52 UTC 2017]; root of context hierarchy
-2017-08-06 10:43:52,244 [main           ] INFO  XmlBeanDefinitionReader        - Loading XML bean definitions from class path resource [META-INF/spring/camel-context.xml]
-2017-08-06 10:43:53,425 [main           ] INFO  GuavaCompatibility             - Detected Guava >= 19 in the classpath, using modern compatibility layer
-2017-08-06 10:43:53,564 [main           ] INFO  ClockFactory                   - Using native clock to generate timestamps.
-2017-08-06 10:43:53,639 [main           ] INFO  NettyUtil                      - Did not find Netty's native epoll transport in the classpath, defaulting to NIO.
-2017-08-06 10:43:54,054 [main           ] INFO  DCAwareRoundRobinPolicy        - Using data-center name 'DC1-K8Demo' for DCAwareRoundRobinPolicy (if this is incorrect, please provide the correct datacenter name with DCAwareRoundRobinPolicy constructor)
-2017-08-06 10:43:54,056 [main           ] INFO  Cluster                        - New Cassandra host cassandra/172.17.0.2:9042 added
-2017-08-06 10:43:54,056 [main           ] INFO  Cluster                        - New Cassandra host cassandra/172.17.0.4:9042 added
-2017-08-06 10:43:56,845 [main           ] INFO  SpringCamelContext             - Apache Camel 2.20.0-SNAPSHOT (CamelContext: camel-1) is starting
-2017-08-06 10:43:56,846 [main           ] INFO  ManagedManagementStrategy      - JMX is enabled
-2017-08-06 10:43:57,105 [main           ] INFO  DefaultTypeConverter           - Type converters loaded (core: 192, classpath: 1)
-2017-08-06 10:43:57,225 [main           ] INFO  SpringCamelContext             - StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
-2017-08-06 10:43:57,230 [main           ] INFO  ClockFactory                   - Using native clock to generate timestamps.
-2017-08-06 10:43:57,918 [main           ] INFO  DCAwareRoundRobinPolicy        - Using data-center name 'DC1-K8Demo' for DCAwareRoundRobinPolicy (if this is incorrect, please provide the correct datacenter name with DCAwareRoundRobinPolicy constructor)
-2017-08-06 10:43:57,920 [main           ] INFO  Cluster                        - New Cassandra host cassandra/172.17.0.2:9042 added
-2017-08-06 10:43:57,920 [main           ] INFO  Cluster                        - New Cassandra host cassandra/172.17.0.4:9042 added
-2017-08-06 10:43:58,488 [main           ] INFO  SpringCamelContext             - Route: cassandra-route started and consuming from: timer://foo?period=5000
-2017-08-06 10:43:58,489 [main           ] INFO  SpringCamelContext             - Total 1 routes, of which 1 are started.
-2017-08-06 10:43:58,489 [main           ] INFO  SpringCamelContext             - Apache Camel 2.20.0-SNAPSHOT (CamelContext: camel-1) started in 1.645 seconds
-2017-08-06 10:43:58,492 [main           ] INFO  DefaultLifecycleProcessor      - Starting beans in phase 2147483646
-2017-08-06 10:43:59,586 [2 - timer://foo] INFO  cassandra-route                - Query result set [Row[1, oscerd]]
-2017-08-06 10:44:04,575 [2 - timer://foo] INFO  cassandra-route                - Query result set [Row[1, oscerd]]
-2017-08-06 10:44:09,577 [2 - timer://foo] INFO  cassandra-route                - Query result set [Row[1, oscerd]]
-....
+[source,sh]
+----
+[INFO] k8s: 2020-08-07 12:34:32,569 [main           ] INFO  GuavaCompatibility             - Detected Guava >= 19 in the classpath, using modern compatibility layer
+[INFO] k8s: 2020-08-07 12:34:32,834 [main           ] INFO  ClockFactory                   - Using native clock to generate timestamps.
+[INFO] k8s: 2020-08-07 12:34:33,005 [main           ] INFO  NettyUtil                      - Did not find Netty's native epoll transport in the classpath, defaulting to NIO.
+[INFO] k8s: 2020-08-07 12:34:34,122 [main           ] INFO  DCAwareRoundRobinPolicy        - Using data-center name 'DC1-K8Demo' for DCAwareRoundRobinPolicy (if this is incorrect, please provide the correct datacenter name with DCAwareRoundRobinPolicy constructor)
+[INFO] k8s: 2020-08-07 12:34:34,124 [main           ] INFO  Cluster                        - New Cassandra host cassandra/172.17.0.7:9042 added
+[INFO] k8s: 2020-08-07 12:34:34,150 [main           ] INFO  Cluster                        - New Cassandra host cassandra/172.17.0.6:9042 added
+[INFO] k8s: 2020-08-07 12:34:36,780 [main           ] INFO  CqlPopulateBean                - Cassandra was populated with sample values for test.users table
+[INFO] k8s: 2020-08-07 12:34:37,372 [main           ] INFO  LRUCacheFactory                - Detected and using LRUCacheFactory: camel-caffeine-lrucache
+[INFO] k8s: 2020-08-07 12:34:38,012 [main           ] INFO  AbstractCamelContext           - Apache Camel 3.5.0-SNAPSHOT (camel-1) is starting
+[INFO] k8s: 2020-08-07 12:34:38,019 [main           ] INFO  AbstractCamelContext           - StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
+[INFO] k8s: 2020-08-07 12:34:38,019 [main           ] INFO  AbstractCamelContext           - Using HealthCheck: camel-health
+[INFO] k8s: 2020-08-07 12:34:38,664 [main           ] INFO  DefaultMavenCoordinates        - DataStax Java driver for Apache Cassandra(R) (com.datastax.oss:java-driver-core) version 4.8.0
+[INFO] k8s: 2020-08-07 12:34:39,554 [s0-admin-0     ] INFO  Clock                          - Using native clock for microsecond precision
+[INFO] k8s: 2020-08-07 12:34:41,453 [main           ] INFO  InternalRouteStartupManager    - Route: cassandra-route started and consuming from: timer://foo
+[INFO] k8s: 2020-08-07 12:34:41,454 [main           ] INFO  AbstractCamelContext           - Total 1 routes, of which 1 are started
+[INFO] k8s: 2020-08-07 12:34:41,455 [main           ] INFO  AbstractCamelContext           - Apache Camel 3.5.0-SNAPSHOT (camel-1) started in 3.441 seconds
+[INFO] k8s: 2020-08-07 12:34:41,469 [main           ] INFO  BaseMainSupport                - Using properties from: classpath:application.properties;optional=true
+[INFO] k8s: 2020-08-07 12:34:41,557 [main           ] INFO  DefaultRoutesCollector         - No additional Camel XML routes discovered from: classpath:camel/*.xml
+[INFO] k8s: 2020-08-07 12:34:41,557 [main           ] INFO  DefaultRoutesCollector         - No additional Camel XML route templates discovered from: classpath:camel-template/*.xml
+[INFO] k8s: 2020-08-07 12:34:41,559 [main           ] INFO  DefaultRoutesCollector         - No additional Camel XML rests discovered from: classpath:camel-rest/*.xml
+[INFO] k8s: 2020-08-07 12:34:42,557 [1 - timer://foo] INFO  cassandra-route                - Query result set [1-oscerd,2-not-a-bot]
+[INFO] k8s: 2020-08-07 12:34:47,548 [1 - timer://foo] INFO  cassandra-route                - Query result set [1-oscerd,2-not-a-bot]
+[INFO] k8s: 2020-08-07 12:34:52,661 [1 - timer://foo] INFO  cassandra-route                - Query result set [1-oscerd,2-not-a-bot]
+----
 
 === Cleanup
 
 Run following to undeploy the application and cassandra nodes
 
-....
-$ mvn -Pkubernetes-install fabric8:undeploy
-$ kubectl create -f src/main/resources/fabric8/cassandra-service.yaml
-$ kubectl create -f src/main/resources/fabric8/cassandra-statefulset.yaml
-....
+[source,sh]
+----
+$ mvn -Pkubernetes-install k8s:undeploy
+$ kubectl delete -f src/main/resources/jkube/cassandra-service.yaml
+$ kubectl delete -f src/main/resources/jkube/cassandra-statefulset.yaml
+----
 
 Make sure no pod is running
 
-....
+[source,sh]
+----
 $ kubectl get pods
 No resources found.
-....
+----
 
 === Help and contributions
 
diff --git a/examples/camel-example-cassandra-kubernetes/pom.xml b/examples/camel-example-cassandra-kubernetes/pom.xml
index 4123006..c6d4cc5 100644
--- a/examples/camel-example-cassandra-kubernetes/pom.xml
+++ b/examples/camel-example-cassandra-kubernetes/pom.xml
@@ -36,6 +36,7 @@
         <category>Cloud</category>
         <!-- dependency versions -->
         <cassandra.driver.version>3.7.2</cassandra.driver.version>
+        <main.class>org.apache.camel.spring.Main</main.class>
     </properties>
 
     <dependencyManagement>
@@ -72,6 +73,12 @@
             <groupId>com.datastax.cassandra</groupId>
             <artifactId>cassandra-driver-core</artifactId>
             <version>${cassandra.driver.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>io.netty</groupId>
+                    <artifactId>netty-handler</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <!-- used for generating random message -->
@@ -98,30 +105,55 @@
             <version>${log4j-version}</version>
         </dependency>
     </dependencies>
-
-    <!-- only run tests if this profile is enabled -->
+    <build>
+        <plugins>
+            <!-- allows the route to be ran via 'mvn exec:java' -->
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <version>${exec-maven-plugin-version}</version>
+                <configuration>
+                    <mainClass>${main.class}</mainClass>
+                </configuration>
+            </plugin>
+            <!-- Create a Fat JAR -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>${maven-assembly-plugin-version}</version>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                    <appendAssemblyId>false</appendAssemblyId>
+                    <archive>
+                        <manifest>
+                            <mainClass>${main.class}</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>fat-jar</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
     <profiles>
         <profile>
             <id>kubernetes-install</id>
-
             <build>
                 <defaultGoal>install</defaultGoal>
-
                 <plugins>
-
                     <plugin>
-                        <groupId>io.fabric8</groupId>
-                        <artifactId>fabric8-maven-plugin</artifactId>
-                        <version>${fabric8-maven-plugin-version}</version>
-                        <configuration>
-                            <generator>
-                                <config>
-                                    <java-exec>
-                                        <mainClass>org.apache.camel.spring.Main</mainClass>
-                                    </java-exec>
-                                </config>
-                            </generator>
-                        </configuration>
+                        <groupId>org.eclipse.jkube</groupId>
+                        <artifactId>kubernetes-maven-plugin</artifactId>
+                        <version>${jkube-version}</version>
                         <executions>
                             <execution>
                                 <goals>
@@ -132,15 +164,7 @@
                         </executions>
                     </plugin>
 
-                    <!-- allows the route to be ran via 'mvn exec:java' -->
-                    <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>exec-maven-plugin</artifactId>
-                        <version>${exec-maven-plugin-version}</version>
-                        <configuration>
-                            <mainClass>org.apache.camel.spring.Main</mainClass>
-                        </configuration>
-                    </plugin>
+
 
                 </plugins>
             </build>
diff --git a/examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/fmp/CqlPopulateBean.java b/examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/jkube/CqlPopulateBean.java
similarity index 63%
rename from examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/fmp/CqlPopulateBean.java
rename to examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/jkube/CqlPopulateBean.java
index b4ee7ad..f7094f7 100644
--- a/examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/fmp/CqlPopulateBean.java
+++ b/examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/jkube/CqlPopulateBean.java
@@ -14,21 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.example.kubernetes.fmp;
+package org.apache.camel.example.kubernetes.jkube;
 
 import com.datastax.driver.core.Cluster;
 import com.datastax.driver.core.Session;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class CqlPopulateBean {
 
+    private static final Logger log = LoggerFactory.getLogger(CqlPopulateBean.class);
+
     public void populate() {
         Cluster cluster = Cluster.builder().addContactPoint("cassandra").build();
         Session session = cluster.connect();
-        session.execute("create keyspace if not exists test with replication = {'class':'SimpleStrategy', 'replication_factor':1};");
-        session.execute("create table if not exists test.users ( id int primary key, name text );");
-        session.execute("insert into test.users (id,name) values (1, 'oscerd') if not exists;");
+        session.execute("CREATE KEYSPACE IF NOT EXISTS test WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':1};");
+        session.execute("CREATE TABLE IF NOT EXISTS test.users ( id int primary key, name text );");
+        session.execute("INSERT INTO test.users (id,name) VALUES (1, 'oscerd') IF NOT EXISTS;");
+        session.execute("INSERT INTO test.users (id,name) VALUES (2, 'not-a-bot') IF NOT EXISTS;");
         session.close();
         cluster.close();
+        log.info("Cassandra was populated with sample values for test.users table");
     }
 
 }
diff --git a/examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/jkube/RowProcessor.java b/examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/jkube/RowProcessor.java
new file mode 100644
index 0000000..9235d49
--- /dev/null
+++ b/examples/camel-example-cassandra-kubernetes/src/main/java/org/apache/camel/example/kubernetes/jkube/RowProcessor.java
@@ -0,0 +1,36 @@
+/*
+ * 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.kubernetes.jkube;
+
+import com.datastax.oss.driver.api.core.cql.Row;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class RowProcessor implements Processor {
+  @SuppressWarnings("unchecked")
+  @Override
+  public void process(Exchange exchange) {
+    final List<Row> rows = exchange.getIn().getBody(List.class);
+    exchange.getIn().setBody(rows.stream()
+      .map(row -> String.format("%s-%s", row.getInt("id"), row.getString("name")))
+      .collect(Collectors.joining(","))
+    );
+  }
+}
diff --git a/examples/camel-example-cassandra-kubernetes/src/main/resources/META-INF/spring/camel-context.xml b/examples/camel-example-cassandra-kubernetes/src/main/resources/META-INF/spring/camel-context.xml
index 2303f7d..f4d722d 100644
--- a/examples/camel-example-cassandra-kubernetes/src/main/resources/META-INF/spring/camel-context.xml
+++ b/examples/camel-example-cassandra-kubernetes/src/main/resources/META-INF/spring/camel-context.xml
@@ -26,14 +26,15 @@
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
 
-  <bean id="populate" class="org.apache.camel.example.kubernetes.fmp.CqlPopulateBean" init-method="populate"/>
-
+  <bean id="populate" class="org.apache.camel.example.kubernetes.jkube.CqlPopulateBean" init-method="populate"/>
+  <bean id="rowProcessor" class="org.apache.camel.example.kubernetes.jkube.RowProcessor"/>
   <camelContext xmlns="http://camel.apache.org/schema/spring" depends-on="populate">
 
     <route id="cassandra-route">
       <from uri="timer:foo?period=5000"/>
-      <to uri="cql://cassandra/test?cql=select * from users;&amp;consistencyLevel=quorum" />
-      <log message="Query result set ${body}"/>
+      <to uri="cql://cassandra/test?datacenter=DC1-K8Demo&amp;cql=SELECT * FROM users;&amp;consistencyLevel=quorum" />
+      <process ref="rowProcessor"/>
+      <log message="Query result set [${body}]"/>
     </route>
 
   </camelContext>
diff --git a/examples/camel-example-cassandra-kubernetes/src/main/resources/fabric8/cassandra-service.yaml b/examples/camel-example-cassandra-kubernetes/src/main/resources/jkube/cassandra-service.yaml
similarity index 100%
rename from examples/camel-example-cassandra-kubernetes/src/main/resources/fabric8/cassandra-service.yaml
rename to examples/camel-example-cassandra-kubernetes/src/main/resources/jkube/cassandra-service.yaml
diff --git a/examples/camel-example-cassandra-kubernetes/src/main/resources/fabric8/cassandra-statefulset.yaml b/examples/camel-example-cassandra-kubernetes/src/main/resources/jkube/cassandra-statefulset.yaml
similarity index 97%
rename from examples/camel-example-cassandra-kubernetes/src/main/resources/fabric8/cassandra-statefulset.yaml
rename to examples/camel-example-cassandra-kubernetes/src/main/resources/jkube/cassandra-statefulset.yaml
index 6650053..fdb1665 100644
--- a/examples/camel-example-cassandra-kubernetes/src/main/resources/fabric8/cassandra-statefulset.yaml
+++ b/examples/camel-example-cassandra-kubernetes/src/main/resources/jkube/cassandra-statefulset.yaml
@@ -15,13 +15,16 @@
 # limitations under the License.
 #
 
-apiVersion: "apps/v1beta1"
+apiVersion: "apps/v1"
 kind: StatefulSet
 metadata:
   name: cassandra
 spec:
   serviceName: cassandra
   replicas: 2
+  selector:
+    matchLabels:
+      app: cassandra
   template:
     metadata:
       labels:
diff --git a/examples/pom.xml b/examples/pom.xml
index d9b861e..caab63b 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -189,6 +189,7 @@
         <woodstox-version>6.0.3</woodstox-version>
         <xmlunit-version>1.6</xmlunit-version>
         <derby-version>10.14.2.0</derby-version>
+        <jkube-version>1.0.0-rc-1</jkube-version>
     </properties>
 
     <!-- Comment out the snapshot repositories as we don't need them now -->