Skip to content

Commit d91f1f7

Browse files
committed
feat: make it possible to not automatically add finalizers
Fixes #415
1 parent 9acf662 commit d91f1f7

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,9 +49,11 @@ 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
4554
- Updated Fabric8 client to version 5.4.0
55+
- It is now possible to configure the controllers to not automatically add finalizers to resources.
56+
See the `Controller` annotation documentation for more details.
4657

4758
#### Overview of the 1.8.0 changes
4859

@@ -82,18 +93,23 @@ the `Namescaped` interface.
8293
## Usage
8394

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

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

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

96111
```xml
112+
97113
<dependency>
98114
<groupId>io.javaoperatorsdk</groupId>
99115
<artifactId>operator-framework</artifactId>
@@ -111,52 +127,59 @@ dependencies {
111127
}
112128
```
113129

114-
Once you've added the dependency, define a main method initializing the Operator and registering a controller.
130+
Once you've added the dependency, define a main method initializing the Operator and registering a
131+
controller.
115132

116133
```java
117134
public class Runner {
118135

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

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

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

142161
A sample custom resource POJO representation
143162

144163
```java
164+
145165
@Group("sample.javaoperatorsdk")
146166
@Version("v1")
147-
public class WebServer extends CustomResource<WebServerSpec, WebServerStatus> implements Namespaced {}
167+
public class WebServer extends CustomResource<WebServerSpec, WebServerStatus> implements
168+
Namespaced {
169+
170+
}
148171

149172
public class WebServerSpec {
150173

151-
private String html;
174+
private String html;
152175

153-
public String getHtml() {
154-
return html;
155-
}
176+
public String getHtml() {
177+
return html;
178+
}
156179

157-
public void setHtml(String html) {
158-
this.html = html;
159-
}
180+
public void setHtml(String html) {
181+
this.html = html;
182+
}
160183
}
161184
```
162185

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

177200
```xml
201+
178202
<dependency>
179203
<groupId>io.fabric8</groupId>
180204
<artifactId>crd-generator-apt</artifactId>
@@ -195,7 +219,8 @@ a `mycrs` plural form will result in 2 files:
195219
196220
### Quarkus
197221

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

200225
Add [this dependency](https://search.maven.org/search?q=a:quarkus-operator-sdk)
201226
to your project:
@@ -205,17 +230,23 @@ to your project:
205230
<dependency>
206231
<groupId>io.quarkiverse.operatorsdk</groupId>
207232
<artifactId>quarkus-operator-sdk</artifactId>
208-
<version>{see https://search.maven.org/search?q=a:quarkus-operator-sdk for latest version}</version>
233+
<version>{see https://search.maven.org/search?q=a:quarkus-operator-sdk for latest version}
234+
</version>
209235
</dependency>
210236
```
211237

212-
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:
238+
Create an Application, Quarkus will automatically create and inject a `KubernetesClient` (
239+
or `OpenShiftClient`), `Operator`, `ConfigurationService` and `ResourceController` instances that
240+
your application can use. Below, you can see the minimal code you need to write to get your operator
241+
and controllers up and running:
213242

214243
```java
244+
215245
@QuarkusMain
216246
public class QuarkusOperator implements QuarkusApplication {
217247

218-
@Inject Operator operator;
248+
@Inject
249+
Operator operator;
219250

220251
public static void main(String... args) {
221252
Quarkus.run(QuarkusOperator.class, args);
@@ -232,49 +263,62 @@ public class QuarkusOperator implements QuarkusApplication {
232263

233264
### Spring Boot
234265

235-
You can also let Spring Boot wire your application together and automatically register the controllers.
266+
You can also let Spring Boot wire your application together and automatically register the
267+
controllers.
236268

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

239272
```xml
273+
240274
<dependency>
241-
<groupId>io.javaoperatorsdk</groupId>
242-
<artifactId>operator-framework-spring-boot-starter</artifactId>
243-
<version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter for latest version}</version>
275+
<groupId>io.javaoperatorsdk</groupId>
276+
<artifactId>operator-framework-spring-boot-starter</artifactId>
277+
<version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter for
278+
latest version}
279+
</version>
244280
</dependency>
245281
```
246282

247283
Create an Application
284+
248285
```java
286+
249287
@SpringBootApplication
250288
public class Application {
251-
public static void main(String[] args) {
252-
SpringApplication.run(Application.class, args);
253-
}
289+
290+
public static void main(String[] args) {
291+
SpringApplication.run(Application.class, args);
292+
}
254293
}
255294
```
256295

257296
#### Spring Boot test support
258297

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

263301
```xml
302+
264303
<dependency>
265-
<groupId>io.javaoperatorsdk</groupId>
266-
<artifactId>operator-framework-spring-boot-starter-test</artifactId>
267-
<version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter for latest version}</version>
304+
<groupId>io.javaoperatorsdk</groupId>
305+
<artifactId>operator-framework-spring-boot-starter-test</artifactId>
306+
<version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter for
307+
latest version}
308+
</version>
268309
</dependency>
269310
```
270311

271312
Mock the operator:
313+
272314
```java
315+
273316
@SpringBootTest
274317
@EnableMockOperator
275318
public class SpringBootStarterSampleApplicationTest {
276319

277320
@Test
278-
void contextLoads() {}
321+
void contextLoads() {
322+
}
279323
}
280324
```

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
@@ -61,4 +61,8 @@ default RetryConfiguration getRetryConfiguration() {
6161
ConfigurationService getConfigurationService();
6262

6363
void setConfigurationService(ConfigurationService service);
64+
65+
default boolean useFinalizer() {
66+
return !Controller.NO_FINALIZER.equals(getFinalizer());
67+
}
6468
}

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)