Skip to content

Commit 6c8ab47

Browse files
committed
feat: make it possible to not automatically add finalizers
Fixes #415
1 parent 2818b49 commit 6c8ab47

File tree

7 files changed

+205
-108
lines changed

7 files changed

+205
-108
lines changed

README.md

Lines changed: 97 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
# ![java-operator-sdk](docs/assets/images/logo.png)
1+
# ![java-operator-sdk](docs/assets/images/logo.png)
2+
23
![Java CI with Maven](https://github.com/java-operator-sdk/java-operator-sdk/workflows/Java%20CI%20with%20Maven/badge.svg)
34
[![Discord](https://img.shields.io/discord/723455000604573736.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.com/channels/723455000604573736)
45

5-
Build Kubernetes Operators in Java without hassle. Inspired by [operator-sdk](https://github.com/operator-framework/operator-sdk).
6-
6+
Build Kubernetes Operators in Java without hassle. Inspired
7+
by [operator-sdk](https://github.com/operator-framework/operator-sdk).
8+
79

810
Table of Contents
911
==========
@@ -15,17 +17,24 @@ Table of Contents
1517
1. [Usage](#Usage)
1618

1719
## Features
20+
1821
* Framework for handling Kubernetes API events
1922
* Automatic registration of Custom Resource watches
2023
* Retry action on failure
2124
* Smart event scheduling (only handle the latest event for the same resource)
2225

23-
Check out this [blog post](https://csviri.medium.com/deep-dive-building-a-kubernetes-operator-sdk-for-java-developers-5008218822cb)
24-
about the non-trivial yet common problems needed to be solved for every operator. In case you are interested how to
25-
handle more complex scenarios take a look on [event sources](https://csviri.medium.com/java-operator-sdk-introduction-to-event-sources-a1aab5af4b7b).
26+
Check out
27+
this [blog post](https://csviri.medium.com/deep-dive-building-a-kubernetes-operator-sdk-for-java-developers-5008218822cb)
28+
about the non-trivial yet common problems needed to be solved for every operator. In case you are
29+
interested how to handle more complex scenarios take a look
30+
on [event sources](https://csviri.medium.com/java-operator-sdk-introduction-to-event-sources-a1aab5af4b7b)
31+
.
2632

2733
## Why build your own Operator?
28-
* Infrastructure automation using the power and flexibility of Java. See [blog post](https://blog.container-solutions.com/cloud-native-java-infrastructure-automation-with-kubernetes-operators).
34+
35+
* Infrastructure automation using the power and flexibility of Java.
36+
See [blog post](https://blog.container-solutions.com/cloud-native-java-infrastructure-automation-with-kubernetes-operators)
37+
.
2938
* Provisioning of complex applications - avoiding Helm chart hell
3039
* Integration with Cloud services - e.g. Secret stores
3140
* Safer deployment of applications - only expose cluster to users by Custom Resources
@@ -40,8 +49,10 @@ handle more complex scenarios take a look on [event sources](https://csviri.medi
4049
#### Overview of the 1.9.0 changes
4150

4251
- The Spring Boot starters have been moved to their own repositories and are now found at:
43-
- https://github.com/java-operator-sdk/operator-framework-spring-boot-starter
44-
- https://github.com/java-operator-sdk/operator-framework-spring-boot-starter-test
52+
- https://github.com/java-operator-sdk/operator-framework-spring-boot-starter
53+
- https://github.com/java-operator-sdk/operator-framework-spring-boot-starter-test
54+
- It is now possible to configure the controllers to not automatically add finalizers to resources.
55+
See the `Controller` annotation documentation for more details.
4556

4657
#### Overview of the 1.8.0 changes
4758

@@ -81,18 +92,23 @@ the `Namescaped` interface.
8192
## Usage
8293

8394
We have several sample Operators under the [samples](samples) directory:
84-
* *pure-java*: Minimal Operator implementation which only parses the Custom Resource and prints to stdout.
85-
Implemented with and without Spring Boot support. The two samples share the common module.
95+
96+
* *pure-java*: Minimal Operator implementation which only parses the Custom Resource and prints to
97+
stdout. Implemented with and without Spring Boot support. The two samples share the common module.
8698
* *spring-boot-plain*: Sample showing integration with Spring Boot.
8799

88-
There are also more samples in the standalone [samples repo](https://github.com/java-operator-sdk/samples):
89-
* *webserver*: Simple example creating an NGINX webserver from a Custom Resource containing HTML code.
100+
There are also more samples in the
101+
standalone [samples repo](https://github.com/java-operator-sdk/samples):
102+
103+
* *webserver*: Simple example creating an NGINX webserver from a Custom Resource containing HTML
104+
code.
90105
* *mysql-schema*: Operator managing schemas in a MySQL database.
91106
* *tomcat*: Operator with two controllers, managing Tomcat instances and Webapps for these.
92107

93108
Add [dependency](https://search.maven.org/search?q=a:operator-framework) to your project with Maven:
94109

95110
```xml
111+
96112
<dependency>
97113
<groupId>io.javaoperatorsdk</groupId>
98114
<artifactId>operator-framework</artifactId>
@@ -110,52 +126,59 @@ dependencies {
110126
}
111127
```
112128

113-
Once you've added the dependency, define a main method initializing the Operator and registering a controller.
129+
Once you've added the dependency, define a main method initializing the Operator and registering a
130+
controller.
114131

115132
```java
116133
public class Runner {
117134

118-
public static void main(String[] args) {
119-
Operator operator = new Operator(new DefaultKubernetesClient(),
120-
DefaultConfigurationService.instance());
121-
operator.register(new WebServerController());
122-
}
135+
public static void main(String[] args) {
136+
Operator operator = new Operator(new DefaultKubernetesClient(),
137+
DefaultConfigurationService.instance());
138+
operator.register(new WebServerController());
139+
}
123140
}
124141
```
125142

126143
The Controller implements the business logic and describes all the classes needed to handle the CRD.
127144

128145
```java
146+
129147
@Controller
130148
public class WebServerController implements ResourceController<WebServer> {
131-
132-
// Return the changed resource, so it gets updated. See javadoc for details.
133-
@Override
134-
public UpdateControl<CustomService> createOrUpdateResource(CustomService resource, Context<WebServer> context) {
135-
// ... your logic ...
136-
return UpdateControl.updateStatusSubResource(resource);
137-
}
149+
150+
// Return the changed resource, so it gets updated. See javadoc for details.
151+
@Override
152+
public UpdateControl<CustomService> createOrUpdateResource(CustomService resource,
153+
Context<WebServer> context) {
154+
// ... your logic ...
155+
return UpdateControl.updateStatusSubResource(resource);
156+
}
138157
}
139158
```
140159

141160
A sample custom resource POJO representation
142161

143162
```java
163+
144164
@Group("sample.javaoperatorsdk")
145165
@Version("v1")
146-
public class WebServer extends CustomResource<WebServerSpec, WebServerStatus> implements Namespaced {}
166+
public class WebServer extends CustomResource<WebServerSpec, WebServerStatus> implements
167+
Namespaced {
168+
169+
}
147170

148171
public class WebServerSpec {
149172

150-
private String html;
173+
private String html;
151174

152-
public String getHtml() {
153-
return html;
154-
}
175+
public String getHtml() {
176+
return html;
177+
}
155178

156-
public void setHtml(String html) {
157-
this.html = html;
158-
}
179+
public void setHtml(String html) {
180+
this.html = html;
181+
}
159182
}
160183
```
161184

@@ -174,6 +197,7 @@ To automatically generate CRD manifests from your annotated Custom Resource clas
174197
to add the following dependencies to your project:
175198

176199
```xml
200+
177201
<dependency>
178202
<groupId>io.fabric8</groupId>
179203
<artifactId>crd-generator-apt</artifactId>
@@ -194,7 +218,8 @@ a `mycrs` plural form will result in 2 files:
194218
195219
### Quarkus
196220

197-
A [Quarkus](https://quarkus.io) extension is also provided to ease the development of Quarkus-based operators.
221+
A [Quarkus](https://quarkus.io) extension is also provided to ease the development of Quarkus-based
222+
operators.
198223

199224
Add [this dependency](https://search.maven.org/search?q=a:quarkus-operator-sdk)
200225
to your project:
@@ -204,17 +229,23 @@ to your project:
204229
<dependency>
205230
<groupId>io.quarkiverse.operatorsdk</groupId>
206231
<artifactId>quarkus-operator-sdk</artifactId>
207-
<version>{see https://search.maven.org/search?q=a:quarkus-operator-sdk for latest version}</version>
232+
<version>{see https://search.maven.org/search?q=a:quarkus-operator-sdk for latest version}
233+
</version>
208234
</dependency>
209235
```
210236

211-
Create an Application, Quarkus will automatically create and inject a `KubernetesClient` (or `OpenShiftClient`), `Operator`, `ConfigurationService` and `ResourceController` instances that your application can use. Below, you can see the minimal code you need to write to get your operator and controllers up and running:
237+
Create an Application, Quarkus will automatically create and inject a `KubernetesClient` (
238+
or `OpenShiftClient`), `Operator`, `ConfigurationService` and `ResourceController` instances that
239+
your application can use. Below, you can see the minimal code you need to write to get your operator
240+
and controllers up and running:
212241

213242
```java
243+
214244
@QuarkusMain
215245
public class QuarkusOperator implements QuarkusApplication {
216246

217-
@Inject Operator operator;
247+
@Inject
248+
Operator operator;
218249

219250
public static void main(String... args) {
220251
Quarkus.run(QuarkusOperator.class, args);
@@ -231,49 +262,62 @@ public class QuarkusOperator implements QuarkusApplication {
231262

232263
### Spring Boot
233264

234-
You can also let Spring Boot wire your application together and automatically register the controllers.
265+
You can also let Spring Boot wire your application together and automatically register the
266+
controllers.
235267

236-
Add [this dependency](https://search.maven.org/search?q=a:operator-framework-spring-boot-starter) to your project:
268+
Add [this dependency](https://search.maven.org/search?q=a:operator-framework-spring-boot-starter) to
269+
your project:
237270

238271
```xml
272+
239273
<dependency>
240-
<groupId>io.javaoperatorsdk</groupId>
241-
<artifactId>operator-framework-spring-boot-starter</artifactId>
242-
<version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter for latest version}</version>
274+
<groupId>io.javaoperatorsdk</groupId>
275+
<artifactId>operator-framework-spring-boot-starter</artifactId>
276+
<version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter for
277+
latest version}
278+
</version>
243279
</dependency>
244280
```
245281

246282
Create an Application
283+
247284
```java
285+
248286
@SpringBootApplication
249287
public class Application {
250-
public static void main(String[] args) {
251-
SpringApplication.run(Application.class, args);
252-
}
288+
289+
public static void main(String[] args) {
290+
SpringApplication.run(Application.class, args);
291+
}
253292
}
254293
```
255294

256295
#### Spring Boot test support
257296

258-
Adding the following dependency would let you mock the operator for the
259-
tests where loading the spring container is necessary,
260-
but it doesn't need real access to a Kubernetes cluster.
297+
Adding the following dependency would let you mock the operator for the tests where loading the
298+
spring container is necessary, but it doesn't need real access to a Kubernetes cluster.
261299

262300
```xml
301+
263302
<dependency>
264-
<groupId>io.javaoperatorsdk</groupId>
265-
<artifactId>operator-framework-spring-boot-starter-test</artifactId>
266-
<version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter for latest version}</version>
303+
<groupId>io.javaoperatorsdk</groupId>
304+
<artifactId>operator-framework-spring-boot-starter-test</artifactId>
305+
<version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter for
306+
latest version}
307+
</version>
267308
</dependency>
268309
```
269310

270311
Mock the operator:
312+
271313
```java
314+
272315
@SpringBootTest
273316
@EnableMockOperator
274317
public class SpringBootStarterSampleApplicationTest {
275318

276319
@Test
277-
void contextLoads() {}
320+
void contextLoads() {
321+
}
278322
}
279323
```

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/Controller.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111

1212
String NULL = "";
1313
String WATCH_CURRENT_NAMESPACE = "JOSDK_WATCH_CURRENT";
14+
String NO_FINALIZER = "JOSDK_NO_FINALIZER";
1415

1516
String name() default NULL;
1617

1718
/**
18-
* Optional finalizer name, if it is not, the crdName will be used as the name of the finalizer
19-
* too.
19+
* Optional finalizer name, if it is not provided, one will be automatically generated. If the
20+
* provided value is the value specified by {@link #NO_FINALIZER}, then no finalizer will be added
21+
* to custom resources.
2022
*
2123
* @return the finalizer name
2224
*/

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ResourceController.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,21 @@ public interface ResourceController<R extends CustomResource> {
99
* The implementation should delete the associated component(s). Note that this is method is
1010
* called when an object is marked for deletion. After it's executed the custom resource finalizer
1111
* is automatically removed by the framework; unless the return value is {@link
12-
* DeleteControl#NO_FINALIZER_REMOVAL} - note that this is almost never the case. It's important
13-
* to have the implementation also idempotent, in the current implementation to cover all edge
14-
* cases actually will be executed mostly twice.
12+
* DeleteControl#NO_FINALIZER_REMOVAL}, which indicates that the controller has determined that
13+
* the resource should not be deleted yet, in which case it is up to the controller to restore the
14+
* resource's status so that it's not marked for deletion anymore.
15+
*
16+
* <p>It's important that this method be idempotent, as it could be called several times,
17+
* depending on the conditions and the controller's configuration (for example, if the controller
18+
* is configured to not use a finalizer but the resource does have finalizers, it might be be
19+
* "offered" again for deletion several times until the finalizers are all removed.
1520
*
1621
* @param resource the resource that is marked for deletion
1722
* @param context the context with which the operation is executed
1823
* @return {@link DeleteControl#DEFAULT_DELETE} - so the finalizer is automatically removed after
1924
* the call. {@link DeleteControl#NO_FINALIZER_REMOVAL} if you don't want to remove the
20-
* finalizer. Note that this is ALMOST NEVER the case.
25+
* finalizer to indicate that the resource should not be deleted after all, in which case the
26+
* controller should restore the resource's state appropriately.
2127
*/
2228
default DeleteControl deleteResource(R resource, Context<R> context) {
2329
return DeleteControl.DEFAULT_DELETE;

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,8 @@ default RetryConfiguration getRetryConfiguration() {
5757
ConfigurationService getConfigurationService();
5858

5959
void setConfigurationService(ConfigurationService service);
60+
61+
default boolean useFinalizer() {
62+
return !Controller.NO_FINALIZER.equals(getFinalizer());
63+
}
6064
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/DefaultEventHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public class DefaultEventHandler implements EventHandler {
4848
public DefaultEventHandler(
4949
ResourceController controller, ControllerConfiguration configuration, MixedOperation client) {
5050
this(
51-
new EventDispatcher(controller, configuration.getFinalizer(), client),
51+
new EventDispatcher(controller, configuration, client),
5252
configuration.getName(),
5353
GenericRetry.fromConfiguration(configuration.getRetryConfiguration()),
5454
configuration.getConfigurationService().concurrentReconciliationThreads());

0 commit comments

Comments
 (0)