Skip to content

Commit 3b93582

Browse files
committed
update Tomcat sample to use EventSources
1 parent da6f814 commit 3b93582

File tree

17 files changed

+511
-443
lines changed

17 files changed

+511
-443
lines changed

samples/tomcat/README.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
Creates a Tomcat deployment from a Custom Resource, while keeping the WAR separated with another Custom Resource.
44

5+
This sample demonstrates the following capabilities of the Java Operator SDK:
6+
* Multiple Controllers in a single Operator. The Tomcat resource is managed by the TomcatController while the Webapp
7+
resource is managed by the WebappController.
8+
* Reacting to events about resources created by the controller. The TomcatController will receive events about the
9+
Deployment resources it created. See EventSource section below for more detail.
10+
511
## Example input for creating a Tomcat instance
612
```
713
apiVersion: "tomcatoperator.io/v1"
@@ -27,17 +33,26 @@ spec:
2733

2834
## Getting started / Testing
2935

30-
The quickest way to try the operator is to run it on your local machine, while it connects to a local or remote Kubernetes cluster. When you start it it will use the current kubectl context on your machine to connect to the cluster.
36+
The quickest way to try the operator is to run it on your local machine, while it connects to a local or remote
37+
Kubernetes cluster. When you start it, it will use the current kubectl context on your machine to connect to the cluster.
3138

3239
Before you run it you have to install the CRD on your cluster by running `kubectl apply -f k8s/crd.yaml`.
3340

34-
When the Operator is running you can create some Tomcat Custom Resources. You can find a sample custom resources in the k8s folder.
41+
When the Operator is running you can create some Tomcat Custom Resources. You can find a sample custom resources
42+
in the k8s folder.
3543

3644
If you want the Operator to be running as a deployment in your cluster, follow the below steps.
3745

3846
## Build
39-
You can build the sample using `mvn install jib:dockerBuild` this will produce a Docker image you can push to the registry of your choice. The jar file is built using your local Maven and JDK and then copied into the Docker image.
47+
You can build the sample using `mvn install jib:dockerBuild` this will produce a Docker image you can push to the
48+
registry of your choice. The jar file is built using your local Maven and JDK and then copied into the Docker image.
49+
50+
## Install Operator into cluster
51+
52+
Run `kubectl apply -f k8s/crd.yaml` if you haven't already, then run `kubectl apply -f k8s/operator.yaml`.
53+
Now you can create Tomcat instances with CRs (see examples above).
4054

41-
## Install Operator into cluster
55+
## EventSources
56+
The TomcatController is listening to events about Deployments created by the TomcatOperator by registering a
57+
DeploymentEventSource.
4258

43-
Run `kubectl apply -f k8s/crd.yaml` if you haven't already, then run `kubectl apply -f k8s/operator.yaml`. Now you can create Tomcat instances with CRs (see examples above).

samples/tomcat/pom.xml

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@
1212

1313
<artifactId>tomcat-sample</artifactId>
1414
<name>Operator SDK - Samples - Tomcat</name>
15-
<description>Provisions a Tomcat server based on CRDs</description>
15+
<description>Provisions Tomcat Pods and deploys Webapplications in them</description>
1616
<packaging>jar</packaging>
1717

1818
<properties>
1919
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20-
<java-operator-sdk.version>1.3.0</java-operator-sdk.version>
21-
<java.version>11</java.version>
2220
<maven.compiler.source>11</maven.compiler.source>
2321
<maven.compiler.target>11</maven.compiler.target>
2422
<jib-maven-plugin.version>2.5.2</jib-maven-plugin.version>
@@ -43,68 +41,38 @@
4341
<dependency>
4442
<groupId>commons-io</groupId>
4543
<artifactId>commons-io</artifactId>
46-
<version>2.8.0</version>
47-
</dependency>
48-
<dependency>
49-
<groupId>io.fabric8</groupId>
50-
<artifactId>kubernetes-client</artifactId>
51-
<version>4.12.0</version>
44+
<version>2.6</version>
5245
</dependency>
5346
</dependencies>
5447

5548
<build>
5649
<plugins>
5750
<plugin>
58-
<groupId>org.apache.maven.plugins</groupId>
59-
<artifactId>maven-compiler-plugin</artifactId>
60-
<version>3.8.1</version>
61-
</plugin>
62-
<plugin>
63-
<groupId>com.spotify</groupId>
64-
<artifactId>dockerfile-maven-plugin</artifactId>
65-
<version>1.4.13</version>
51+
<groupId>com.google.cloud.tools</groupId>
52+
<artifactId>jib-maven-plugin</artifactId>
53+
<version>${jib-maven-plugin.version}</version>
6654
<configuration>
67-
<repository>tomcat-operator</repository>
68-
<tag>latest</tag>
69-
<buildArgs>
70-
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
71-
</buildArgs>
55+
<from>
56+
<image>gcr.io/distroless/java:11</image>
57+
</from>
58+
<to>
59+
<image>eu.gcr.io/adamsandor-test/tomcat-operator</image>
60+
</to>
7261
</configuration>
73-
</plugin>
74-
<plugin>
75-
<groupId>org.apache.maven.plugins</groupId>
76-
<artifactId>maven-shade-plugin</artifactId>
77-
<version>3.2.4</version>
7862
<executions>
7963
<execution>
8064
<phase>package</phase>
8165
<goals>
82-
<goal>shade</goal>
66+
<goal>build</goal>
8367
</goals>
84-
<configuration>
85-
<createDependencyReducedPom>false</createDependencyReducedPom>
86-
<transformers>
87-
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
88-
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
89-
<manifestEntries>
90-
<Main-Class>io.javaoperatorsdk.operator.sample.TomcatOperator</Main-Class>
91-
<Build-Number>1.0</Build-Number>
92-
<Multi-Release>true</Multi-Release>
93-
</manifestEntries>
94-
</transformer>
95-
</transformers>
96-
<filters>
97-
<filter>
98-
<artifact>io.fabric8:openshift-client</artifact>
99-
<excludes>
100-
<exclude>io/fabric8/kubernetes/client/Config*</exclude>
101-
</excludes>
102-
</filter>
103-
</filters>
104-
</configuration>
10568
</execution>
10669
</executions>
10770
</plugin>
71+
<plugin>
72+
<groupId>org.apache.maven.plugins</groupId>
73+
<artifactId>maven-compiler-plugin</artifactId>
74+
<version>3.8.1</version>
75+
</plugin>
10876
</plugins>
10977
</build>
110-
</project>
78+
</project>

samples/tomcat/src/main/java/META-INF/MANIFEST.MF

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.javaoperatorsdk.operator.sample;
2+
3+
import io.fabric8.kubernetes.api.model.apps.Deployment;
4+
import io.fabric8.kubernetes.client.Watcher;
5+
import io.javaoperatorsdk.operator.processing.event.AbstractEvent;
6+
7+
public class DeploymentEvent extends AbstractEvent {
8+
9+
private final Watcher.Action action;
10+
private final Deployment deployment;
11+
12+
public DeploymentEvent(Watcher.Action action, Deployment resource,
13+
DeploymentEventSource deploymentEventSource) {
14+
//TODO: this mapping is really critical and should be made more explicit
15+
super(resource.getMetadata().getOwnerReferences().get(0).getUid(), deploymentEventSource);
16+
this.action = action;
17+
this.deployment = resource;
18+
}
19+
20+
public Watcher.Action getAction() {
21+
return action;
22+
}
23+
24+
public String resourceUid() {
25+
return getDeployment().getMetadata().getUid();
26+
}
27+
28+
@Override
29+
public String toString() {
30+
return "CustomResourceEvent{" +
31+
"action=" + action +
32+
", resource=[ name=" + getDeployment().getMetadata().getName() + ", kind=" + getDeployment().getKind() +
33+
", apiVersion=" + getDeployment().getApiVersion() + " ,resourceVersion=" + getDeployment().getMetadata().getResourceVersion() +
34+
", markedForDeletion: " + (getDeployment().getMetadata().getDeletionTimestamp() != null
35+
&& !getDeployment().getMetadata().getDeletionTimestamp().isEmpty()) +
36+
" ]" +
37+
'}';
38+
}
39+
40+
public Deployment getDeployment() {
41+
return deployment;
42+
}
43+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package io.javaoperatorsdk.operator.sample;
2+
3+
import io.fabric8.kubernetes.api.model.apps.Deployment;
4+
import io.fabric8.kubernetes.client.KubernetesClient;
5+
import io.fabric8.kubernetes.client.KubernetesClientException;
6+
import io.fabric8.kubernetes.client.Watcher;
7+
import io.javaoperatorsdk.operator.processing.event.AbstractEventSource;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
11+
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID;
12+
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion;
13+
import static java.net.HttpURLConnection.HTTP_GONE;
14+
15+
public class DeploymentEventSource extends AbstractEventSource implements Watcher<Deployment> {
16+
private final static Logger log = LoggerFactory.getLogger(DeploymentEventSource.class);
17+
18+
private final KubernetesClient client;
19+
20+
public static DeploymentEventSource createAndRegisterWatch(KubernetesClient client) {
21+
DeploymentEventSource deploymentEventSource = new DeploymentEventSource(client);
22+
deploymentEventSource.registerWatch();
23+
return deploymentEventSource;
24+
}
25+
26+
private DeploymentEventSource(KubernetesClient client) {
27+
this.client = client;
28+
}
29+
30+
private void registerWatch() {
31+
client.apps().deployments().inAnyNamespace().withLabel("managed-by", "tomcat-operator").watch(this);
32+
}
33+
34+
@Override
35+
public void eventReceived(Action action, Deployment deployment) {
36+
log.info("Event received for action: {}, Deployment: {} (rr={})", action.name(), deployment.getMetadata().getName(), deployment.getStatus().getReadyReplicas());
37+
38+
if (action == Action.ERROR) {
39+
log.warn("Skipping {} event for custom resource uid: {}, version: {}", action,
40+
getUID(deployment), getVersion(deployment));
41+
return;
42+
}
43+
44+
eventHandler.handleEvent(new DeploymentEvent(action, deployment, this));
45+
}
46+
47+
@Override
48+
public void onClose(KubernetesClientException e) {
49+
if (e == null) {
50+
return;
51+
}
52+
if (e.getCode() == HTTP_GONE) {
53+
log.warn("Received error for watch, will try to reconnect.", e);
54+
registerWatch();
55+
} else {
56+
// Note that this should not happen normally, since fabric8 client handles reconnect.
57+
// In case it tries to reconnect this method is not called.
58+
log.error("Unexpected error happened with watch. Will exit.", e);
59+
System.exit(1);
60+
}
61+
}
62+
}

samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Tomcat.java

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,29 @@
44

55
public class Tomcat extends CustomResource {
66

7-
private TomcatSpec spec;
7+
private TomcatSpec spec;
88

9-
private TomcatStatus status;
9+
private TomcatStatus status;
1010

11-
public TomcatSpec getSpec() {
12-
if (spec == null) {
13-
spec = new TomcatSpec();
11+
public TomcatSpec getSpec() {
12+
if (spec == null) {
13+
spec = new TomcatSpec();
14+
}
15+
return spec;
1416
}
15-
return spec;
16-
}
1717

18-
public void setSpec(TomcatSpec spec) {
19-
this.spec = spec;
20-
}
18+
public void setSpec(TomcatSpec spec) {
19+
this.spec = spec;
20+
}
2121

22-
public TomcatStatus getStatus() {
23-
if (status == null) {
24-
status = new TomcatStatus();
22+
public TomcatStatus getStatus() {
23+
if (status == null) {
24+
status = new TomcatStatus();
25+
}
26+
return status;
2527
}
26-
return status;
27-
}
2828

29-
public void setStatus(TomcatStatus status) {
30-
this.status = status;
31-
}
32-
}
29+
public void setStatus(TomcatStatus status) {
30+
this.status = status;
31+
}
32+
}

0 commit comments

Comments
 (0)