diff --git a/.github/workflows/master-snapshot-release.yml b/.github/workflows/master-snapshot-release.yml
index 67d63ef2..566a3d6b 100644
--- a/.github/workflows/master-snapshot-release.yml
+++ b/.github/workflows/master-snapshot-release.yml
@@ -27,7 +27,7 @@ jobs:
cache: 'maven'
- name: Run unit tests
run: ./mvnw ${MAVEN_ARGS} -B test --file pom.xml
- - name: Run integration tests
+ - name: Package
run: ./mvnw ${MAVEN_ARGS} -B package --file pom.xml
release-snapshot:
runs-on: ubuntu-latest
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 89729ae3..a703cc67 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -31,7 +31,7 @@ jobs:
./mvnw ${MAVEN_ARGS} impsort:check --file pom.xml
- name: Run unit tests
run: ./mvnw ${MAVEN_ARGS} -B test --file pom.xml
- spring-boot-integration-test:
+ spring-boot-e2e-tests:
runs-on: ubuntu-latest
needs: build
strategy:
@@ -46,59 +46,50 @@ jobs:
distribution: ${{ matrix.distribution }}
java-version: ${{ matrix.java }}
cache: 'maven'
- - name: Build
- run: ./mvnw ${MAVEN_ARGS} clean install -DskipTests
- - name: Kubernetes KinD Cluster
- uses: container-tools/kind-action@v1
+ - name: Setup Minikube-Kubernetes
+ uses: manusa/actions-setup-minikube@v2.7.1
with:
- version: v0.11.1
- registry: true
- - name: Install Cert-Manager
+ minikube version: v1.25.2
+ kubernetes version: v1.23.6
+ github token: ${{ secrets.GITHUB_TOKEN }}
+ driver: docker
+ - name: Run E2E Test
run: |
- OS=$(go env GOOS); ARCH=$(go env GOARCH); curl -sSL -o kubectl-cert-manager.tar.gz https://github.com/cert-manager/cert-manager/releases/download/v1.7.2/kubectl-cert_manager-$OS-$ARCH.tar.gz
- tar xzf kubectl-cert-manager.tar.gz
- sudo mv kubectl-cert_manager /usr/local/bin
- kubectl cert-manager x install
- - name: Run Integration Test
+ set -x
+ eval $(minikube -p minikube docker-env)
+ ./mvnw ${MAVEN_ARGS} clean install -DskipTests
+ cd samples/spring-boot
+ pwd
+ ./mvnw ${MAVEN_ARGS} jib:dockerBuild -DskipTests
+ ./mvnw ${MAVEN_ARGS} test -Pend-to-end-tests
+
+ quarkus-e2e-tests:
+ runs-on: ubuntu-latest
+ needs: build
+ strategy:
+ matrix:
+ java: [ 11 ]
+ distribution: [ temurin ]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Java and Maven
+ uses: actions/setup-java@v2
+ with:
+ distribution: ${{ matrix.distribution }}
+ java-version: ${{ matrix.java }}
+ cache: 'maven'
+ - name: Setup Minikube-Kubernetes
+ uses: manusa/actions-setup-minikube@v2.7.1
+ with:
+ minikube version: v1.25.2
+ kubernetes version: v1.23.6
+ github token: ${{ secrets.GITHUB_TOKEN }}
+ driver: docker
+ - name: Run E2E Test
run: |
set -x
-
- # Create namespace
- kubectl create namespace test
- kubectl config set-context --current --namespace=test
-
- # Generate manifests and image
- cd samples/spring-boot
- ./mvnw ${MAVEN_ARGS} clean install -Ddekorate.jib.registry=$KIND_REGISTRY -Ddekorate.jib.group=tests -Ddekorate.jib.version=latest -Ddekorate.jib.autoPushEnabled=true -DskipTests
-
- # Install manifests
- kubectl apply -f target/classes/META-INF/dekorate/kubernetes.yml
-
- # Wait until the service is started
- kubectl wait --for=condition=available --timeout=600s deployment/spring-boot-sample
-
- # First test: verify validating webhook works
- ## Install webhook
- kubectl apply -f k8s/validating-webhook-configuration.yml
-
- ## Wait some time to let Cert-Manager to inject issuers
- sleep 10
-
- ## Test Pod with missing label: it should fail
- K8S_MESSAGE=$(kubectl apply -f k8s/create-pod-with-missing-label-example.yml 2>&1 || true)
- if [[ $K8S_MESSAGE != *"Missing label"* ]]; then
- echo "The validation webhook didn't work. Message: $K8S_MESSAGE"
- exit 1
- fi
-
- # Second test: verify mutating webhook works
- ## Install webhook
- kubectl apply -f k8s/mutating-webhook-configuration.yml
-
- ## Test the same Pod can now be installed because the mutating webhook adds the missing label
- kubectl apply -f k8s/create-pod-with-missing-label-example.yml
- K8S_MESSAGE=`kubectl get pod pod-with-missing-label -o yaml | grep app.kubernetes.io/name`
- if [[ $K8S_MESSAGE != *"mutation-test"* ]]; then
- echo "The mutating webhook didn't work. Message: $K8S_MESSAGE"
- exit 1
- fi
\ No newline at end of file
+ eval $(minikube -p minikube docker-env)
+ ./mvnw clean install -DskipTests
+ cd samples/quarkus
+ ./mvnw install -Dquarkus.container-image.build=true -DskipTests
+ ./mvnw ${MAVEN_ARGS} test -Pend-to-end-tests
\ No newline at end of file
diff --git a/delme.yaml b/delme.yaml
new file mode 100644
index 00000000..a3e33f63
--- /dev/null
+++ b/delme.yaml
@@ -0,0 +1,21 @@
+# TODO del this
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: minimal-ingress
+ annotations:
+ nginx.ingress.kubernetes.io/rewrite-target: /
+ labels:
+ app.kubernetes.io/name: "app"
+spec:
+ ingressClassName: nginx-example
+ rules:
+ - http:
+ paths:
+ - path: /testpath
+ pathType: Prefix
+ backend:
+ service:
+ name: test
+ port:
+ number: 80
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 0386f69e..25454665 100644
--- a/pom.xml
+++ b/pom.xml
@@ -134,6 +134,11 @@
certmanager-annotations
${dekorate.version}
+
+ io.dekorate
+ kubernetes-annotations
+ ${dekorate.version}
+
io.dekorate
jib-annotations
diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/AdmissionControllers.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/AdmissionControllers.java
index d062a3dc..c4a70e7b 100644
--- a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/AdmissionControllers.java
+++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/AdmissionControllers.java
@@ -3,7 +3,7 @@
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
-import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
import io.javaoperatorsdk.webhook.admission.NotAllowedException;
@@ -14,68 +14,69 @@
public class AdmissionControllers {
public static final String ERROR_MESSAGE = "Some error happened";
- public static final String APP_NAME_LABEL_KEY = "app.kubernetes.io/name";
+ public static final String VALIDATION_TARGET_LABEL = "app.kubernetes.io/name";
+ public static final String MUTATION_TARGET_LABEL = "app.kubernetes.io/id";
- public static AdmissionController mutatingController() {
+ public static AdmissionController mutatingController() {
return new AdmissionController<>((resource, operation) -> {
if (resource.getMetadata().getLabels() == null) {
resource.getMetadata().setLabels(new HashMap<>());
}
- resource.getMetadata().getLabels().putIfAbsent(APP_NAME_LABEL_KEY, "mutation-test");
+ resource.getMetadata().getLabels().putIfAbsent(MUTATION_TARGET_LABEL, "mutation-test");
return resource;
});
}
- public static AdmissionController validatingController() {
+ public static AdmissionController validatingController() {
return new AdmissionController<>((resource, operation) -> {
if (resource.getMetadata().getLabels() == null
- || resource.getMetadata().getLabels().get(APP_NAME_LABEL_KEY) == null) {
- throw new NotAllowedException("Missing label: " + APP_NAME_LABEL_KEY);
+ || resource.getMetadata().getLabels().get(VALIDATION_TARGET_LABEL) == null) {
+ throw new NotAllowedException("Missing label: " + VALIDATION_TARGET_LABEL);
}
});
}
- public static AsyncAdmissionController asyncMutatingController() {
+ public static AsyncAdmissionController asyncMutatingController() {
return new AsyncAdmissionController<>(
- (AsyncMutator) (resource, operation) -> CompletableFuture.supplyAsync(() -> {
+ (AsyncMutator) (resource, operation) -> CompletableFuture.supplyAsync(() -> {
if (resource.getMetadata().getLabels() == null) {
resource.getMetadata().setLabels(new HashMap<>());
}
- resource.getMetadata().getLabels().putIfAbsent(APP_NAME_LABEL_KEY, "mutation-test");
+ resource.getMetadata().getLabels().putIfAbsent(MUTATION_TARGET_LABEL, "mutation-test");
return resource;
}));
}
- public static AsyncAdmissionController asyncValidatingController() {
+ public static AsyncAdmissionController asyncValidatingController() {
return new AsyncAdmissionController<>((resource, operation) -> {
if (resource.getMetadata().getLabels() == null
- || resource.getMetadata().getLabels().get(APP_NAME_LABEL_KEY) == null) {
- throw new NotAllowedException("Missing label: " + APP_NAME_LABEL_KEY);
+ || resource.getMetadata().getLabels().get(VALIDATION_TARGET_LABEL) == null) {
+ throw new NotAllowedException("Missing label: " + VALIDATION_TARGET_LABEL);
}
});
}
- public static AdmissionController errorMutatingController() {
- return new AdmissionController<>((Validator) (resource, operation) -> {
+ public static AdmissionController errorMutatingController() {
+ return new AdmissionController<>((Validator) (resource, operation) -> {
throw new IllegalStateException(ERROR_MESSAGE);
});
}
- public static AdmissionController errorValidatingController() {
- return new AdmissionController<>((Mutator) (resource, operation) -> {
+ public static AdmissionController errorValidatingController() {
+ return new AdmissionController<>((Mutator) (resource, operation) -> {
throw new IllegalStateException(ERROR_MESSAGE);
});
}
- public static AsyncAdmissionController errorAsyncMutatingController() {
- return new AsyncAdmissionController<>((AsyncMutator) (resource, operation) -> {
+ public static AsyncAdmissionController errorAsyncMutatingController() {
+ return new AsyncAdmissionController<>((AsyncMutator) (resource, operation) -> {
throw new IllegalStateException(ERROR_MESSAGE);
});
}
- public static AsyncAdmissionController errorAsyncValidatingController() {
- return new AsyncAdmissionController<>((Validator) (resource, operation) -> {
+ public static AsyncAdmissionController errorAsyncValidatingController() {
+ return new AsyncAdmissionController<>((Validator) (resource, operation) -> {
throw new IllegalStateException(ERROR_MESSAGE);
});
}
diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/Utils.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/Utils.java
new file mode 100644
index 00000000..7a6c825b
--- /dev/null
+++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/Utils.java
@@ -0,0 +1,63 @@
+package io.javaoperatorsdk.webhook.sample.commons;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import io.fabric8.kubernetes.api.model.networking.v1.*;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+import static io.javaoperatorsdk.webhook.sample.commons.AdmissionControllers.VALIDATION_TARGET_LABEL;
+
+public class Utils {
+
+ public static final int SPIN_UP_GRACE_PERIOD = 120;
+
+ public static void applyAndWait(KubernetesClient client, String path) {
+ try (FileInputStream fileInputStream = new FileInputStream(path)) {
+ applyAndWait(client, fileInputStream);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static void applyAndWait(KubernetesClient client, InputStream is) {
+ var resources = client.load(is).get();
+ client.resourceList(resources).createOrReplace();
+ client.resourceList(resources).waitUntilReady(3, TimeUnit.MINUTES);
+ }
+
+ public static void addRequiredLabels(Ingress ingress) {
+ ingress.getMetadata().setLabels(Map.of(VALIDATION_TARGET_LABEL, "val"));
+ }
+
+ public static Ingress testIngress(String name) {
+ return new IngressBuilder()
+ .withNewMetadata()
+ .withName(name)
+ .endMetadata()
+ .withSpec(new IngressSpecBuilder()
+ .withIngressClassName("sample")
+ .withRules(new IngressRuleBuilder()
+ .withHttp(new HTTPIngressRuleValueBuilder()
+ .withPaths(new HTTPIngressPathBuilder()
+ .withPath("/test")
+ .withPathType("Prefix")
+ .withBackend(new IngressBackendBuilder()
+ .withService(new IngressServiceBackendBuilder()
+ .withName("service")
+ .withPort(new ServiceBackendPortBuilder()
+ .withNumber(80)
+ .build())
+ .build())
+ .build())
+ .build())
+ .build())
+ .build())
+ .build())
+ .build();
+ }
+
+}
diff --git a/samples/commons/src/main/resources/admission-request.json b/samples/commons/src/main/resources/admission-request.json
index 072f583a..244f1f76 100644
--- a/samples/commons/src/main/resources/admission-request.json
+++ b/samples/commons/src/main/resources/admission-request.json
@@ -25,91 +25,37 @@
]
},
"object": {
- "apiVersion": "v1",
- "kind": "Pod",
+ "apiVersion": "networking.k8s.io/v1",
+ "kind": "Ingress",
"metadata": {
- "generateName": "nginx-deployment-6c54bd5869-",
- "creationTimestamp": null,
- "labels": {
- "app": "nginx",
- "pod-template-hash": "2710681425"
- },
+ "name": "minimal-ingress",
"annotations": {
- "openshift.io/scc": "restricted"
- },
- "ownerReferences": [
- {
- "apiVersion": "extensions/v1beta1",
- "kind": "ReplicaSet",
- "name": "nginx-deployment-6c54bd5869",
- "uid": "16c2b355-5f5d-11e8-ac91-36e6bb280816",
- "controller": true,
- "blockOwnerDeletion": true
- }
- ]
+ "nginx.ingress.kubernetes.io/rewrite-target": "/"
+ }
},
"spec": {
- "volumes": [
- {
- "name": "default-token-tq5lq",
- "secret": {
- "secretName": "default-token-tq5lq"
- }
- }
- ],
- "containers": [
+ "ingressClassName": "nginx-example",
+ "rules": [
{
- "name": "nginx",
- "image": "nginx:1.7.9",
- "ports": [
- {
- "containerPort": 80,
- "protocol": "TCP"
- }
- ],
- "resources": {},
- "volumeMounts": [
- {
- "name": "default-token-tq5lq",
- "readOnly": true,
- "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
- }
- ],
- "terminationMessagePath": "/dev/termination-log",
- "terminationMessagePolicy": "File",
- "imagePullPolicy": "IfNotPresent",
- "securityContext": {
- "capabilities": {
- "drop": [
- "KILL",
- "MKNOD",
- "SETGID",
- "SETUID"
- ]
- },
- "runAsUser": 1000080000
+ "http": {
+ "paths": [
+ {
+ "path": "/testpath",
+ "pathType": "Prefix",
+ "backend": {
+ "service": {
+ "name": "test",
+ "port": {
+ "number": 80
+ }
+ }
+ }
+ }
+ ]
}
}
- ],
- "restartPolicy": "Always",
- "terminationGracePeriodSeconds": 30,
- "dnsPolicy": "ClusterFirst",
- "serviceAccountName": "default",
- "serviceAccount": "default",
- "securityContext": {
- "seLinuxOptions": {
- "level": "s0:c9,c4"
- },
- "fsGroup": 1000080000
- },
- "imagePullSecrets": [
- {
- "name": "default-dockercfg-kksdv"
- }
- ],
- "schedulerName": "default-scheduler"
- },
- "status": {}
+ ]
+ }
},
"oldObject": null
}
diff --git a/samples/manual-test.http b/samples/manual-test.http
index d34c53bd..1f7482ef 100644
--- a/samples/manual-test.http
+++ b/samples/manual-test.http
@@ -1,4 +1,4 @@
-POST http://localhost:8080/mutate HTTP/1.1
+POST http://192.168.49.2:31599/validate HTTP/1.1
Content-Type: application/json
{
@@ -28,91 +28,37 @@ Content-Type: application/json
]
},
"object": {
- "apiVersion": "v1",
- "kind": "Pod",
+ "apiVersion": "networking.k8s.io/v1",
+ "kind": "Ingress",
"metadata": {
- "generateName": "nginx-deployment-6c54bd5869-",
- "creationTimestamp": null,
- "labels": {
- "app": "nginx",
- "pod-template-hash": "2710681425"
- },
+ "name": "minimal-ingress",
"annotations": {
- "openshift.io/scc": "restricted"
- },
- "ownerReferences": [
- {
- "apiVersion": "extensions/v1beta1",
- "kind": "ReplicaSet",
- "name": "nginx-deployment-6c54bd5869",
- "uid": "16c2b355-5f5d-11e8-ac91-36e6bb280816",
- "controller": true,
- "blockOwnerDeletion": true
- }
- ]
+ "nginx.ingress.kubernetes.io/rewrite-target": "/"
+ }
},
"spec": {
- "volumes": [
- {
- "name": "default-token-tq5lq",
- "secret": {
- "secretName": "default-token-tq5lq"
- }
- }
- ],
- "containers": [
+ "ingressClassName": "nginx-example",
+ "rules": [
{
- "name": "nginx",
- "image": "nginx:1.7.9",
- "ports": [
- {
- "containerPort": 80,
- "protocol": "TCP"
- }
- ],
- "resources": {},
- "volumeMounts": [
- {
- "name": "default-token-tq5lq",
- "readOnly": true,
- "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
- }
- ],
- "terminationMessagePath": "/dev/termination-log",
- "terminationMessagePolicy": "File",
- "imagePullPolicy": "IfNotPresent",
- "securityContext": {
- "capabilities": {
- "drop": [
- "KILL",
- "MKNOD",
- "SETGID",
- "SETUID"
- ]
- },
- "runAsUser": 1000080000
+ "http": {
+ "paths": [
+ {
+ "path": "/testpath",
+ "pathType": "Prefix",
+ "backend": {
+ "service": {
+ "name": "test",
+ "port": {
+ "number": 80
+ }
+ }
+ }
+ }
+ ]
}
}
- ],
- "restartPolicy": "Always",
- "terminationGracePeriodSeconds": 30,
- "dnsPolicy": "ClusterFirst",
- "serviceAccountName": "default",
- "serviceAccount": "default",
- "securityContext": {
- "seLinuxOptions": {
- "level": "s0:c9,c4"
- },
- "fsGroup": 1000080000
- },
- "imagePullSecrets": [
- {
- "name": "default-dockercfg-kksdv"
- }
- ],
- "schedulerName": "default-scheduler"
- },
- "status": {}
+ ]
+ }
},
"oldObject": null
}
diff --git a/samples/quarkus/k8s/mutating-webhook-configuration.yml b/samples/quarkus/k8s/mutating-webhook-configuration.yml
new file mode 100644
index 00000000..5ba8a6d9
--- /dev/null
+++ b/samples/quarkus/k8s/mutating-webhook-configuration.yml
@@ -0,0 +1,23 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+ name: "mutating.quarkus.example.com"
+ annotations:
+ cert-manager.io/inject-ca-from: default/quarkus-sample
+webhooks:
+ - name: "mutating.quarkus.example.com"
+ rules:
+ - apiGroups: ["networking.k8s.io"]
+ apiVersions: ["v1"]
+ operations: ["*"]
+ resources: ["ingresses"]
+ scope: "Namespaced"
+ clientConfig:
+ service:
+ namespace: "default"
+ name: "quarkus-sample"
+ path: "/mutate"
+ port: 443
+ admissionReviewVersions: ["v1"]
+ sideEffects: None
+ timeoutSeconds: 5
\ No newline at end of file
diff --git a/samples/quarkus/k8s/validating-webhook-configuration.yml b/samples/quarkus/k8s/validating-webhook-configuration.yml
new file mode 100644
index 00000000..6474e024
--- /dev/null
+++ b/samples/quarkus/k8s/validating-webhook-configuration.yml
@@ -0,0 +1,23 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ name: "validating.quarkus.example.com"
+ annotations:
+ cert-manager.io/inject-ca-from: default/quarkus-sample
+webhooks:
+ - name: "validating.quarkus.example.com"
+ rules:
+ - apiGroups: ["networking.k8s.io"]
+ apiVersions: ["v1"]
+ operations: ["*"]
+ resources: ["ingresses"]
+ scope: "Namespaced"
+ clientConfig:
+ service:
+ namespace: "default"
+ name: "quarkus-sample"
+ path: "/validate"
+ port: 443
+ admissionReviewVersions: ["v1"]
+ sideEffects: None
+ timeoutSeconds: 5
\ No newline at end of file
diff --git a/samples/quarkus/pom.xml b/samples/quarkus/pom.xml
index b4b97203..591af2b6 100644
--- a/samples/quarkus/pom.xml
+++ b/samples/quarkus/pom.xml
@@ -46,8 +46,8 @@
${project.version}
- io.fabric8
kubernetes-client
+ io.fabric8
@@ -55,6 +55,19 @@
io.quarkus
quarkus-kubernetes-client
+
+ io.quarkus
+ quarkus-minikube
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+ io.quarkus
+ quarkus-container-image-jib
+
io.quarkus
quarkus-junit5
@@ -69,16 +82,31 @@
org.jboss.resteasy
resteasy-jackson2-provider
+
+ io.quarkus
+ quarkus-kubernetes
+
+
+ io.quarkiverse.certmanager
+ quarkus-certmanager
+ 0.0.2
+
io.javaoperatorsdk.admissioncontroller.sample
sample-commons
${project.version}
-
-
- io.fabric8
- kubernetes-client
-
-
+
+
+ kubernetes-client
+ io.fabric8
+
+
+
+
+ org.awaitility
+ awaitility
+ ${awaitility.version}
+ test
diff --git a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerConfig.java b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerConfig.java
index 28b09f0d..8fec52b1 100644
--- a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerConfig.java
+++ b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerConfig.java
@@ -3,7 +3,7 @@
import javax.inject.Named;
import javax.inject.Singleton;
-import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
import io.javaoperatorsdk.webhook.sample.commons.AdmissionControllers;
@@ -17,25 +17,25 @@ public class AdmissionControllerConfig {
@Singleton
@Named(MUTATING_CONTROLLER)
- public AdmissionController mutatingController() {
+ public AdmissionController mutatingController() {
return AdmissionControllers.mutatingController();
}
@Singleton
@Named(VALIDATING_CONTROLLER)
- public AdmissionController validatingController() {
+ public AdmissionController validatingController() {
return AdmissionControllers.validatingController();
}
@Singleton
@Named(ASYNC_MUTATING_CONTROLLER)
- public AsyncAdmissionController asyncMutatingController() {
+ public AsyncAdmissionController asyncMutatingController() {
return AdmissionControllers.asyncMutatingController();
}
@Singleton
@Named(ASYNC_VALIDATING_CONTROLLER)
- public AsyncAdmissionController asyncValidatingController() {
+ public AsyncAdmissionController asyncValidatingController() {
return AdmissionControllers.asyncValidatingController();
}
}
diff --git a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpoint.java b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpoint.java
index 7ad6cef4..4f98da38 100644
--- a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpoint.java
+++ b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpoint.java
@@ -5,8 +5,8 @@
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
-import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionReview;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
import io.smallrye.mutiny.Uni;
@@ -19,17 +19,17 @@ public class AdmissionEndpoint {
public static final String ASYNC_MUTATE_PATH = "async-mutate";
public static final String ASYNC_VALIDATE_PATH = "async-validate";
- private final AdmissionController mutationController;
- private final AdmissionController validationController;
- private final AsyncAdmissionController asyncMutationController;
- private final AsyncAdmissionController asyncValidationController;
+ private final AdmissionController mutationController;
+ private final AdmissionController validationController;
+ private final AsyncAdmissionController asyncMutationController;
+ private final AsyncAdmissionController asyncValidationController;
@Inject
public AdmissionEndpoint(
- @Named(AdmissionControllerConfig.MUTATING_CONTROLLER) AdmissionController mutationController,
- @Named(AdmissionControllerConfig.VALIDATING_CONTROLLER) AdmissionController validationController,
- @Named(AdmissionControllerConfig.ASYNC_MUTATING_CONTROLLER) AsyncAdmissionController asyncMutationController,
- @Named(AdmissionControllerConfig.ASYNC_VALIDATING_CONTROLLER) AsyncAdmissionController asyncValidationController) {
+ @Named(AdmissionControllerConfig.MUTATING_CONTROLLER) AdmissionController mutationController,
+ @Named(AdmissionControllerConfig.VALIDATING_CONTROLLER) AdmissionController validationController,
+ @Named(AdmissionControllerConfig.ASYNC_MUTATING_CONTROLLER) AsyncAdmissionController asyncMutationController,
+ @Named(AdmissionControllerConfig.ASYNC_VALIDATING_CONTROLLER) AsyncAdmissionController asyncValidationController) {
this.mutationController = mutationController;
this.validationController = validationController;
this.asyncMutationController = asyncMutationController;
diff --git a/samples/spring-boot/src/main/resources/kubernetes/common.yml b/samples/quarkus/src/main/kubernetes/common.yml
similarity index 88%
rename from samples/spring-boot/src/main/resources/kubernetes/common.yml
rename to samples/quarkus/src/main/kubernetes/common.yml
index 3c76a673..336ec2fe 100644
--- a/samples/spring-boot/src/main/resources/kubernetes/common.yml
+++ b/samples/quarkus/src/main/kubernetes/common.yml
@@ -5,4 +5,4 @@ metadata:
name: pkcs12-pass
data:
password: c3VwZXJzZWNyZXQ=
-type: Opaque
+type: Opaque
\ No newline at end of file
diff --git a/samples/quarkus/src/main/resources/application.properties b/samples/quarkus/src/main/resources/application.properties
index e69de29b..add08155 100644
--- a/samples/quarkus/src/main/resources/application.properties
+++ b/samples/quarkus/src/main/resources/application.properties
@@ -0,0 +1,22 @@
+#quarkus.http.insecure-requests=disabled
+quarkus.http.port=80
+quarkus.http.ssl-port=443
+
+quarkus.kubernetes.image-pull-policy=IfNotPresent
+quarkus.kubernetes.ports."tls".container-port=443
+
+## To generate the Certificate and the Issuer resources
+quarkus.certificate.secret-name=tls-secret
+quarkus.certificate.dns-names=quarkus-sample.default.svc,localhost
+quarkus.certificate.self-signed.enabled=true
+quarkus.certificate.subject.organizations=Dekorate,Community
+quarkus.certificate.duration=2160h0m0s
+quarkus.certificate.renew-before=360h0m0s
+quarkus.certificate.private-key.algorithm=RSA
+quarkus.certificate.private-key.encoding=PKCS8
+quarkus.certificate.private-key.size=2048
+quarkus.certificate.keystores.pkcs12.create=true
+quarkus.certificate.keystores.pkcs12.password-secret-ref.name=pkcs12-pass
+quarkus.certificate.keystores.pkcs12.password-secret-ref.key=password
+quarkus.certificate.usages=server auth,client auth
+
diff --git a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdditionalAdmissionConfig.java b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdditionalAdmissionConfig.java
index c3c16ddb..5969c4d3 100644
--- a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdditionalAdmissionConfig.java
+++ b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdditionalAdmissionConfig.java
@@ -3,7 +3,7 @@
import javax.inject.Named;
import javax.inject.Singleton;
-import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
import io.javaoperatorsdk.webhook.sample.commons.AdmissionControllers;
@@ -17,25 +17,25 @@ public class AdditionalAdmissionConfig {
@Singleton
@Named(ERROR_MUTATING_CONTROLLER)
- public AdmissionController errorMutatingController() {
+ public AdmissionController errorMutatingController() {
return AdmissionControllers.errorMutatingController();
}
@Singleton
@Named(ERROR_VALIDATING_CONTROLLER)
- public AdmissionController errorValidatingController() {
+ public AdmissionController errorValidatingController() {
return AdmissionControllers.errorValidatingController();
}
@Singleton
@Named(ERROR_ASYNC_MUTATING_CONTROLLER)
- public AsyncAdmissionController errorAsyncMutatingController() {
+ public AsyncAdmissionController errorAsyncMutatingController() {
return AdmissionControllers.errorAsyncMutatingController();
}
@Singleton
@Named(ERROR_ASYNC_VALIDATING_CONTROLLER)
- public AsyncAdmissionController errorAsyncValidatingController() {
+ public AsyncAdmissionController errorAsyncValidatingController() {
return AdmissionControllers.errorAsyncValidatingController();
}
}
diff --git a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionAdditionalTestEndpoint.java b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionAdditionalTestEndpoint.java
index fac1f02d..2b005243 100644
--- a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionAdditionalTestEndpoint.java
+++ b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionAdditionalTestEndpoint.java
@@ -8,8 +8,8 @@
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
-import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionReview;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
import io.smallrye.mutiny.Uni;
@@ -22,17 +22,17 @@ public class AdmissionAdditionalTestEndpoint {
public static final String ERROR_MUTATE_PATH = "error-mutate";
public static final String ERROR_VALIDATE_PATH = "error-validate";
- private final AdmissionController errorMutationController;
- private final AdmissionController errorValidationController;
- private final AsyncAdmissionController errorAsyncMutationController;
- private final AsyncAdmissionController errorAsyncValidationController;
+ private final AdmissionController errorMutationController;
+ private final AdmissionController errorValidationController;
+ private final AsyncAdmissionController errorAsyncMutationController;
+ private final AsyncAdmissionController errorAsyncValidationController;
@Inject
public AdmissionAdditionalTestEndpoint(
- @Named(AdditionalAdmissionConfig.ERROR_MUTATING_CONTROLLER) AdmissionController errorMutationController,
- @Named(AdditionalAdmissionConfig.ERROR_VALIDATING_CONTROLLER) AdmissionController errorValidationController,
- @Named(AdditionalAdmissionConfig.ERROR_ASYNC_MUTATING_CONTROLLER) AsyncAdmissionController errorAsyncMutationController,
- @Named(AdditionalAdmissionConfig.ERROR_ASYNC_VALIDATING_CONTROLLER) AsyncAdmissionController errorAsyncValidationController) {
+ @Named(AdditionalAdmissionConfig.ERROR_MUTATING_CONTROLLER) AdmissionController errorMutationController,
+ @Named(AdditionalAdmissionConfig.ERROR_VALIDATING_CONTROLLER) AdmissionController errorValidationController,
+ @Named(AdditionalAdmissionConfig.ERROR_ASYNC_MUTATING_CONTROLLER) AsyncAdmissionController errorAsyncMutationController,
+ @Named(AdditionalAdmissionConfig.ERROR_ASYNC_VALIDATING_CONTROLLER) AsyncAdmissionController errorAsyncValidationController) {
this.errorMutationController = errorMutationController;
this.errorValidationController = errorValidationController;
this.errorAsyncMutationController = errorAsyncMutationController;
diff --git a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerE2E.java b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerE2E.java
new file mode 100644
index 00000000..2c93fa10
--- /dev/null
+++ b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerE2E.java
@@ -0,0 +1,73 @@
+package io.javaoperatorsdk.webhook.admission.sample.quarkus.admission;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.time.Duration;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import io.fabric8.kubernetes.api.model.networking.v1.*;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClientBuilder;
+import io.fabric8.kubernetes.client.KubernetesClientException;
+
+import static io.javaoperatorsdk.webhook.sample.commons.AdmissionControllers.MUTATION_TARGET_LABEL;
+import static io.javaoperatorsdk.webhook.sample.commons.Utils.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class AdmissionControllerE2E {
+
+ private KubernetesClient client = new KubernetesClientBuilder().build();
+
+ @BeforeAll
+ static void deployService() throws IOException {
+ try (KubernetesClient client = new KubernetesClientBuilder().build();
+ InputStream certManager =
+ new URL(
+ "https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml")
+ .openStream()) {
+ applyAndWait(client, certManager);
+ applyAndWait(client, "target/kubernetes/minikube.yml");
+ applyAndWait(client, "k8s/validating-webhook-configuration.yml");
+ applyAndWait(client, "k8s/mutating-webhook-configuration.yml");
+ }
+ }
+
+ @Test
+ void validationHook() {
+ var ingressWithLabel = testIngress("normal-add-test");
+ addRequiredLabels(ingressWithLabel);
+ await().atMost(Duration.ofSeconds(SPIN_UP_GRACE_PERIOD)).untilAsserted(() -> {
+ Ingress res = null;
+ try {
+ // this can be since coredns in minikube can take some time
+ res = client.network().v1().ingresses().resource(ingressWithLabel).createOrReplace();
+ } catch (KubernetesClientException e) {
+ }
+ assertThat(res).isNotNull();
+ });
+ assertThrows(KubernetesClientException.class,
+ () -> client.network().v1().ingresses().resource(testIngress("validate-test"))
+ .createOrReplace());
+ }
+
+ @Test
+ void mutationHook() {
+ var ingressWithLabel = testIngress("mutation-test");
+ addRequiredLabels(ingressWithLabel);
+ await().atMost(Duration.ofSeconds(SPIN_UP_GRACE_PERIOD)).untilAsserted(() -> {
+ Ingress res = null;
+ try {
+ // this can be since coredns in minikube can take some time
+ res = client.network().v1().ingresses().resource(ingressWithLabel).createOrReplace();
+ } catch (KubernetesClientException e) {
+ }
+ assertThat(res).isNotNull();
+ assertThat(res.getMetadata().getLabels()).containsKey(MUTATION_TARGET_LABEL);
+ });
+ }
+}
diff --git a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpointTest.java b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpointTest.java
index d9d0c5b5..9a9047df 100644
--- a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpointTest.java
+++ b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpointTest.java
@@ -18,7 +18,7 @@
class AdmissionEndpointTest {
public static final String MUTATION_RESPONSE =
- "{\"apiVersion\":\"admission.k8s.io/v1\",\"kind\":\"AdmissionReview\",\"response\":{\"allowed\":true,\"patch\":\"W3sib3AiOiJhZGQiLCJwYXRoIjoiL21ldGFkYXRhL2xhYmVscy9hcHAua3ViZXJuZXRlcy5pb34xbmFtZSIsInZhbHVlIjoibXV0YXRpb24tdGVzdCJ9XQ==\",\"patchType\":\"JSONPatch\",\"uid\":\"0df28fbd-5f5f-11e8-bc74-36e6bb280816\"}}";
+ "{\"apiVersion\":\"admission.k8s.io/v1\",\"kind\":\"AdmissionReview\",\"response\":{\"allowed\":true,\"patch\":\"W3sib3AiOiJhZGQiLCJwYXRoIjoiL21ldGFkYXRhL2xhYmVscyIsInZhbHVlIjp7ImFwcC5rdWJlcm5ldGVzLmlvL2lkIjoibXV0YXRpb24tdGVzdCJ9fV0=\",\"patchType\":\"JSONPatch\",\"uid\":\"0df28fbd-5f5f-11e8-bc74-36e6bb280816\"}}";
public static final String VALIDATE_RESPONSE =
"{\"apiVersion\":\"admission.k8s.io/v1\",\"kind\":\"AdmissionReview\",\"response\":{\"allowed\":false,\"status\":{\"apiVersion\":\"v1\",\"kind\":\"Status\",\"code\":403,\"message\":\"Missing label: app.kubernetes.io/name\"},\"uid\":\"0df28fbd-5f5f-11e8-bc74-36e6bb280816\"}}";
diff --git a/samples/spring-boot/k8s/mutating-webhook-configuration.yml b/samples/spring-boot/k8s/mutating-webhook-configuration.yml
index fc424d06..a1ce2122 100644
--- a/samples/spring-boot/k8s/mutating-webhook-configuration.yml
+++ b/samples/spring-boot/k8s/mutating-webhook-configuration.yml
@@ -1,20 +1,20 @@
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
- name: "pod-mutating.spring-boot.example.com"
+ name: "mutating.spring-boot.example.com"
annotations:
- cert-manager.io/inject-ca-from: test/spring-boot-sample
+ cert-manager.io/inject-ca-from: default/spring-boot-sample
webhooks:
- - name: "pod-mutating.spring-boot.example.com"
+ - name: "mutating.spring-boot.example.com"
rules:
- - apiGroups: [""]
+ - apiGroups: ["networking.k8s.io"]
apiVersions: ["v1"]
- operations: ["CREATE"]
- resources: ["pods"]
+ operations: ["*"]
+ resources: ["ingresses"]
scope: "Namespaced"
clientConfig:
service:
- namespace: "test"
+ namespace: "default"
name: "spring-boot-sample"
path: "/mutate"
admissionReviewVersions: ["v1"]
diff --git a/samples/spring-boot/k8s/validating-webhook-configuration.yml b/samples/spring-boot/k8s/validating-webhook-configuration.yml
index dac1c42a..1c899f4a 100644
--- a/samples/spring-boot/k8s/validating-webhook-configuration.yml
+++ b/samples/spring-boot/k8s/validating-webhook-configuration.yml
@@ -1,20 +1,20 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
- name: "pod-policy.spring-boot.example.com"
+ name: "validating.spring-boot.example.com"
annotations:
- cert-manager.io/inject-ca-from: test/spring-boot-sample
+ cert-manager.io/inject-ca-from: default/spring-boot-sample
webhooks:
- - name: "pod-policy.spring-boot.example.com"
+ - name: "validating.spring-boot.example.com"
rules:
- - apiGroups: [""]
+ - apiGroups: ["networking.k8s.io"]
apiVersions: ["v1"]
- operations: ["CREATE"]
- resources: ["pods"]
+ operations: ["*"]
+ resources: ["ingresses"]
scope: "Namespaced"
clientConfig:
service:
- namespace: "test"
+ namespace: "default"
name: "spring-boot-sample"
path: "/validate"
admissionReviewVersions: ["v1"]
diff --git a/samples/spring-boot/pom.xml b/samples/spring-boot/pom.xml
index c94aea0a..2364a341 100644
--- a/samples/spring-boot/pom.xml
+++ b/samples/spring-boot/pom.xml
@@ -76,6 +76,12 @@
assertj-core
test
+
+ org.awaitility
+ awaitility
+ ${awaitility.version}
+ test
+
@@ -89,7 +95,7 @@
gcr.io/distroless/java:11
- spring-boot-sample
+ test/spring-boot-sample:${project.version}
diff --git a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionConfig.java b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionConfig.java
index 42b2f094..9e6d91ba 100644
--- a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionConfig.java
+++ b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionConfig.java
@@ -3,7 +3,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
import io.javaoperatorsdk.webhook.sample.commons.AdmissionControllers;
@@ -12,22 +12,22 @@
public class AdmissionConfig {
@Bean
- public AdmissionController mutatingController() {
+ public AdmissionController mutatingController() {
return AdmissionControllers.mutatingController();
}
@Bean
- public AdmissionController validatingController() {
+ public AdmissionController validatingController() {
return AdmissionControllers.validatingController();
}
@Bean
- public AsyncAdmissionController asyncMutatingController() {
+ public AsyncAdmissionController asyncMutatingController() {
return AdmissionControllers.asyncMutatingController();
}
@Bean
- public AsyncAdmissionController asyncValidatingController() {
+ public AsyncAdmissionController asyncValidatingController() {
return AdmissionControllers.asyncValidatingController();
}
}
diff --git a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpoint.java b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpoint.java
index 5e5b7b2a..ebdbfef1 100644
--- a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpoint.java
+++ b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpoint.java
@@ -7,8 +7,8 @@
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
-import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionReview;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
@@ -22,17 +22,17 @@ public class AdmissionEndpoint {
public static final String ASYNC_MUTATE_PATH = "async-mutate";
public static final String ASYNC_VALIDATE_PATH = "async-validate";
- private final AdmissionController mutatingController;
- private final AdmissionController validatingController;
- private final AsyncAdmissionController asyncMutatingController;
- private final AsyncAdmissionController asyncValidatingController;
+ private final AdmissionController mutatingController;
+ private final AdmissionController validatingController;
+ private final AsyncAdmissionController asyncMutatingController;
+ private final AsyncAdmissionController asyncValidatingController;
@Autowired
public AdmissionEndpoint(
- @Qualifier("mutatingController") AdmissionController mutationController,
- @Qualifier("validatingController") AdmissionController validatingController,
- @Qualifier("asyncMutatingController") AsyncAdmissionController asyncMutatingController,
- @Qualifier("asyncValidatingController") AsyncAdmissionController asyncValidatingController) {
+ @Qualifier("mutatingController") AdmissionController mutationController,
+ @Qualifier("validatingController") AdmissionController validatingController,
+ @Qualifier("asyncMutatingController") AsyncAdmissionController asyncMutatingController,
+ @Qualifier("asyncValidatingController") AsyncAdmissionController asyncValidatingController) {
this.mutatingController = mutationController;
this.validatingController = validatingController;
this.asyncMutatingController = asyncMutatingController;
diff --git a/samples/spring-boot/src/main/resources/application.properties b/samples/spring-boot/src/main/resources/application.properties
index 9bc6156a..9587382a 100644
--- a/samples/spring-boot/src/main/resources/application.properties
+++ b/samples/spring-boot/src/main/resources/application.properties
@@ -5,10 +5,10 @@ server.ssl.key-store-type=PKCS12
dekorate.jib.from=openjdk:11
## To include the keystore secret
dekorate.options.input-path=kubernetes
-
+dekorate.jib.group=test
## To generate the Certificate and the Issuer resources
dekorate.certificate.secret-name=tls-secret
-dekorate.certificate.dnsNames=spring-boot-sample.test.svc,localhost
+dekorate.certificate.dnsNames=spring-boot-sample.default.svc,localhost
dekorate.certificate.self-signed.enabled=true
dekorate.certificate.subject.organizations=Dekorate,Community
dekorate.certificate.duration=2160h0m0s
diff --git a/samples/spring-boot/src/main/resources/kubernetes/common.yaml b/samples/spring-boot/src/main/resources/kubernetes/common.yaml
new file mode 100644
index 00000000..336ec2fe
--- /dev/null
+++ b/samples/spring-boot/src/main/resources/kubernetes/common.yaml
@@ -0,0 +1,8 @@
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: pkcs12-pass
+data:
+ password: c3VwZXJzZWNyZXQ=
+type: Opaque
\ No newline at end of file
diff --git a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdditionalAdmissionConfig.java b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdditionalAdmissionConfig.java
index 7bc198ec..6e20545a 100644
--- a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdditionalAdmissionConfig.java
+++ b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdditionalAdmissionConfig.java
@@ -3,7 +3,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
import io.javaoperatorsdk.webhook.sample.commons.AdmissionControllers;
@@ -12,22 +12,22 @@
public class AdditionalAdmissionConfig {
@Bean
- public AdmissionController errorMutatingController() {
+ public AdmissionController errorMutatingController() {
return AdmissionControllers.errorMutatingController();
}
@Bean
- public AdmissionController errorValidatingController() {
+ public AdmissionController errorValidatingController() {
return AdmissionControllers.errorValidatingController();
}
@Bean
- public AsyncAdmissionController errorAsyncMutatingController() {
+ public AsyncAdmissionController errorAsyncMutatingController() {
return AdmissionControllers.errorAsyncMutatingController();
}
@Bean
- public AsyncAdmissionController errorAsyncValidatingController() {
+ public AsyncAdmissionController errorAsyncValidatingController() {
return AdmissionControllers.errorAsyncValidatingController();
}
}
diff --git a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionAdditionalTestEndpoint.java b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionAdditionalTestEndpoint.java
index 0b2ba6eb..172e7ff8 100644
--- a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionAdditionalTestEndpoint.java
+++ b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionAdditionalTestEndpoint.java
@@ -7,8 +7,8 @@
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
-import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionReview;
+import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.javaoperatorsdk.webhook.admission.AdmissionController;
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionController;
@@ -22,17 +22,17 @@ public class AdmissionAdditionalTestEndpoint {
public static final String ERROR_ASYNC_MUTATE_PATH = "error-async-mutate";
public static final String ERROR_ASYNC_VALIDATE_PATH = "error-async-validate";
- private final AdmissionController errorMutatingController;
- private final AdmissionController errorValidatingController;
- private final AsyncAdmissionController errorAsyncMutatingController;
- private final AsyncAdmissionController errorAsyncValidatingController;
+ private final AdmissionController errorMutatingController;
+ private final AdmissionController errorValidatingController;
+ private final AsyncAdmissionController errorAsyncMutatingController;
+ private final AsyncAdmissionController errorAsyncValidatingController;
@Autowired
public AdmissionAdditionalTestEndpoint(
- @Qualifier("errorMutatingController") AdmissionController errorMutatingController,
- @Qualifier("errorValidatingController") AdmissionController errorValidatingController,
- @Qualifier("errorAsyncMutatingController") AsyncAdmissionController errorAsyncMutatingController,
- @Qualifier("errorAsyncValidatingController") AsyncAdmissionController errorAsyncValidatingController) {
+ @Qualifier("errorMutatingController") AdmissionController errorMutatingController,
+ @Qualifier("errorValidatingController") AdmissionController errorValidatingController,
+ @Qualifier("errorAsyncMutatingController") AsyncAdmissionController errorAsyncMutatingController,
+ @Qualifier("errorAsyncValidatingController") AsyncAdmissionController errorAsyncValidatingController) {
this.errorMutatingController = errorMutatingController;
this.errorValidatingController = errorValidatingController;
this.errorAsyncMutatingController = errorAsyncMutatingController;
diff --git a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionControllerE2E.java b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionControllerE2E.java
new file mode 100644
index 00000000..6c08d2cc
--- /dev/null
+++ b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionControllerE2E.java
@@ -0,0 +1,73 @@
+package io.javaoperatorsdk.webhook.sample.springboot.admission;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.time.Duration;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import io.fabric8.kubernetes.api.model.networking.v1.*;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClientBuilder;
+import io.fabric8.kubernetes.client.KubernetesClientException;
+
+import static io.javaoperatorsdk.webhook.sample.commons.AdmissionControllers.MUTATION_TARGET_LABEL;
+import static io.javaoperatorsdk.webhook.sample.commons.Utils.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class AdmissionControllerE2E {
+
+ private KubernetesClient client = new KubernetesClientBuilder().build();
+
+ @BeforeAll
+ static void deployService() throws IOException {
+ try (KubernetesClient client = new KubernetesClientBuilder().build();
+ InputStream certManager =
+ new URL(
+ "https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml")
+ .openStream()) {
+ applyAndWait(client, certManager);
+ applyAndWait(client, "target/classes/META-INF/dekorate/kubernetes.yml");
+ applyAndWait(client, "k8s/validating-webhook-configuration.yml");
+ applyAndWait(client, "k8s/mutating-webhook-configuration.yml");
+ }
+ }
+
+ @Test
+ void validationHook() {
+ var ingressWithLabel = testIngress("normal-add-test");
+ addRequiredLabels(ingressWithLabel);
+ await().atMost(Duration.ofSeconds(SPIN_UP_GRACE_PERIOD)).untilAsserted(() -> {
+ Ingress res = null;
+ try {
+ // this can be since coredns in minikube can take some time
+ res = client.network().v1().ingresses().resource(ingressWithLabel).createOrReplace();
+ } catch (KubernetesClientException e) {
+ }
+ assertThat(res).isNotNull();
+ });
+ assertThrows(KubernetesClientException.class,
+ () -> client.network().v1().ingresses().resource(testIngress("validate-test"))
+ .createOrReplace());
+ }
+
+ @Test
+ void mutationHook() {
+ var ingressWithLabel = testIngress("mutation-test");
+ addRequiredLabels(ingressWithLabel);
+ await().atMost(Duration.ofSeconds(SPIN_UP_GRACE_PERIOD)).untilAsserted(() -> {
+ Ingress res = null;
+ try {
+ res = client.network().v1().ingresses().resource(ingressWithLabel).createOrReplace();
+ } catch (KubernetesClientException e) {
+ }
+ assertThat(res).isNotNull();
+ assertThat(res.getMetadata().getLabels()).containsKey(MUTATION_TARGET_LABEL);
+ });
+ }
+
+}
diff --git a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpointTest.java b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpointTest.java
index 505d27e3..07fcd378 100644
--- a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpointTest.java
+++ b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpointTest.java
@@ -77,7 +77,7 @@ public void testMutate(String path) {
.body(request())
.exchange()
.expectStatus().isOk().expectBody().json(
- "{\"apiVersion\":\"admission.k8s.io/v1\",\"kind\":\"AdmissionReview\",\"response\":{\"allowed\":true,\"patch\":\"W3sib3AiOiJhZGQiLCJwYXRoIjoiL21ldGFkYXRhL2xhYmVscy9hcHAua3ViZXJuZXRlcy5pb34xbmFtZSIsInZhbHVlIjoibXV0YXRpb24tdGVzdCJ9XQ==\",\"patchType\":\"JSONPatch\",\"uid\":\"0df28fbd-5f5f-11e8-bc74-36e6bb280816\"}}");
+ "{\"apiVersion\":\"admission.k8s.io/v1\",\"kind\":\"AdmissionReview\",\"response\":{\"allowed\":true,\"patch\":\"W3sib3AiOiJhZGQiLCJwYXRoIjoiL21ldGFkYXRhL2xhYmVscyIsInZhbHVlIjp7ImFwcC5rdWJlcm5ldGVzLmlvL2lkIjoibXV0YXRpb24tdGVzdCJ9fV0=\",\"patchType\":\"JSONPatch\",\"uid\":\"0df28fbd-5f5f-11e8-bc74-36e6bb280816\"}}");
}
public void testValidate(String path) {