Skip to content

Commit f6b16e9

Browse files
authored
feat: demonstrate contract-first CRDs (#1524)
* feat: demonstrate contract-first CRDs Modify the leader-election sample to use contract-first. That is, the CRDs is written in YAML and the java code is generated automatically using the java-generator-maven-plugin from fabric8. * Fix custom resource name and plural * Add status to CRD, ensure reconciledBy is not null, fix ClusterRole Lots of silly mistakes, sorry for that. * Use plural form in CRD file name
1 parent 14598b8 commit f6b16e9

File tree

9 files changed

+80
-58
lines changed

9 files changed

+80
-58
lines changed
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Leader Election E2E Test
22

3-
The purpose of this module is to e2e test leader election feature.
3+
The purpose of this module is to e2e test leader election feature and to demonstrate contract-first CRDs.
44

55
The deployment is using directly pods in order to better control some aspects in test.
6-
In real life this would be a Deployment.
6+
In real life this would be a Deployment.
7+
8+
The custom resource definition (CRD) is defined in YAML in the folder `src/main/resources/kubernetes`.
9+
Upon build, the [java-generator-maven-plugin](https://github.com/fabric8io/kubernetes-client/blob/master/doc/java-generation-from-CRD.md)
10+
generates the Java code under `target/generated-sources/java`.

sample-operators/leader-election/k8s/namespace-inferred-operator.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ rules:
4848
- apiGroups:
4949
- "sample.javaoperatorsdk"
5050
resources:
51-
- leaderelectiontestcustomresources
52-
- leaderelectiontestcustomresources/status
51+
- leaderelections
52+
- leaderelections/status
5353
verbs:
5454
- '*'
5555
- apiGroups:

sample-operators/leader-election/k8s/operator.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ rules:
5252
- apiGroups:
5353
- "sample.javaoperatorsdk"
5454
resources:
55-
- leaderelectiontestcustomresources
56-
- leaderelectiontestcustomresources/status
55+
- leaderelections
56+
- leaderelections/status
5757
verbs:
5858
- '*'
5959
- apiGroups:

sample-operators/leader-election/pom.xml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@
4747
<artifactId>takes</artifactId>
4848
<version>1.21.1</version>
4949
</dependency>
50-
<dependency>
51-
<groupId>io.fabric8</groupId>
52-
<artifactId>crd-generator-apt</artifactId>
53-
<scope>provided</scope>
54-
</dependency>
5550
<dependency>
5651
<groupId>org.awaitility</groupId>
5752
<artifactId>awaitility</artifactId>
@@ -88,6 +83,22 @@
8883
<artifactId>maven-compiler-plugin</artifactId>
8984
<version>3.10.0</version>
9085
</plugin>
86+
<plugin>
87+
<!-- Generate Java code from the custom resource definitions -->
88+
<groupId>io.fabric8</groupId>
89+
<artifactId>java-generator-maven-plugin</artifactId>
90+
<version>${fabric8-client.version}</version>
91+
<executions>
92+
<execution>
93+
<goals>
94+
<goal>generate</goal>
95+
</goals>
96+
</execution>
97+
</executions>
98+
<configuration>
99+
<source>src/main/resources/kubernetes</source>
100+
</configuration>
101+
</plugin>
91102
</plugins>
92103
</build>
93104

sample-operators/leader-election/src/main/java/io/javaoperatorsdk/operator/sample/LeaderElectionTestCustomResource.java

Lines changed: 0 additions & 15 deletions
This file was deleted.

sample-operators/leader-election/src/main/java/io/javaoperatorsdk/operator/sample/LeaderElectionTestReconciler.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
package io.javaoperatorsdk.operator.sample;
22

33
import java.time.Duration;
4+
import java.util.ArrayList;
45

56
import io.javaoperatorsdk.operator.api.reconciler.Context;
67
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
78
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
89
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
910

11+
import javaoperatorsdk.sample.v1.LeaderElection;
12+
import javaoperatorsdk.sample.v1.LeaderElectionStatus;
13+
1014
@ControllerConfiguration()
1115
public class LeaderElectionTestReconciler
12-
implements Reconciler<LeaderElectionTestCustomResource> {
16+
implements Reconciler<LeaderElection> {
1317

1418
private final String reconcilerName;
1519

@@ -18,12 +22,15 @@ public LeaderElectionTestReconciler(String reconcilerName) {
1822
}
1923

2024
@Override
21-
public UpdateControl<LeaderElectionTestCustomResource> reconcile(
22-
LeaderElectionTestCustomResource resource,
23-
Context<LeaderElectionTestCustomResource> context) {
25+
public UpdateControl<LeaderElection> reconcile(
26+
LeaderElection resource,
27+
Context<LeaderElection> context) {
2428

2529
if (resource.getStatus() == null) {
26-
resource.setStatus(new LeaderElectionTestStatus());
30+
resource.setStatus(new LeaderElectionStatus());
31+
}
32+
if (resource.getStatus().getReconciledBy() == null) {
33+
resource.getStatus().setReconciledBy(new ArrayList<>());
2734
}
2835

2936
resource.getStatus().getReconciledBy().add(reconcilerName);

sample-operators/leader-election/src/main/java/io/javaoperatorsdk/operator/sample/LeaderElectionTestStatus.java

Lines changed: 0 additions & 21 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Custom Resource Definition that will be used to generate the Java classes in target/generated-sources/java
2+
# See https://github.com/fabric8io/kubernetes-client/blob/master/doc/java-generation-from-CRD.md
3+
# The Java classes will then be used to recreate this CR in target/classes/META-INF/fabric8
4+
apiVersion: apiextensions.k8s.io/v1
5+
kind: CustomResourceDefinition
6+
metadata:
7+
name: leaderelections.sample.javaoperatorsdk
8+
spec:
9+
group: sample.javaoperatorsdk
10+
names:
11+
kind: LeaderElection
12+
singular: leaderelection
13+
plural: leaderelections
14+
shortNames:
15+
- le
16+
- les
17+
scope: Namespaced
18+
versions:
19+
- name: v1
20+
schema:
21+
openAPIV3Schema:
22+
properties:
23+
status:
24+
properties:
25+
reconciledBy:
26+
items:
27+
type: string
28+
type: array
29+
type: object
30+
type: object
31+
served: true
32+
storage: true
33+
subresources:
34+
status: {}

sample-operators/leader-election/src/test/java/io/javaoperatorsdk/operator/sample/LeaderElectionE2E.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import io.fabric8.kubernetes.client.KubernetesClient;
2828
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
2929

30+
import javaoperatorsdk.sample.v1.LeaderElection;
31+
3032
import static io.javaoperatorsdk.operator.junit.AbstractOperatorExtension.CRD_READY_WAIT;
3133
import static org.assertj.core.api.Assertions.assertThat;
3234
import static org.awaitility.Awaitility.await;
@@ -61,7 +63,7 @@ void otherInstancesTakesOverWhenSteppingDown(String yamlFilePrefix) {
6163
await().pollDelay(Duration.ofSeconds(MINIMAL_SECONDS_FOR_RENEWAL))
6264
.atMost(Duration.ofSeconds(MAX_WAIT_SECONDS))
6365
.untilAsserted(() -> {
64-
var actualStatus = client.resources(LeaderElectionTestCustomResource.class)
66+
var actualStatus = client.resources(LeaderElection.class)
6567
.inNamespace(namespace).withName(TEST_RESOURCE_NAME).get().getStatus();
6668

6769
assertThat(actualStatus).isNotNull();
@@ -71,14 +73,14 @@ void otherInstancesTakesOverWhenSteppingDown(String yamlFilePrefix) {
7173

7274
client.pods().inNamespace(namespace).withName(OPERATOR_1_POD_NAME).delete();
7375

74-
var actualListSize = client.resources(LeaderElectionTestCustomResource.class)
76+
var actualListSize = client.resources(LeaderElection.class)
7577
.inNamespace(namespace).withName(TEST_RESOURCE_NAME).get().getStatus().getReconciledBy()
7678
.size();
7779

7880
await().pollDelay(Duration.ofSeconds(MINIMAL_SECONDS_FOR_RENEWAL))
7981
.atMost(Duration.ofSeconds(240))
8082
.untilAsserted(() -> {
81-
var actualStatus = client.resources(LeaderElectionTestCustomResource.class)
83+
var actualStatus = client.resources(LeaderElection.class)
8284
.inNamespace(namespace).withName(TEST_RESOURCE_NAME).get().getStatus();
8385

8486
assertThat(actualStatus).isNotNull();
@@ -87,7 +89,7 @@ void otherInstancesTakesOverWhenSteppingDown(String yamlFilePrefix) {
8789
});
8890

8991
assertReconciliations(
90-
client.resources(LeaderElectionTestCustomResource.class).inNamespace(namespace)
92+
client.resources(LeaderElection.class).inNamespace(namespace)
9193
.withName(TEST_RESOURCE_NAME).get().getStatus().getReconciledBy());
9294
}
9395

@@ -104,7 +106,7 @@ private void assertReconciliations(List<String> reconciledBy) {
104106
}
105107

106108
private void applyCustomResource() {
107-
var res = new LeaderElectionTestCustomResource();
109+
var res = new LeaderElection();
108110
res.setMetadata(new ObjectMetaBuilder()
109111
.withName(TEST_RESOURCE_NAME)
110112
.withNamespace(namespace)
@@ -150,7 +152,7 @@ private void deployOperatorsInOrder(String yamlFilePrefix) {
150152

151153
void applyCRD() {
152154
String path =
153-
"./target/classes/META-INF/fabric8/leaderelectiontestcustomresources.sample.javaoperatorsdk-v1.yml";
155+
"./src/main/resources/kubernetes/leaderelections.sample.javaoperatorsdk-v1.yml";
154156
try (InputStream is = new FileInputStream(path)) {
155157
final var crd = client.load(is);
156158
crd.createOrReplace();

0 commit comments

Comments
 (0)