Skip to content

Commit eb688fb

Browse files
authored
docs: add main docs (#53)
* docs: core docs * wip * wip * wip * wip * wip * wip * fixes * decor
1 parent 40a6af8 commit eb688fb

File tree

5 files changed

+170
-2
lines changed

5 files changed

+170
-2
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ implementing [admission controllers](https://kubernetes.io/docs/reference/access
55
and [conversion hooks](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-conversion)
66
for Kubernetes in Java. Supports both **quarkus** and **spring boot**. Both **sync** and **async** programing model.
77

8+
## Documentation
9+
10+
**For a more detailed documentation check the [docs](docs).**
11+
812
## Sample Usage
913

1014
### Admission Controllers
@@ -15,7 +19,7 @@ Defining a mutation or validation controller is simple as:
1519

1620
@Singleton
1721
@Named(MUTATING_CONTROLLER)
18-
public AdmissionController<Pod> mutatingController() {
22+
public AdmissionController<Ingress> mutatingController() {
1923
return new AdmissionController<>((resource, operation) -> {
2024
if (resource.getMetadata().getLabels() == null) {
2125
resource.getMetadata().setLabels(new HashMap<>());
@@ -27,7 +31,7 @@ Defining a mutation or validation controller is simple as:
2731

2832
@Singleton
2933
@Named(VALIDATING_CONTROLLER)
30-
public AdmissionController<Pod> validatingController() {
34+
public AdmissionController<Ingress> validatingController() {
3135
return new AdmissionController<>((resource, operation) -> {
3236
if (resource.getMetadata().getLabels() == null
3337
|| resource.getMetadata().getLabels().get(APP_NAME_LABEL_KEY) == null) {

core/src/main/java/io/javaoperatorsdk/webhook/admission/mutation/Mutator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
import io.javaoperatorsdk.webhook.admission.NotAllowedException;
55
import io.javaoperatorsdk.webhook.admission.Operation;
66

7+
/**
8+
* Any change made on the resource will be reflected in the response.
9+
*
10+
* @param <T> type of Kubernetes resources
11+
*/
712
public interface Mutator<T extends KubernetesResource> {
813

914
T mutate(T resource, Operation operation) throws NotAllowedException;

docs/README.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Kubernetes Webhooks Framework Documentation
2+
3+
## Intro
4+
5+
Kubernetes Webhooks Framework makes it simple to
6+
implementing [admission controllers](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/)
7+
and [conversion hooks](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-conversion)
8+
for Kubernetes in Java.
9+
10+
## Getting Started
11+
12+
Before you start make sure you understand these concepts in Kubernetes, reading the docs mentioned above.
13+
14+
### Samples
15+
16+
There are samples both
17+
for [Spring Boot](https://github.com/java-operator-sdk/admission-controller-framework/tree/main/samples/spring-boot)
18+
and [Quarkus](https://github.com/java-operator-sdk/kubernetes-webooks-framework/tree/main/samples/quarkus), both of them
19+
implements the same logic. Both sync and async APIs
20+
are showcased. This documentation describes the Quarkus version, however Spring Boot version is almost identical.
21+
22+
There are two endpoint, one
23+
for [admission controllers](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/sample/admission/AdmissionEndpoint.java)
24+
(a validating and a mutating) and one for the
25+
sample [conversion hook](https://github.com/java-operator-sdk/admission-controller-framework/blob/76fd9c4b9fef6738310a7dd97b159c3668ced9f1/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/sample/conversion/ConversionEndpoint.java)
26+
.
27+
28+
Starting from those endpoints, it should be trivial to understand how the underlying logic works.
29+
30+
### End-To-End Tests
31+
32+
The goal of the end-to-end tests is to test the framework in a production like environment, but also works as an
33+
executable documentation to guide developers how to deploy and configure the target service.
34+
35+
The [end-to-end tests](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/sample/QuarkusWebhooksE2E.java)
36+
are using the [same test cases](https://github.com/java-operator-sdk/admission-controller-framework/blob/de2b0da7f592aa166049ef7ad65bcebf8d45e358/samples/commons/src/test/java/io/javaoperatorsdk/webhook/sample/EndToEndTestBase.java) and are based on the samples (See Spring Boot
37+
version [here](https://github.com/java-operator-sdk/admission-controller-framework/blob/e2637a90152bebfca2983ba17268c1f7ec7e9602/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/SpringBootWebhooksE2E.java)).
38+
To see how those tests are executed during a pull request check
39+
the [related GitHub Action](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/.github/workflows/pr.yml#L66-L66)
40+
41+
The samples are first built, then [deployed](https://github.com/java-operator-sdk/admission-controller-framework/blob/6959de06c0de1c8e04fc241ea5f4196219002e53/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/sample/QuarkusWebhooksE2E.java#L23-L30) to a local Kubernetes cluster (in our case minikube is used).
42+
For Quarkus most of the deployment artifacts is generated using extensions (works similarly for Spring Boot,
43+
using [dekorate](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/samples/spring-boot/pom.xml#L52-L63)):
44+
45+
```xml
46+
47+
<dependency>
48+
<groupId>io.quarkus</groupId>
49+
<artifactId>quarkus-kubernetes</artifactId>
50+
</dependency>
51+
<dependency>
52+
<groupId>io.quarkiverse.certmanager</groupId>
53+
<artifactId>quarkus-certmanager</artifactId>
54+
</dependency>
55+
```
56+
57+
Only additional resources used for admission hooks, are present in
58+
the [k8s](https://github.com/java-operator-sdk/admission-controller-framework/tree/main/samples/quarkus/k8s)
59+
directory. These are the configuration files to configure the admission hooks. For example the configuration for
60+
validation look like:
61+
62+
```yaml
63+
64+
apiVersion: admissionregistration.k8s.io/v1
65+
kind: ValidatingWebhookConfiguration
66+
metadata:
67+
name: "validating.quarkus.example.com"
68+
annotations:
69+
# Cert Manager annotation to inject CA
70+
cert-manager.io/inject-ca-from: default/quarkus-sample
71+
webhooks:
72+
- name: "validating.quarkus.example.com"
73+
rules:
74+
- apiGroups: [ "networking.k8s.io" ]
75+
apiVersions: [ "v1" ]
76+
operations: [ "*" ]
77+
resources: [ "ingresses" ]
78+
scope: "Namespaced"
79+
clientConfig:
80+
service:
81+
namespace: "default"
82+
name: "quarkus-sample"
83+
path: "/validate"
84+
port: 443
85+
admissionReviewVersions: [ "v1" ]
86+
sideEffects: None
87+
timeoutSeconds: 5
88+
```
89+
90+
The conversion hook is configured within the `CustomResourceDefinition`, see
91+
related [Kubernetes docs](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#configure-customresourcedefinition-to-use-conversion-webhooks).
92+
Since this is [not yet supported](https://github.com/fabric8io/kubernetes-client/issues/4692) by the fabric8 client CRD
93+
generator, the hook definition is
94+
[added before](https://github.com/java-operator-sdk/admission-controller-framework/blob/e2637a90152bebfca2983ba17268c1f7ec7e9602/samples/commons/src/test/java/io/javaoperatorsdk/webhook/sample/EndToEndTestBase.java#L97-L124) CRD is applied.
95+
96+
Note
97+
that [cert manager](https://github.com/java-operator-sdk/admission-controller-framework/blob/e2637a90152bebfca2983ba17268c1f7ec7e9602/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/sample/QuarkusWebhooksE2E.java#L19-L23)
98+
is used to generate certificates for the application and for configurations.
99+
100+
## Admission Controllers API
101+
102+
There are two types of admission controllers: validation and mutation. Both should be extremely simple to use.
103+
104+
To create the related controller simply pass a lambda to the constructor
105+
of [AdmissionController](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/core/src/main/java/io/javaoperatorsdk/webhook/admission/AdmissionController.java#L104-L104)
106+
that validates the resource. (See also
107+
the [async version](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/core/src/main/java/io/javaoperatorsdk/webhook/admission/AsyncAdmissionController.java#L104-L104)
108+
of admission controller implementation.)
109+
110+
```java
111+
new AdmissionController<>((resource,operation) -> {
112+
if(resource.getMetadata().getLabels() == null || resource.getMetadata().getLabels().get(APP_NAME_LABEL_KEY) == null){
113+
throw new NotAllowedException("Missing label: "+APP_NAME_LABEL_KEY);
114+
}
115+
});
116+
```
117+
118+
respectively mutates it:
119+
120+
```java
121+
new AdmissionController<>((resource,operation) -> {
122+
if(resource.getMetadata().getLabels() == null){
123+
resource.getMetadata().setLabels(new HashMap<>());
124+
}
125+
resource.getMetadata().getLabels().putIfAbsent(APP_NAME_LABEL_KEY,"mutation-test");
126+
return resource;
127+
});
128+
```
129+
130+
All changes made to the resource are reflected in the response created by the admission controller.
131+
132+
## Conversion Hooks API
133+
134+
[ConversionController](https://github.com/java-operator-sdk/admission-controller-framework/blob/core/src/main/java/io/javaoperatorsdk/webhook/conversion/ConversionController.java) (
135+
respectively [AsyncConversionController](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/core/src/main/java/io/javaoperatorsdk/webhook/conversion/AsyncConversionController.java))
136+
handles conversion between different versions of custom resources
137+
using [mappers](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/core/src/main/java/io/javaoperatorsdk/webhook/conversion/Mapper.java)
138+
( respectively [async mappers](https://github.com/java-operator-sdk/admission-controller-framework/blob/main/core/src/main/java/io/javaoperatorsdk/webhook/conversion/AsyncMapper.java)).
139+
140+
The mapper interface is simple:
141+
142+
```java
143+
public interface Mapper<R extends HasMetadata, HUB> {
144+
145+
HUB toHub(R resource);
146+
147+
R fromHub(HUB hub);
148+
149+
}
150+
```
151+
152+
It handles mapping to and from a Hub. Hub is an intermediate representation in a conversion. Thus, the conversion
153+
steps from v1 to v2 happens in the following way: v1 -> HUB -> v2. Using the provided v1 and v2 mappers implementations.
154+
Having this approach is useful mainly in case there are more than two version of resources on the cluster, so there is
155+
no need for a mapper for every combination. See also related docs in
156+
[Kubebuilder](https://book.kubebuilder.io/multiversion-tutorial/conversion-concepts.html).

samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/AdmissionControllers.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class AdmissionControllers {
1717
public static final String VALIDATION_TARGET_LABEL = "app.kubernetes.io/name";
1818
public static final String MUTATION_TARGET_LABEL = "app.kubernetes.io/id";
1919

20+
// adds a label to the target resource
2021
public static AdmissionController<Ingress> mutatingController() {
2122
return new AdmissionController<>((resource, operation) -> {
2223
if (resource.getMetadata().getLabels() == null) {
@@ -27,6 +28,7 @@ public static AdmissionController<Ingress> mutatingController() {
2728
});
2829
}
2930

31+
// validates if a resource contains the target label
3032
public static AdmissionController<Ingress> validatingController() {
3133
return new AdmissionController<>((resource, operation) -> {
3234
if (resource.getMetadata().getLabels() == null

samples/quarkus/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
<groupId>org.jboss.resteasy</groupId>
8383
<artifactId>resteasy-jackson2-provider</artifactId>
8484
</dependency>
85+
<!-- used to generate Kubernetes resources -->
8586
<dependency>
8687
<groupId>io.quarkus</groupId>
8788
<artifactId>quarkus-kubernetes</artifactId>

0 commit comments

Comments
 (0)