Skip to content

Commit e075efb

Browse files
committed
Merge branch 'master' into user-guide
2 parents e610da6 + 765d651 commit e075efb

File tree

52 files changed

+826
-408
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+826
-408
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
strategy:
1212
matrix:
13-
java: [8, 11]
13+
java: [8, 11, 14]
1414
steps:
1515
- uses: actions/checkout@v2
1616
- uses: actions/cache@v2

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
![Java CI with Maven](https://github.com/ContainerSolutions/java-operator-sdk/workflows/Java%20CI%20with%20Maven/badge.svg)
33

44
SDK for building Kubernetes Operators in Java. Inspired by [operator-sdk](https://github.com/operator-framework/operator-sdk).
5-
In this first iteration we aim to provide a framework which handles the reconciliation loop by dispatching events to
6-
a Controller written by the user of the framework.
7-
8-
The Controller only contains the logic to create, update and delete the actual resources related to the CRD.
5+
User (you) only writes the logic in a Controller that creates/updates or deletes resources related to a custom resource.
6+
All the issues around are handled by the framework for you.
7+
Check out this [blog post](https://blog.container-solutions.com/a-deep-dive-into-the-java-operator-sdk)
8+
about the non-trivial yet common problems needs to be solved for every operator.
99

1010
## Join us on Discord!
1111

@@ -48,7 +48,7 @@ public class Runner {
4848

4949
public static void main(String[] args) {
5050
Operator operator = new Operator(new DefaultKubernetesClient());
51-
operator.registerController(new CustomServiceController());
51+
operator.registerController(new WebServerController());
5252
}
5353
}
5454
```
@@ -61,16 +61,16 @@ The Controller implements the business logic and describes all the classes neede
6161
public class WebServerController implements ResourceController<WebServer> {
6262

6363
@Override
64-
public boolean deleteResource(CustomService resource) {
64+
public boolean deleteResource(CustomService resource, Context<WebServer> context) {
6565
// ... your logic ...
6666
return true;
6767
}
6868

6969
// Return the changed resource, so it gets updated. See javadoc for details.
7070
@Override
71-
public Optional<CustomService> createOrUpdateResource(CustomService resource) {
71+
public UpdateControl<CustomService> createOrUpdateResource(CustomService resource, Context<WebServer> context) {
7272
// ... your logic ...
73-
return resource;
73+
return UpdateControl.updateStatusSubResource(resource);
7474
}
7575
}
7676
```
@@ -139,7 +139,7 @@ public class Application {
139139
}
140140
```
141141

142-
And add Spring's `@Service` annotation to your controller classes so they will be automatically registered as resource controllers.
142+
add Spring's `@Service` annotation to your controller classes so they will be automatically registered as resource controllers.
143143

144144
The Operator's Spring Boot integration leverages [Spring's configuration mechanisms](https://docs.spring.io/spring-boot/docs/1.0.1.RELEASE/reference/html/boot-features-external-config.html) to configure
145145
- [The Kubernetes client](spring-boot-starter/src/main/java/com/github/containersolutions/operator/spingboot/starter/OperatorProperties.java)

operator-framework/pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<parent>
77
<groupId>com.github.containersolutions</groupId>
88
<artifactId>java-operator-sdk</artifactId>
9-
<version>1.2.3-SNAPSHOT</version>
9+
<version>1.3.1-SNAPSHOT</version>
1010
</parent>
1111

1212
<artifactId>operator-framework</artifactId>
@@ -54,19 +54,19 @@
5454
<dependency>
5555
<groupId>org.apache.logging.log4j</groupId>
5656
<artifactId>log4j-slf4j-impl</artifactId>
57-
<version>2.11.2</version>
57+
<version>2.13.3</version>
5858
<scope>test</scope>
5959
</dependency>
6060
<dependency>
6161
<groupId>org.assertj</groupId>
6262
<artifactId>assertj-core</artifactId>
63-
<version>3.4.1</version>
63+
<version>3.16.1</version>
6464
<scope>test</scope>
6565
</dependency>
6666
<dependency>
6767
<groupId>org.awaitility</groupId>
6868
<artifactId>awaitility</artifactId>
69-
<version>4.0.1</version>
69+
<version>4.0.3</version>
7070
<scope>test</scope>
7171
</dependency>
7272
<dependency>

operator-framework/src/main/java/com/github/containersolutions/operator/ControllerUtils.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import java.util.Map;
1414

1515

16-
class ControllerUtils {
16+
public class ControllerUtils {
1717

1818
private final static double JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version"));
1919

@@ -78,4 +78,11 @@ static String getCrdName(ResourceController controller) {
7878
private static Controller getAnnotation(ResourceController controller) {
7979
return controller.getClass().getAnnotation(Controller.class);
8080
}
81+
82+
public static boolean hasDefaultFinalizer(CustomResource resource, String finalizer) {
83+
if (resource.getMetadata().getFinalizers() != null) {
84+
return resource.getMetadata().getFinalizers().contains(finalizer);
85+
}
86+
return false;
87+
}
8188
}

operator-framework/src/main/java/com/github/containersolutions/operator/Operator.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@ private <R extends CustomResource> void registerController(ResourceController<R>
5656
Class<R> resClass = getCustomResourceClass(controller);
5757
CustomResourceDefinition crd = getCustomResourceDefinitionForController(controller);
5858
KubernetesDeserializer.registerCustomKind(getApiVersion(crd), getKind(crd), resClass);
59-
59+
String finalizer = getDefaultFinalizer(controller);
6060
MixedOperation client = k8sClient.customResources(crd, resClass, CustomResourceList.class, getCustomResourceDoneableClass(controller));
6161
EventDispatcher eventDispatcher = new EventDispatcher(controller,
62-
getDefaultFinalizer(controller), new EventDispatcher.CustomResourceReplaceFacade(client));
63-
EventScheduler eventScheduler = new EventScheduler(eventDispatcher, retry, ControllerUtils.getGenerationEventProcessing(controller));
62+
finalizer, new EventDispatcher.CustomResourceFacade(client), ControllerUtils.getGenerationEventProcessing(controller));
63+
EventScheduler eventScheduler = new EventScheduler(eventDispatcher, retry);
6464
registerWatches(controller, client, resClass, watchAllNamespaces, targetNamespaces, eventScheduler);
6565
}
6666

67+
6768
private <R extends CustomResource> void registerWatches(ResourceController<R> controller, MixedOperation client,
6869
Class<R> resClass,
6970
boolean watchAllNamespaces, String[] targetNamespaces, EventScheduler eventScheduler) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.github.containersolutions.operator.api;
2+
3+
import io.fabric8.kubernetes.client.CustomResource;
4+
5+
public interface Context<T extends CustomResource> {
6+
7+
RetryInfo retryInfo();
8+
9+
}

operator-framework/src/main/java/com/github/containersolutions/operator/api/Controller.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
String finalizerName() default DEFAULT_FINALIZER;
2121

2222
/**
23-
* If true, will process new event only if generation increased since the last processing, otherwise will
23+
* If true, will dispatch new event to the controller if generation increased since the last processing, otherwise will
2424
* process all events.
2525
* See generation meta attribute
2626
* <a href="https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#status-subresource">here</a>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.github.containersolutions.operator.api;
2+
3+
import io.fabric8.kubernetes.client.CustomResource;
4+
5+
public class DefaultContext<T extends CustomResource> implements Context<T> {
6+
7+
private final RetryInfo retryInfo;
8+
9+
public DefaultContext(RetryInfo retryInfo) {
10+
this.retryInfo = retryInfo;
11+
}
12+
13+
@Override
14+
public RetryInfo retryInfo() {
15+
return retryInfo;
16+
}
17+
}

operator-framework/src/main/java/com/github/containersolutions/operator/api/ResourceController.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import io.fabric8.kubernetes.client.CustomResource;
44

5-
import java.util.Optional;
6-
75
public interface ResourceController<R extends CustomResource> {
86

97
/**
@@ -17,7 +15,7 @@ public interface ResourceController<R extends CustomResource> {
1715
* @return true - so the finalizer is automatically removed after the call.
1816
* false if you don't want to remove the finalizer. Note that this is ALMOST NEVER the case.
1917
*/
20-
boolean deleteResource(R resource);
18+
boolean deleteResource(R resource, Context<R> context);
2119

2220
/**
2321
* The implementation of this operation is required to be idempotent.
@@ -28,6 +26,6 @@ public interface ResourceController<R extends CustomResource> {
2826
* this update can be skipped.
2927
* <b>However we will always call an update if there is no finalizer on object and its not marked for deletion.</b>
3028
*/
31-
Optional<R> createOrUpdateResource(R resource);
29+
UpdateControl createOrUpdateResource(R resource, Context<R> context);
3230

3331
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.github.containersolutions.operator.api;
2+
3+
public class RetryInfo {
4+
5+
private int retryNumber;
6+
private boolean lastAttempt;
7+
8+
public RetryInfo(int retryNumber, boolean lastAttempt) {
9+
this.retryNumber = retryNumber;
10+
this.lastAttempt = lastAttempt;
11+
}
12+
13+
public int getRetryNumber() {
14+
return retryNumber;
15+
}
16+
17+
public boolean isLastAttempt() {
18+
return lastAttempt;
19+
}
20+
}

0 commit comments

Comments
 (0)