Skip to content

Commit cc43041

Browse files
committed
fix: Add NPE protections to the operator with proper validation messsages
1 parent cf7b271 commit cc43041

7 files changed

+66
-11
lines changed

source/rhoas/README.md

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ This operator creates and manages custom resources used by the RHOAS Kafka Servi
44
# Prerequesites
55
* Java 11+
66
* Maven
7-
* A service-api token from cloud.redhat.com (Talk to Pete)
87
* Access to a RHOAS services .
98

109
# Building and Running

source/rhoas/src/main/java/com/openshift/cloud/controllers/AbstractCloudServicesController.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ public abstract class AbstractCloudServicesController<T extends CustomResource>
2929
* @param resource
3030
* @param context
3131
*/
32-
abstract void doCreateOrUpdateResource(T resource, Context<T> context)
33-
throws ConditionAwareException;
32+
abstract void doCreateOrUpdateResource(T resource, Context<T> context) throws Throwable;
3433

3534
@Override
3635
/** This method is overriden by the proxies, but should not be overriden by you, the developer. */

source/rhoas/src/main/java/com/openshift/cloud/controllers/CloudServiceAccountRequestController.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.openshift.cloud.beans.AccessTokenSecretTool;
44
import com.openshift.cloud.beans.KafkaApiClient;
55
import com.openshift.cloud.beans.KafkaK8sClients;
6+
import com.openshift.cloud.utils.InvalidUserInputException;
67
import com.openshift.cloud.v1alpha.models.CloudServiceAccountRequest;
78
import io.javaoperatorsdk.operator.api.*;
89
import java.time.Instant;
@@ -22,8 +23,9 @@ public class CloudServiceAccountRequestController
2223
@Override
2324
void doCreateOrUpdateResource(
2425
CloudServiceAccountRequest resource, Context<CloudServiceAccountRequest> context)
25-
throws ConditionAwareException {
26+
throws ConditionAwareException, InvalidUserInputException {
2627

28+
validateResource(resource);
2729
var accessTokenSecretName = resource.getSpec().getAccessTokenSecretName();
2830
var namespace = resource.getMetadata().getNamespace();
2931

@@ -42,4 +44,15 @@ void doCreateOrUpdateResource(
4244

4345
resource.setStatus(status);
4446
}
47+
48+
void validateResource(CloudServiceAccountRequest resource) throws InvalidUserInputException {
49+
ConditionUtil.assertNotNull(resource.getSpec(), "spec");
50+
ConditionUtil.assertNotNull(
51+
resource.getSpec().getAccessTokenSecretName(), "spec.accessTokenSecretName");
52+
ConditionUtil.assertNotNull(
53+
resource.getSpec().getServiceAccountName(), "spec.serviceAccountName");
54+
ConditionUtil.assertNotNull(
55+
resource.getSpec().getServiceAccountSecretName(), "spec.serviceAccountSecretName");
56+
ConditionUtil.assertNotNull(resource.getMetadata().getNamespace(), "metadata.namespace");
57+
}
4558
}

source/rhoas/src/main/java/com/openshift/cloud/controllers/CloudServicesRequestController.java

+11-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.openshift.cloud.beans.AccessTokenSecretTool;
44
import com.openshift.cloud.beans.KafkaApiClient;
55
import com.openshift.cloud.beans.KafkaK8sClients;
6+
import com.openshift.cloud.utils.InvalidUserInputException;
67
import com.openshift.cloud.v1alpha.models.CloudServicesRequest;
78
import com.openshift.cloud.v1alpha.models.UserKafka;
89
import io.javaoperatorsdk.operator.api.*;
@@ -26,11 +27,7 @@ public class CloudServicesRequestController
2627

2728
public CloudServicesRequestController() {}
2829

29-
/**
30-
* @param resource the resource to check for new kafkas
31-
* @return true if there were changes, false otherwise
32-
* @throws ApiException if something goes wrong connecting to services
33-
*/
30+
/** @return true if there were changes, false otherwise */
3431
@Override
3532
public void init(EventSourceManager eventSourceManager) {
3633
LOG.info("Init! This is where we would add watches for child resources");
@@ -39,9 +36,10 @@ public void init(EventSourceManager eventSourceManager) {
3936
@Override
4037
void doCreateOrUpdateResource(
4138
CloudServicesRequest resource, Context<CloudServicesRequest> context)
42-
throws ConditionAwareException {
39+
throws ConditionAwareException, InvalidUserInputException {
4340
var accessTokenSecretName = resource.getSpec().getAccessTokenSecretName();
4441
var namespace = resource.getMetadata().getNamespace();
42+
validateResource(resource);
4543
String accessToken = null;
4644
accessToken = accessTokenSecretTool.getAccessToken(accessTokenSecretName, namespace);
4745

@@ -69,4 +67,11 @@ void doCreateOrUpdateResource(
6967

7068
resource.getStatus().setUserKafkas(userKafkas);
7169
}
70+
71+
void validateResource(CloudServicesRequest resource) throws InvalidUserInputException {
72+
ConditionUtil.assertNotNull(resource.getSpec(), "spec");
73+
ConditionUtil.assertNotNull(
74+
resource.getSpec().getAccessTokenSecretName(), "spec.accessTokenSecretName");
75+
ConditionUtil.assertNotNull(resource.getMetadata().getNamespace(), "metadata.namespace");
76+
}
7277
}

source/rhoas/src/main/java/com/openshift/cloud/controllers/ConditionUtil.java

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static com.openshift.cloud.v1alpha.models.KafkaCondition.Status.True;
55

66
import com.openshift.cloud.ApiException;
7+
import com.openshift.cloud.utils.InvalidUserInputException;
78
import com.openshift.cloud.v1alpha.models.*;
89
import com.openshift.cloud.v1alpha.models.KafkaCondition.Status;
910
import java.time.ZoneOffset;
@@ -268,4 +269,12 @@ public static String getStandarizedErrorMessage(int statusCode) {
268269
return String.format("Http Error Code %d", statusCode);
269270
}
270271
}
272+
273+
/** Assert value and throw exception if that is not used */
274+
public static void assertNotNull(Object value, String key) throws InvalidUserInputException {
275+
if (value == null) {
276+
var message = String.format("%s should not be null", key);
277+
throw new InvalidUserInputException(key, message);
278+
}
279+
}
271280
}

source/rhoas/src/main/java/com/openshift/cloud/controllers/KafkaConnectionController.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.openshift.cloud.beans.AccessTokenSecretTool;
44
import com.openshift.cloud.beans.KafkaApiClient;
55
import com.openshift.cloud.utils.ConnectionResourcesMetadata;
6+
import com.openshift.cloud.utils.InvalidUserInputException;
67
import com.openshift.cloud.v1alpha.models.KafkaConnection;
78
import io.javaoperatorsdk.operator.api.*;
89
import java.time.Instant;
@@ -20,9 +21,11 @@ public class KafkaConnectionController extends AbstractCloudServicesController<K
2021

2122
@Override
2223
void doCreateOrUpdateResource(KafkaConnection resource, Context<KafkaConnection> context)
23-
throws ConditionAwareException {
24+
throws ConditionAwareException, InvalidUserInputException {
2425
LOG.info(String.format("Creating or Updating resource %s", resource.getMetadata().getName()));
2526

27+
validateResource(resource);
28+
2629
var kafkaId = resource.getSpec().getKafkaId();
2730
var accessTokenSecretName = resource.getSpec().getAccessTokenSecretName();
2831
var serviceAccountSecretName =
@@ -42,4 +45,16 @@ void doCreateOrUpdateResource(KafkaConnection resource, Context<KafkaConnection>
4245
status.setServiceAccountSecretName(serviceAccountSecretName);
4346
status.setMetadata(ConnectionResourcesMetadata.buildKafkaMetadata(kafkaId));
4447
}
48+
49+
void validateResource(KafkaConnection resource) throws InvalidUserInputException {
50+
ConditionUtil.assertNotNull(resource.getSpec(), "spec");
51+
ConditionUtil.assertNotNull(
52+
resource.getSpec().getAccessTokenSecretName(), "spec.accessTokenSecretName");
53+
ConditionUtil.assertNotNull(resource.getSpec().getCredentials(), "spec.credentials");
54+
ConditionUtil.assertNotNull(
55+
resource.getSpec().getCredentials().getServiceAccountSecretName(),
56+
"spec.credentials.serviceAccountSecretName");
57+
ConditionUtil.assertNotNull(resource.getSpec().getKafkaId(), "spec.kafkaId");
58+
ConditionUtil.assertNotNull(resource.getMetadata().getNamespace(), "metadata.namespace");
59+
}
4560
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.openshift.cloud.utils;
2+
3+
/** Exception raised when there is problem with validation of the CR */
4+
public class InvalidUserInputException extends Exception {
5+
6+
/**
7+
* Constructs a new exception with the specified detail message. The cause is not initialized, and
8+
* may subsequently be initialized by a call to {@link #initCause}.
9+
*
10+
* @param field field that was invalid/undefined/not meeting
11+
*/
12+
public InvalidUserInputException(String field, String additionalMessage) {
13+
super(String.format("Missing argument %s in CR, %s", field, additionalMessage));
14+
}
15+
}

0 commit comments

Comments
 (0)