Skip to content

Commit 2133d28

Browse files
authored
Fix exception handling in AsyncDefaultAdmissionRequestMutator (#284)
Signed-off-by: David Sondermann <[email protected]>
1 parent b0a5838 commit 2133d28

File tree

59 files changed

+421
-297
lines changed

Some content is hidden

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

59 files changed

+421
-297
lines changed

core/src/main/java/io/javaoperatorsdk/webhook/admission/AdmissionController.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@ public AdmissionController(AdmissionRequestHandler admissionRequestHandler) {
2525

2626
public AdmissionReview handle(AdmissionReview admissionReview) {
2727
var response = admissionRequestHandler.handle(admissionReview.getRequest());
28-
AdmissionReview responseAdmissionReview = new AdmissionReview();
28+
var responseAdmissionReview = new AdmissionReview();
2929
responseAdmissionReview.setResponse(response);
3030
response.setUid(admissionReview.getRequest().getUid());
3131
return responseAdmissionReview;
3232
}
33-
3433
}

core/src/main/java/io/javaoperatorsdk/webhook/admission/AdmissionRequestHandler.java

-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,4 @@
66
public interface AdmissionRequestHandler {
77

88
AdmissionResponse handle(AdmissionRequest admissionRequest);
9-
109
}

core/src/main/java/io/javaoperatorsdk/webhook/admission/AdmissionUtils.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@ public class AdmissionUtils {
1717

1818
private AdmissionUtils() {}
1919

20+
public static AdmissionResponse allowedAdmissionResponse() {
21+
var admissionResponse = new AdmissionResponse();
22+
admissionResponse.setAllowed(true);
23+
return admissionResponse;
24+
}
25+
2026
public static AdmissionResponse notAllowedExceptionToAdmissionResponse(
2127
NotAllowedException notAllowedException) {
22-
AdmissionResponse admissionResponse = new AdmissionResponse();
28+
var admissionResponse = new AdmissionResponse();
2329
admissionResponse.setAllowed(false);
2430
admissionResponse.setStatus(notAllowedException.getStatus());
2531
return admissionResponse;
@@ -33,17 +39,16 @@ public static KubernetesResource getTargetResource(AdmissionRequest admissionReq
3339

3440
public static AdmissionResponse admissionResponseFromMutation(KubernetesResource originalResource,
3541
KubernetesResource mutatedResource) {
36-
AdmissionResponse admissionResponse = new AdmissionResponse();
42+
var admissionResponse = new AdmissionResponse();
3743
admissionResponse.setAllowed(true);
3844
admissionResponse.setPatchType(JSON_PATCH);
3945
var originalResNode = mapper.valueToTree(originalResource);
4046
var mutatedResNode = mapper.valueToTree(mutatedResource);
4147

4248
var diff = JsonDiff.asJson(originalResNode, mutatedResNode);
43-
String base64Diff =
49+
var base64Diff =
4450
Base64.getEncoder().encodeToString(diff.toString().getBytes(StandardCharsets.UTF_8));
4551
admissionResponse.setPatch(base64Diff);
4652
return admissionResponse;
4753
}
48-
4954
}

core/src/main/java/io/javaoperatorsdk/webhook/admission/AsyncAdmissionController.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,22 @@
66
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionReview;
77
import io.javaoperatorsdk.webhook.admission.mutation.AsyncDefaultAdmissionRequestMutator;
88
import io.javaoperatorsdk.webhook.admission.mutation.AsyncMutator;
9+
import io.javaoperatorsdk.webhook.admission.mutation.Mutator;
910
import io.javaoperatorsdk.webhook.admission.validation.AsyncDefaultAdmissionRequestValidator;
1011
import io.javaoperatorsdk.webhook.admission.validation.Validator;
1112

1213
public class AsyncAdmissionController<T extends KubernetesResource> {
1314

1415
private final AsyncAdmissionRequestHandler requestHandler;
1516

16-
public AsyncAdmissionController(AsyncMutator<T> mutator) {
17+
public AsyncAdmissionController(Mutator<T> mutator) {
1718
this(new AsyncDefaultAdmissionRequestMutator<>(mutator));
1819
}
1920

21+
public AsyncAdmissionController(AsyncMutator<T> asyncMutator) {
22+
this(new AsyncDefaultAdmissionRequestMutator<>(asyncMutator));
23+
}
24+
2025
public AsyncAdmissionController(Validator<T> validator) {
2126
this(new AsyncDefaultAdmissionRequestValidator<>(validator));
2227
}
@@ -28,11 +33,10 @@ public AsyncAdmissionController(AsyncAdmissionRequestHandler requestHandler) {
2833
public CompletionStage<AdmissionReview> handle(AdmissionReview admissionReview) {
2934
return requestHandler.handle(admissionReview.getRequest())
3035
.thenApply(r -> {
31-
AdmissionReview responseAdmissionReview = new AdmissionReview();
36+
var responseAdmissionReview = new AdmissionReview();
3237
responseAdmissionReview.setResponse(r);
3338
r.setUid(admissionReview.getRequest().getUid());
3439
return responseAdmissionReview;
3540
});
3641
}
37-
3842
}

core/src/main/java/io/javaoperatorsdk/webhook/admission/AsyncAdmissionRequestHandler.java

-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,4 @@
88
public interface AsyncAdmissionRequestHandler {
99

1010
CompletionStage<AdmissionResponse> handle(AdmissionRequest admissionRequest);
11-
1211
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package io.javaoperatorsdk.webhook.admission.mutation;
22

33
import java.util.concurrent.CompletableFuture;
4+
import java.util.concurrent.CompletionException;
45
import java.util.concurrent.CompletionStage;
56

67
import io.fabric8.kubernetes.api.model.KubernetesResource;
78
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionRequest;
89
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionResponse;
9-
import io.javaoperatorsdk.webhook.admission.AdmissionUtils;
1010
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionRequestHandler;
1111
import io.javaoperatorsdk.webhook.admission.NotAllowedException;
1212
import io.javaoperatorsdk.webhook.admission.Operation;
@@ -15,37 +15,48 @@
1515

1616
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.admissionResponseFromMutation;
1717
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.getTargetResource;
18+
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.notAllowedExceptionToAdmissionResponse;
1819

1920
public class AsyncDefaultAdmissionRequestMutator<T extends KubernetesResource>
2021
implements AsyncAdmissionRequestHandler {
2122

22-
private final AsyncMutator<T> mutator;
23+
private final AsyncMutator<T> asyncMutator;
2324
private final Cloner<T> cloner;
2425

25-
public AsyncDefaultAdmissionRequestMutator(AsyncMutator<T> mutator) {
26+
public AsyncDefaultAdmissionRequestMutator(Mutator<T> mutator) {
2627
this(mutator, new ObjectMapperCloner<>());
2728
}
2829

29-
public AsyncDefaultAdmissionRequestMutator(AsyncMutator<T> mutator, Cloner<T> cloner) {
30-
this.mutator = mutator;
30+
public AsyncDefaultAdmissionRequestMutator(Mutator<T> mutator, Cloner<T> cloner) {
31+
this((AsyncMutator<T>) (resource, operation) -> CompletableFuture.supplyAsync(
32+
() -> mutator.mutate(resource, operation)), cloner);
33+
}
34+
35+
public AsyncDefaultAdmissionRequestMutator(AsyncMutator<T> asyncMutator) {
36+
this(asyncMutator, new ObjectMapperCloner<>());
37+
}
38+
39+
public AsyncDefaultAdmissionRequestMutator(AsyncMutator<T> asyncMutator, Cloner<T> cloner) {
40+
this.asyncMutator = asyncMutator;
3141
this.cloner = cloner;
3242
}
3343

3444
@Override
45+
@SuppressWarnings("unchecked")
3546
public CompletionStage<AdmissionResponse> handle(AdmissionRequest admissionRequest) {
36-
Operation operation = Operation.valueOf(admissionRequest.getOperation());
47+
var operation = Operation.valueOf(admissionRequest.getOperation());
3748
var originalResource = (T) getTargetResource(admissionRequest, operation);
3849
var clonedResource = cloner.clone(originalResource);
39-
CompletionStage<AdmissionResponse> admissionResponse;
40-
try {
41-
var mutatedResource = mutator.mutate(clonedResource, operation);
42-
admissionResponse =
43-
mutatedResource.thenApply(mr -> admissionResponseFromMutation(originalResource, mr));
44-
} catch (NotAllowedException e) {
45-
admissionResponse = CompletableFuture
46-
.supplyAsync(() -> AdmissionUtils.notAllowedExceptionToAdmissionResponse(e));
47-
}
48-
return admissionResponse;
50+
return asyncMutator.mutate(clonedResource, operation)
51+
.thenApply(resource -> admissionResponseFromMutation(originalResource, resource))
52+
.exceptionally(e -> {
53+
if (e instanceof CompletionException) {
54+
if (e.getCause() instanceof NotAllowedException) {
55+
return notAllowedExceptionToAdmissionResponse((NotAllowedException) e.getCause());
56+
}
57+
throw new IllegalStateException(e.getCause());
58+
}
59+
throw new IllegalStateException(e);
60+
});
4961
}
50-
5162
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,4 @@
99
public interface AsyncMutator<T extends KubernetesResource> {
1010

1111
CompletionStage<T> mutate(T resource, Operation operation) throws NotAllowedException;
12-
1312
}

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

+5-7
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionRequest;
55
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionResponse;
66
import io.javaoperatorsdk.webhook.admission.AdmissionRequestHandler;
7-
import io.javaoperatorsdk.webhook.admission.AdmissionUtils;
87
import io.javaoperatorsdk.webhook.admission.NotAllowedException;
98
import io.javaoperatorsdk.webhook.admission.Operation;
109
import io.javaoperatorsdk.webhook.clone.Cloner;
1110
import io.javaoperatorsdk.webhook.clone.ObjectMapperCloner;
1211

1312
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.admissionResponseFromMutation;
1413
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.getTargetResource;
14+
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.notAllowedExceptionToAdmissionResponse;
1515

1616
public class DefaultAdmissionRequestMutator<T extends KubernetesResource>
1717
implements AdmissionRequestHandler {
@@ -29,18 +29,16 @@ public DefaultAdmissionRequestMutator(Mutator<T> mutator, Cloner<T> cloner) {
2929
}
3030

3131
@Override
32+
@SuppressWarnings("unchecked")
3233
public AdmissionResponse handle(AdmissionRequest admissionRequest) {
33-
Operation operation = Operation.valueOf(admissionRequest.getOperation());
34+
var operation = Operation.valueOf(admissionRequest.getOperation());
3435
var originalResource = (T) getTargetResource(admissionRequest, operation);
3536
var clonedResource = cloner.clone(originalResource);
36-
AdmissionResponse admissionResponse;
3737
try {
3838
var mutatedResource = mutator.mutate(clonedResource, operation);
39-
admissionResponse = admissionResponseFromMutation(originalResource, mutatedResource);
39+
return admissionResponseFromMutation(originalResource, mutatedResource);
4040
} catch (NotAllowedException e) {
41-
admissionResponse = AdmissionUtils.notAllowedExceptionToAdmissionResponse(e);
41+
return notAllowedExceptionToAdmissionResponse(e);
4242
}
43-
return admissionResponse;
4443
}
45-
4644
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,4 @@
1212
public interface Mutator<T extends KubernetesResource> {
1313

1414
T mutate(T resource, Operation operation) throws NotAllowedException;
15-
1615
}

core/src/main/java/io/javaoperatorsdk/webhook/admission/validation/AsyncDefaultAdmissionRequestValidator.java

+6-15
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
import io.fabric8.kubernetes.api.model.KubernetesResource;
88
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionRequest;
99
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionResponse;
10-
import io.javaoperatorsdk.webhook.admission.AdmissionUtils;
1110
import io.javaoperatorsdk.webhook.admission.AsyncAdmissionRequestHandler;
1211
import io.javaoperatorsdk.webhook.admission.NotAllowedException;
1312
import io.javaoperatorsdk.webhook.admission.Operation;
1413

14+
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.allowedAdmissionResponse;
1515
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.getTargetResource;
16+
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.notAllowedExceptionToAdmissionResponse;
1617

1718
public class AsyncDefaultAdmissionRequestValidator<T extends KubernetesResource>
1819
implements AsyncAdmissionRequestHandler {
@@ -26,30 +27,20 @@ public AsyncDefaultAdmissionRequestValidator(Validator<T> validator) {
2627
@Override
2728
@SuppressWarnings("unchecked")
2829
public CompletionStage<AdmissionResponse> handle(AdmissionRequest admissionRequest) {
29-
Operation operation = Operation.valueOf(admissionRequest.getOperation());
30+
var operation = Operation.valueOf(admissionRequest.getOperation());
3031
var originalResource = (T) getTargetResource(admissionRequest, operation);
31-
3232
var asyncValidate =
3333
CompletableFuture.runAsync(() -> validator.validate(originalResource, operation));
3434
return asyncValidate
3535
.thenApply(v -> allowedAdmissionResponse())
3636
.exceptionally(e -> {
3737
if (e instanceof CompletionException) {
3838
if (e.getCause() instanceof NotAllowedException) {
39-
return AdmissionUtils.notAllowedExceptionToAdmissionResponse(
40-
(NotAllowedException) e.getCause());
41-
} else {
42-
throw new IllegalStateException(e.getCause());
39+
return notAllowedExceptionToAdmissionResponse((NotAllowedException) e.getCause());
4340
}
44-
} else {
45-
throw new IllegalStateException(e);
41+
throw new IllegalStateException(e.getCause());
4642
}
43+
throw new IllegalStateException(e);
4744
});
4845
}
49-
50-
private AdmissionResponse allowedAdmissionResponse() {
51-
AdmissionResponse admissionResponse = new AdmissionResponse();
52-
admissionResponse.setAllowed(true);
53-
return admissionResponse;
54-
}
5546
}

core/src/main/java/io/javaoperatorsdk/webhook/admission/validation/DefaultAdmissionRequestValidator.java

+6-12
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionRequest;
55
import io.fabric8.kubernetes.api.model.admission.v1.AdmissionResponse;
66
import io.javaoperatorsdk.webhook.admission.AdmissionRequestHandler;
7-
import io.javaoperatorsdk.webhook.admission.AdmissionUtils;
87
import io.javaoperatorsdk.webhook.admission.NotAllowedException;
98
import io.javaoperatorsdk.webhook.admission.Operation;
109

10+
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.allowedAdmissionResponse;
1111
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.getTargetResource;
12+
import static io.javaoperatorsdk.webhook.admission.AdmissionUtils.notAllowedExceptionToAdmissionResponse;
1213

1314
public class DefaultAdmissionRequestValidator<T extends KubernetesResource>
1415
implements AdmissionRequestHandler {
@@ -20,22 +21,15 @@ public DefaultAdmissionRequestValidator(Validator<T> validator) {
2021
}
2122

2223
@Override
24+
@SuppressWarnings("unchecked")
2325
public AdmissionResponse handle(AdmissionRequest admissionRequest) {
24-
Operation operation = Operation.valueOf(admissionRequest.getOperation());
26+
var operation = Operation.valueOf(admissionRequest.getOperation());
2527
var originalResource = (T) getTargetResource(admissionRequest, operation);
26-
AdmissionResponse admissionResponse;
2728
try {
2829
validator.validate(originalResource, operation);
29-
admissionResponse = allowedAdmissionResponse();
30+
return allowedAdmissionResponse();
3031
} catch (NotAllowedException e) {
31-
admissionResponse = AdmissionUtils.notAllowedExceptionToAdmissionResponse(e);
32+
return notAllowedExceptionToAdmissionResponse(e);
3233
}
33-
return admissionResponse;
34-
}
35-
36-
private AdmissionResponse allowedAdmissionResponse() {
37-
AdmissionResponse admissionResponse = new AdmissionResponse();
38-
admissionResponse.setAllowed(true);
39-
return admissionResponse;
4034
}
4135
}

core/src/main/java/io/javaoperatorsdk/webhook/admission/validation/Validator.java

-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@
77
public interface Validator<T extends KubernetesResource> {
88

99
void validate(T resource, Operation operation) throws NotAllowedException;
10-
1110
}

core/src/main/java/io/javaoperatorsdk/webhook/clone/Cloner.java

-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,4 @@ public interface Cloner<R> {
99
* @return a deep copy of the given object if it isn't {@code null}, {@code null} otherwise
1010
*/
1111
R clone(R object);
12-
1312
}

core/src/main/java/io/javaoperatorsdk/webhook/clone/ObjectMapperCloner.java

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public class ObjectMapperCloner<T> implements Cloner<T> {
88
private final ObjectMapper objectMapper = new ObjectMapper();
99

1010
@Override
11+
@SuppressWarnings("unchecked")
1112
public T clone(T object) {
1213
if (object == null) {
1314
return null;

0 commit comments

Comments
 (0)