From 36e8ab18b03ac8fadcfe8e56174af1e2cef42a08 Mon Sep 17 00:00:00 2001
From: csviri
Date: Fri, 21 Oct 2022 15:57:15 +0200
Subject: [PATCH 01/25] feat: rbac and informer related behaviors
---
.../operator/RBACBehaviorIT.java | 27 ++++++++
.../RBACBehaviorTestCustomResource.java | 15 +++++
.../RBACBehaviorTestReconciler.java | 65 +++++++++++++++++++
3 files changed, 107 insertions(+)
create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestCustomResource.java
create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
new file mode 100644
index 0000000000..1d8cf080f7
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -0,0 +1,27 @@
+package io.javaoperatorsdk.operator;
+
+import org.junit.jupiter.api.Test;
+
+public class RBACBehaviorIT {
+
+
+ @Test
+ void startsUpWhenNoPermission() {
+
+ }
+
+ @Test
+ void notStartsUpWithoutPermissionIfInstructed() {
+
+ }
+
+ @Test
+ void resilientForLoosingPermissionForCustomResource() {
+
+ }
+
+ @Test
+ void resilientForLoosingPermissionForSecondaryResource() {
+
+ }
+}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestCustomResource.java
new file mode 100644
index 0000000000..6c6879e7c3
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestCustomResource.java
@@ -0,0 +1,15 @@
+package io.javaoperatorsdk.operator.sample.rbacbehavior;
+
+import io.fabric8.kubernetes.api.model.Namespaced;
+import io.fabric8.kubernetes.client.CustomResource;
+import io.fabric8.kubernetes.model.annotation.Group;
+import io.fabric8.kubernetes.model.annotation.ShortNames;
+import io.fabric8.kubernetes.model.annotation.Version;
+
+@Group("sample.javaoperatorsdk")
+@Version("v1")
+@ShortNames("rbt")
+public class RBACBehaviorTestCustomResource
+ extends CustomResource
+ implements Namespaced {
+}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java
new file mode 100644
index 0000000000..62235aea23
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java
@@ -0,0 +1,65 @@
+package io.javaoperatorsdk.operator.sample.rbacbehavior;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ObjectMeta;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.javaoperatorsdk.operator.api.reconciler.*;
+import io.javaoperatorsdk.operator.junit.KubernetesClientAware;
+import io.javaoperatorsdk.operator.processing.event.source.EventSource;
+import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider;
+
+@ControllerConfiguration
+public class RBACBehaviorTestReconciler
+ implements Reconciler, TestExecutionInfoProvider,
+ EventSourceInitializer, KubernetesClientAware {
+
+ private final AtomicInteger numberOfExecutions = new AtomicInteger(0);
+ private KubernetesClient client;
+
+ @Override
+ public UpdateControl reconcile(
+ RBACBehaviorTestCustomResource resource,
+ Context context) {
+
+ return UpdateControl.noUpdate();
+ }
+
+ public int getNumberOfExecutions() {
+ return numberOfExecutions.get();
+ }
+
+ @Override
+ public Map prepareEventSources(
+ EventSourceContext context) {
+
+ return EventSourceInitializer.nameEventSources();
+ }
+
+ ConfigMap configMap(String name, RBACBehaviorTestCustomResource resource) {
+ ConfigMap configMap = new ConfigMap();
+ configMap.setMetadata(new ObjectMeta());
+ configMap.getMetadata().setName(name);
+ configMap.getMetadata().setNamespace(resource.getMetadata().getNamespace());
+ configMap.setData(new HashMap<>());
+ configMap.getData().put(name, name);
+ HashMap labels = new HashMap<>();
+ labels.put("multisecondary", "true");
+ configMap.getMetadata().setLabels(labels);
+ configMap.addOwnerReference(resource);
+ return configMap;
+ }
+
+ @Override
+ public KubernetesClient getKubernetesClient() {
+ return client;
+ }
+
+ @Override
+ public void setKubernetesClient(KubernetesClient kubernetesClient) {
+ this.client = kubernetesClient;
+ }
+}
From 671c2c0385e68756cb803db269a85d75bb8ade73 Mon Sep 17 00:00:00 2001
From: csviri
Date: Mon, 24 Oct 2022 15:27:46 +0200
Subject: [PATCH 02/25] wip
---
.../junit/LocallyRunOperatorExtension.java | 16 ++-
.../operator/RBACBehaviorIT.java | 134 +++++++++++++++++-
.../ConfigMapDependentResource.java | 35 +++++
.../RBACBehaviorTestReconciler.java | 50 ++-----
.../operator/rback-test-full-access-role.yaml | 14 ++
.../operator/rback-test-no-cr-access.yaml | 10 ++
.../operator/rback-test-role-binding.yaml | 13 ++
7 files changed, 225 insertions(+), 47 deletions(-)
create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/ConfigMapDependentResource.java
create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-cr-access.yaml
create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-role-binding.yaml
diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java
index 8f4d62341c..e852455ebf 100644
--- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java
+++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java
@@ -101,6 +101,10 @@ public RegisteredController getRegisteredControllerForReconcile(
return registeredControllers.get(getReconcilerOfType(type));
}
+ public Operator getOperator() {
+ return operator;
+ }
+
@SuppressWarnings("unchecked")
@Override
protected void before(ExtensionContext context) {
@@ -159,12 +163,20 @@ protected void before(ExtensionContext context) {
}
private void applyCrd(String resourceTypeName) {
+ applyCrd(resourceTypeName, getKubernetesClient());
+ }
+
+ public static void applyCrd(Class extends HasMetadata> resourceClass, KubernetesClient client) {
+ applyCrd(ReconcilerUtils.getResourceTypeName(resourceClass), client);
+ }
+
+ public static void applyCrd(String resourceTypeName, KubernetesClient client) {
String path = "/META-INF/fabric8/" + resourceTypeName + "-v1.yml";
- try (InputStream is = getClass().getResourceAsStream(path)) {
+ try (InputStream is = LocallyRunOperatorExtension.class.getResourceAsStream(path)) {
if (is == null) {
throw new IllegalStateException("Cannot find CRD at " + path);
}
- final var crd = getKubernetesClient().load(is);
+ final var crd = client.load(is);
crd.createOrReplace();
Thread.sleep(CRD_READY_WAIT); // readiness is not applicable for CRD, just wait a little
LOGGER.debug("Applied CRD with path: {}", path);
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
index 1d8cf080f7..03682fdefe 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -1,27 +1,153 @@
package io.javaoperatorsdk.operator;
+import java.time.Duration;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.client.ConfigBuilder;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClientBuilder;
+import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
+import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
+import io.javaoperatorsdk.operator.sample.rbacbehavior.RBACBehaviorTestCustomResource;
+import io.javaoperatorsdk.operator.sample.rbacbehavior.RBACBehaviorTestReconciler;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+class RBACBehaviorIT {
+
+ // https://junit.org/junit5/docs/5.1.1/api/org/junit/jupiter/api/extension/TestInstancePostProcessor.html
-public class RBACBehaviorIT {
+ KubernetesClient adminClient = new KubernetesClientBuilder().build();
+ RBACBehaviorTestReconciler reconciler;
+ String actualNamespace;
+ @BeforeEach
+ void beforeEach(TestInfo testInfo) {
+ testInfo.getTestMethod().ifPresent(method -> {
+ actualNamespace = KubernetesResourceUtil.sanitizeName(method.getName());
+ adminClient.resource(namespace()).createOrReplace();
+ });
+
+
+ }
+
+ @AfterEach
+ void cleanup() {
+ adminClient.resource(testCustomResource()).delete();
+ adminClient.resource(namespace()).delete();
+ }
@Test
void startsUpWhenNoPermission() {
+ LocallyRunOperatorExtension.applyCrd(RBACBehaviorTestCustomResource.class, adminClient);
+ adminClient.resource(testCustomResource()).createOrReplace();
+ // todo it should not throw exception
+ fullResourcesAccess();
+ startOperator();
+
+ assertReconciled();
}
+
@Test
- void notStartsUpWithoutPermissionIfInstructed() {
+ void resilientForLoosingPermissionForCustomResource() throws InterruptedException {
+ LocallyRunOperatorExtension.applyCrd(RBACBehaviorTestCustomResource.class, adminClient);
+ fullResourcesAccess();
+ startOperator();
+ noCustomResourceAccess();
+
+ Thread.sleep(3000);
+ adminClient.resource(testCustomResource()).createOrReplace();
+
+ await().pollDelay(Duration.ofMillis(300)).untilAsserted(() -> {
+ assertThat(reconciler.getNumberOfExecutions()).isEqualTo(0);
+ });
}
@Test
- void resilientForLoosingPermissionForCustomResource() {
+ void resilientForLoosingPermissionForSecondaryResource() {
}
@Test
- void resilientForLoosingPermissionForSecondaryResource() {
+ void notStartsUpWithoutPermissionIfInstructed() {
+
+ }
+
+ @Test
+ RBACBehaviorTestCustomResource testCustomResource() {
+ RBACBehaviorTestCustomResource testCustomResource = new RBACBehaviorTestCustomResource();
+ testCustomResource.setMetadata(new ObjectMetaBuilder()
+ .withNamespace(actualNamespace)
+ .withName("test1")
+ .build());
+ return testCustomResource;
+ }
+
+
+ private void assertReconciled() {
+ await().untilAsserted(() -> {
+ assertThat(reconciler.getNumberOfExecutions()).isGreaterThan(0);
+ });
+ }
+
+ KubernetesClient clientUsingServiceAccount() {
+ KubernetesClient client = new KubernetesClientBuilder()
+ .withConfig(new ConfigBuilder()
+ .withImpersonateUsername("rbac-test-user")
+ .withNamespace(actualNamespace)
+ .build())
+ .build();
+ return client;
+ }
+
+ Operator startOperator() {
+ reconciler = new RBACBehaviorTestReconciler();
+ Operator operator = new Operator(clientUsingServiceAccount());
+ operator.register(reconciler);
+ operator.installShutdownHook();
+ operator.start();
+ return operator;
+ }
+
+ private void noCustomResourceAccess() {
+ applyClusterRole("rback-test-no-cr-access.yaml");
+ applyClusterRoleBinding();
+ }
+
+ private void fullResourcesAccess() {
+ applyClusterRole("rback-test-full-access-role.yaml");
+ applyClusterRoleBinding();
+ }
+
+ private void applyClusterRoleBinding() {
+ var clusterRoleBinding = ReconcilerUtils
+ .loadYaml(ClusterRoleBinding.class, this.getClass(), "rback-test-role-binding.yaml");
+ adminClient.resource(clusterRoleBinding).createOrReplace();
+ }
+
+ private void applyClusterRole(String filename) {
+ var clusterRole = ReconcilerUtils
+ .loadYaml(ClusterRole.class, this.getClass(), filename);
+ adminClient.resource(clusterRole).createOrReplace();
+ }
+ private Namespace namespace() {
+ Namespace n = new Namespace();
+ n.setMetadata(new ObjectMetaBuilder()
+ .withName(actualNamespace)
+ .build());
+ return n;
}
}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/ConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/ConfigMapDependentResource.java
new file mode 100644
index 0000000000..463543835f
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/ConfigMapDependentResource.java
@@ -0,0 +1,35 @@
+package io.javaoperatorsdk.operator.sample.rbacbehavior;
+
+import java.util.Map;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
+
+@KubernetesDependent(labelSelector = "app=rbac-test")
+public class ConfigMapDependentResource
+ extends CRUDKubernetesDependentResource {
+
+ public static final String DATA_KEY = "key";
+
+ public ConfigMapDependentResource() {
+ super(ConfigMap.class);
+ }
+
+ @Override
+ protected ConfigMap desired(RBACBehaviorTestCustomResource primary,
+ Context context) {
+ return new ConfigMapBuilder()
+ .withMetadata(new ObjectMetaBuilder()
+ .withLabels(Map.of("app", "rbac-test"))
+ .withName(primary.getMetadata().getName())
+ .withNamespace(primary.getMetadata().getNamespace())
+ .build())
+ .withData(Map.of(DATA_KEY, primary.getMetadata().getName()))
+ .build();
+
+ }
+}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java
index 62235aea23..0f71e49b46 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java
@@ -1,21 +1,19 @@
package io.javaoperatorsdk.operator.sample.rbacbehavior;
-import java.util.HashMap;
-import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.client.KubernetesClient;
-import io.javaoperatorsdk.operator.api.reconciler.*;
-import io.javaoperatorsdk.operator.junit.KubernetesClientAware;
-import io.javaoperatorsdk.operator.processing.event.source.EventSource;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
+import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
+import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider;
-@ControllerConfiguration
+@ControllerConfiguration(dependents = @Dependent(type = ConfigMapDependentResource.class))
public class RBACBehaviorTestReconciler
- implements Reconciler, TestExecutionInfoProvider,
- EventSourceInitializer, KubernetesClientAware {
+ implements Reconciler, TestExecutionInfoProvider {
+
private final AtomicInteger numberOfExecutions = new AtomicInteger(0);
private KubernetesClient client;
@@ -24,7 +22,7 @@ public class RBACBehaviorTestReconciler
public UpdateControl reconcile(
RBACBehaviorTestCustomResource resource,
Context context) {
-
+ numberOfExecutions.addAndGet(1);
return UpdateControl.noUpdate();
}
@@ -32,34 +30,4 @@ public int getNumberOfExecutions() {
return numberOfExecutions.get();
}
- @Override
- public Map prepareEventSources(
- EventSourceContext context) {
-
- return EventSourceInitializer.nameEventSources();
- }
-
- ConfigMap configMap(String name, RBACBehaviorTestCustomResource resource) {
- ConfigMap configMap = new ConfigMap();
- configMap.setMetadata(new ObjectMeta());
- configMap.getMetadata().setName(name);
- configMap.getMetadata().setNamespace(resource.getMetadata().getNamespace());
- configMap.setData(new HashMap<>());
- configMap.getData().put(name, name);
- HashMap labels = new HashMap<>();
- labels.put("multisecondary", "true");
- configMap.getMetadata().setLabels(labels);
- configMap.addOwnerReference(resource);
- return configMap;
- }
-
- @Override
- public KubernetesClient getKubernetesClient() {
- return client;
- }
-
- @Override
- public void setKubernetesClient(KubernetesClient kubernetesClient) {
- this.client = kubernetesClient;
- }
}
diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
new file mode 100644
index 0000000000..ff8f79f559
--- /dev/null
+++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
@@ -0,0 +1,14 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ # "namespace" omitted since ClusterRoles are not namespaced
+ name: rbac-behavior
+rules:
+ - apiGroups: [ "sample.javaoperatorsdk" ]
+ resources: [ "rbacbehaviortestcustomresources" ]
+ verbs: [ "get", "watch", "list","post", "delete" ]
+ - apiGroups: [""]
+ resources: [ "configmaps" ]
+ verbs: [ "get", "watch", "list","post", "delete","create" ]
+
+
diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-cr-access.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-cr-access.yaml
new file mode 100644
index 0000000000..8c6ae85aac
--- /dev/null
+++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-cr-access.yaml
@@ -0,0 +1,10 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ # "namespace" omitted since ClusterRoles are not namespaced
+ name: rbac-behavior
+rules:
+ - apiGroups: [""]
+ resources: [ "configmaps" ]
+ verbs: [ "get", "watch", "list","post", "delete","create" ]
+
diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-role-binding.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-role-binding.yaml
new file mode 100644
index 0000000000..5b9c9ee2d9
--- /dev/null
+++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-role-binding.yaml
@@ -0,0 +1,13 @@
+apiVersion: rbac.authorization.k8s.io/v1
+# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace.
+kind: ClusterRoleBinding
+metadata:
+ name: read-secrets-global
+subjects:
+ - kind: User
+ name: rbac-test-user
+ apiGroup: rbac.authorization.k8s.io
+roleRef:
+ kind: ClusterRole
+ name: rbac-behavior
+ apiGroup: rbac.authorization.k8s.io
\ No newline at end of file
From 0ab11b9781dcc6dd26b2a1cb28182ff90787a062 Mon Sep 17 00:00:00 2001
From: csviri
Date: Mon, 24 Oct 2022 17:22:00 +0200
Subject: [PATCH 03/25] comment
---
.../test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
index 03682fdefe..ce65fe1e44 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -25,6 +25,7 @@
class RBACBehaviorIT {
// https://junit.org/junit5/docs/5.1.1/api/org/junit/jupiter/api/extension/TestInstancePostProcessor.html
+ // minikube start --extra-config=apiserver.min-request-timeout=3
KubernetesClient adminClient = new KubernetesClientBuilder().build();
RBACBehaviorTestReconciler reconciler;
@@ -66,7 +67,7 @@ void resilientForLoosingPermissionForCustomResource() throws InterruptedExceptio
startOperator();
noCustomResourceAccess();
- Thread.sleep(3000);
+ Thread.sleep(5000);
adminClient.resource(testCustomResource()).createOrReplace();
await().pollDelay(Duration.ofMillis(300)).untilAsserted(() -> {
From 56a00339a8d1498eed60e45b9fe422bc27c502ec Mon Sep 17 00:00:00 2001
From: csviri
Date: Tue, 25 Oct 2022 10:23:15 +0200
Subject: [PATCH 04/25] wip
---
.../operator/RBACBehaviorIT.java | 57 +++++++++++++++----
.../rback-test-no-configmap-access.yaml | 11 ++++
2 files changed, 58 insertions(+), 10 deletions(-)
create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-configmap-access.yaml
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
index ce65fe1e44..db81d881d8 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -23,6 +23,7 @@
import static org.awaitility.Awaitility.await;
class RBACBehaviorIT {
+ public static final String TEST_RESOURCE_NAME = "test1";
// https://junit.org/junit5/docs/5.1.1/api/org/junit/jupiter/api/extension/TestInstancePostProcessor.html
// minikube start --extra-config=apiserver.min-request-timeout=3
@@ -33,6 +34,7 @@ class RBACBehaviorIT {
@BeforeEach
void beforeEach(TestInfo testInfo) {
+ LocallyRunOperatorExtension.applyCrd(RBACBehaviorTestCustomResource.class, adminClient);
testInfo.getTestMethod().ifPresent(method -> {
actualNamespace = KubernetesResourceUtil.sanitizeName(method.getName());
adminClient.resource(namespace()).createOrReplace();
@@ -48,37 +50,64 @@ void cleanup() {
}
@Test
- void startsUpWhenNoPermission() {
- LocallyRunOperatorExtension.applyCrd(RBACBehaviorTestCustomResource.class, adminClient);
+ void startsUpWhenNoPermissionToCustomResource() {
+
adminClient.resource(testCustomResource()).createOrReplace();
// todo it should not throw exception
- fullResourcesAccess();
+ setFullResourcesAccess();
startOperator();
assertReconciled();
}
+ @Test
+ void startsUpWhenNoPermissionToSecondaryResource() {
+
+ }
@Test
void resilientForLoosingPermissionForCustomResource() throws InterruptedException {
- LocallyRunOperatorExtension.applyCrd(RBACBehaviorTestCustomResource.class, adminClient);
- fullResourcesAccess();
+ setFullResourcesAccess();
startOperator();
- noCustomResourceAccess();
+ setNoCustomResourceAccess();
- Thread.sleep(5000);
+ waitForWatchReconnect();
adminClient.resource(testCustomResource()).createOrReplace();
await().pollDelay(Duration.ofMillis(300)).untilAsserted(() -> {
assertThat(reconciler.getNumberOfExecutions()).isEqualTo(0);
});
+ setFullResourcesAccess();
+ assertReconciled();
}
@Test
void resilientForLoosingPermissionForSecondaryResource() {
+ setFullResourcesAccess();
+ startOperator();
+ setNoConfigMapAccess();
+
+ waitForWatchReconnect();
+ adminClient.resource(testCustomResource()).createOrReplace();
+
+ await().pollDelay(Duration.ofMillis(300)).untilAsserted(() -> {
+ var cm =
+ adminClient.configMaps().inNamespace(actualNamespace).withName(TEST_RESOURCE_NAME).get();
+ assertThat(cm).isNull();
+ });
+
+ setFullResourcesAccess();
+ assertReconciled();
+ }
+ private static void waitForWatchReconnect() {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
}
@Test
@@ -91,7 +120,7 @@ RBACBehaviorTestCustomResource testCustomResource() {
RBACBehaviorTestCustomResource testCustomResource = new RBACBehaviorTestCustomResource();
testCustomResource.setMetadata(new ObjectMetaBuilder()
.withNamespace(actualNamespace)
- .withName("test1")
+ .withName(TEST_RESOURCE_NAME)
.build());
return testCustomResource;
}
@@ -100,6 +129,9 @@ RBACBehaviorTestCustomResource testCustomResource() {
private void assertReconciled() {
await().untilAsserted(() -> {
assertThat(reconciler.getNumberOfExecutions()).isGreaterThan(0);
+ var cm =
+ adminClient.configMaps().inNamespace(actualNamespace).withName(TEST_RESOURCE_NAME).get();
+ assertThat(cm).isNotNull();
});
}
@@ -122,12 +154,17 @@ Operator startOperator() {
return operator;
}
- private void noCustomResourceAccess() {
+ private void setNoConfigMapAccess() {
+ applyClusterRole("rback-test-no-configmap-access.yaml");
+ applyClusterRoleBinding();
+ }
+
+ private void setNoCustomResourceAccess() {
applyClusterRole("rback-test-no-cr-access.yaml");
applyClusterRoleBinding();
}
- private void fullResourcesAccess() {
+ private void setFullResourcesAccess() {
applyClusterRole("rback-test-full-access-role.yaml");
applyClusterRoleBinding();
}
diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-configmap-access.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-configmap-access.yaml
new file mode 100644
index 0000000000..16e52add81
--- /dev/null
+++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-configmap-access.yaml
@@ -0,0 +1,11 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ # "namespace" omitted since ClusterRoles are not namespaced
+ name: rbac-behavior
+rules:
+ - apiGroups: [ "sample.javaoperatorsdk" ]
+ resources: [ "rbacbehaviortestcustomresources" ]
+ verbs: [ "get", "watch", "list","post", "delete" ]
+
+
From f80575c42e297b7e8af1e52eed1832e91125640a Mon Sep 17 00:00:00 2001
From: csviri
Date: Tue, 25 Oct 2022 12:45:54 +0200
Subject: [PATCH 05/25] wip
---
.../test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
index db81d881d8..2e7b6a544b 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -104,7 +104,7 @@ void resilientForLoosingPermissionForSecondaryResource() {
private static void waitForWatchReconnect() {
try {
- Thread.sleep(5000);
+ Thread.sleep(6000);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
From 0e4ccc0b2ad72418efa8d451d6e9774e2dd1717c Mon Sep 17 00:00:00 2001
From: csviri
Date: Tue, 25 Oct 2022 12:46:40 +0200
Subject: [PATCH 06/25] wip
---
.../test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
index 2e7b6a544b..2fdfb8ee80 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -114,8 +114,7 @@ private static void waitForWatchReconnect() {
void notStartsUpWithoutPermissionIfInstructed() {
}
-
- @Test
+
RBACBehaviorTestCustomResource testCustomResource() {
RBACBehaviorTestCustomResource testCustomResource = new RBACBehaviorTestCustomResource();
testCustomResource.setMetadata(new ObjectMetaBuilder()
From 756d1f7639096c334eca4462981516f96116700b Mon Sep 17 00:00:00 2001
From: csviri
Date: Tue, 25 Oct 2022 13:04:06 +0200
Subject: [PATCH 07/25] wip
---
.../java/io/javaoperatorsdk/operator/RBACBehaviorIT.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
index 2fdfb8ee80..b84e37f51d 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -53,8 +53,8 @@ void cleanup() {
void startsUpWhenNoPermissionToCustomResource() {
adminClient.resource(testCustomResource()).createOrReplace();
- // todo it should not throw exception
- setFullResourcesAccess();
+ setNoCustomResourceAccess();
+ // setFullResourcesAccess();
startOperator();
@@ -114,7 +114,7 @@ private static void waitForWatchReconnect() {
void notStartsUpWithoutPermissionIfInstructed() {
}
-
+
RBACBehaviorTestCustomResource testCustomResource() {
RBACBehaviorTestCustomResource testCustomResource = new RBACBehaviorTestCustomResource();
testCustomResource.setMetadata(new ObjectMetaBuilder()
From 0243b8b878ffd247632a138ab08c153c29c83b45 Mon Sep 17 00:00:00 2001
From: csviri
Date: Tue, 25 Oct 2022 14:13:24 +0200
Subject: [PATCH 08/25] wip
---
.../api/config/ConfigurationService.java | 4 ++
.../config/ConfigurationServiceOverrider.java | 13 ++++++
.../source/informer/InformerWrapper.java | 13 ++++--
.../operator/RBACBehaviorIT.java | 43 +++++++++++++------
.../operator/rback-test-full-access-role.yaml | 4 +-
5 files changed, 60 insertions(+), 17 deletions(-)
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
index 72099f7fcb..6ea1f143f5 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
@@ -152,6 +152,10 @@ default Optional getLeaderElectionConfiguration() {
return Optional.empty();
}
+ default boolean stopOnInformerErrorDuringStartup() {
+ return true;
+ }
+
default Optional getInformerStoppedHandler() {
return Optional.of((informer, ex) -> {
if (ex != null) {
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
index ee442c07fa..97f0db1967 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
@@ -27,6 +27,7 @@ public class ConfigurationServiceOverrider {
private ExecutorService workflowExecutorService;
private LeaderElectionConfiguration leaderElectionConfiguration;
private InformerStoppedHandler informerStoppedHandler;
+ private Boolean stopOnInformerErrorDuringStartup;
ConfigurationServiceOverrider(ConfigurationService original) {
this.original = original;
@@ -99,6 +100,12 @@ public ConfigurationServiceOverrider withInformerStoppedHandler(InformerStoppedH
return this;
}
+ public ConfigurationServiceOverrider withStopOnInformerErrorDuringStartup(
+ Boolean stopOnInformerErrorDuringStartup) {
+ this.stopOnInformerErrorDuringStartup = stopOnInformerErrorDuringStartup;
+ return this;
+ }
+
public ConfigurationService build() {
return new BaseConfigurationService(original.getVersion(), cloner, objectMapper) {
@Override
@@ -171,6 +178,12 @@ public Optional getInformerStoppedHandler() {
return informerStoppedHandler != null ? Optional.of(informerStoppedHandler)
: original.getInformerStoppedHandler();
}
+
+ @Override
+ public boolean stopOnInformerErrorDuringStartup() {
+ return stopOnInformerErrorDuringStartup != null ? stopOnInformerErrorDuringStartup
+ : super.stopOnInformerErrorDuringStartup();
+ }
};
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
index 90bf01267c..5f7c7e127c 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
@@ -37,10 +37,17 @@ public InformerWrapper(SharedIndexInformer informer) {
@Override
public void start() throws OperatorException {
try {
- informer.run();
-
+ var configService = ConfigurationServiceProvider.instance();
+ if (configService.stopOnInformerErrorDuringStartup()) {
+ informer.run();
+ } else {
+ informer.start().exceptionally((e) -> {
+ log.error("Error", e);
+ return null;
+ });
+ }
// register stopped handler if we have one defined
- ConfigurationServiceProvider.instance().getInformerStoppedHandler()
+ configService.getInformerStoppedHandler()
.ifPresent(ish -> {
final var stopped = informer.stopped();
if (stopped != null) {
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
index b84e37f51d..732cfc134b 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -6,6 +6,8 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import io.fabric8.kubernetes.api.model.Namespace;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
@@ -23,6 +25,9 @@
import static org.awaitility.Awaitility.await;
class RBACBehaviorIT {
+
+ private final static Logger log = LoggerFactory.getLogger(RBACBehaviorIT.class);
+
public static final String TEST_RESOURCE_NAME = "test1";
// https://junit.org/junit5/docs/5.1.1/api/org/junit/jupiter/api/extension/TestInstancePostProcessor.html
@@ -39,8 +44,6 @@ void beforeEach(TestInfo testInfo) {
actualNamespace = KubernetesResourceUtil.sanitizeName(method.getName());
adminClient.resource(namespace()).createOrReplace();
});
-
-
}
@AfterEach
@@ -51,13 +54,15 @@ void cleanup() {
@Test
void startsUpWhenNoPermissionToCustomResource() {
-
adminClient.resource(testCustomResource()).createOrReplace();
setNoCustomResourceAccess();
- // setFullResourcesAccess();
- startOperator();
+ startOperator(false);
+ assertNotReconciled();
+
+ setFullResourcesAccess();
+ waitForWatchReconnect();
assertReconciled();
}
@@ -69,24 +74,23 @@ void startsUpWhenNoPermissionToSecondaryResource() {
@Test
void resilientForLoosingPermissionForCustomResource() throws InterruptedException {
setFullResourcesAccess();
- startOperator();
+ startOperator(true);
setNoCustomResourceAccess();
waitForWatchReconnect();
adminClient.resource(testCustomResource()).createOrReplace();
- await().pollDelay(Duration.ofMillis(300)).untilAsserted(() -> {
- assertThat(reconciler.getNumberOfExecutions()).isEqualTo(0);
- });
+ assertNotReconciled();
setFullResourcesAccess();
assertReconciled();
}
+
@Test
void resilientForLoosingPermissionForSecondaryResource() {
setFullResourcesAccess();
- startOperator();
+ startOperator(true);
setNoConfigMapAccess();
waitForWatchReconnect();
@@ -110,6 +114,13 @@ private static void waitForWatchReconnect() {
}
}
+
+ private void assertNotReconciled() {
+ await().pollDelay(Duration.ofMillis(2000)).untilAsserted(() -> {
+ assertThat(reconciler.getNumberOfExecutions()).isEqualTo(0);
+ });
+ }
+
@Test
void notStartsUpWithoutPermissionIfInstructed() {
@@ -144,9 +155,17 @@ KubernetesClient clientUsingServiceAccount() {
return client;
}
- Operator startOperator() {
+ Operator startOperator(boolean stopOnInformerErrorDuringStartup) {
reconciler = new RBACBehaviorTestReconciler();
- Operator operator = new Operator(clientUsingServiceAccount());
+
+ Operator operator = new Operator(clientUsingServiceAccount(),
+ co -> {
+ co.withStopOnInformerErrorDuringStartup(stopOnInformerErrorDuringStartup);
+ co.withInformerStoppedHandler((informer, ex) -> {
+ informer.start();
+ log.error("Stop handler: {}", informer, ex);
+ });
+ });
operator.register(reconciler);
operator.installShutdownHook();
operator.start();
diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
index ff8f79f559..c27febb067 100644
--- a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
+++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
@@ -7,8 +7,8 @@ rules:
- apiGroups: [ "sample.javaoperatorsdk" ]
resources: [ "rbacbehaviortestcustomresources" ]
verbs: [ "get", "watch", "list","post", "delete" ]
- - apiGroups: [""]
+ - apiGroups: [ "" ]
resources: [ "configmaps" ]
- verbs: [ "get", "watch", "list","post", "delete","create" ]
+ verbs: [ "get", "watch", "list","post", "delete", "create" ]
From cb269ff0635db5859934fc310ff3214bb8a6ea23 Mon Sep 17 00:00:00 2001
From: csviri
Date: Tue, 25 Oct 2022 16:26:36 +0200
Subject: [PATCH 09/25] wp
---
.../source/informer/InformerWrapper.java | 29 ++++++++++++++-----
.../operator/MockKubernetesClient.java | 18 +++---------
.../informer/InformerEventSourceTest.java | 3 +-
.../operator/RBACBehaviorIT.java | 26 +++++++++++++----
4 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
index 5f7c7e127c..3b11b7755d 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
@@ -3,6 +3,9 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -11,6 +14,7 @@
import org.slf4j.LoggerFactory;
import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.client.informers.ExceptionHandler;
import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
import io.fabric8.kubernetes.client.informers.cache.Cache;
@@ -38,14 +42,6 @@ public InformerWrapper(SharedIndexInformer informer) {
public void start() throws OperatorException {
try {
var configService = ConfigurationServiceProvider.instance();
- if (configService.stopOnInformerErrorDuringStartup()) {
- informer.run();
- } else {
- informer.start().exceptionally((e) -> {
- log.error("Error", e);
- return null;
- });
- }
// register stopped handler if we have one defined
configService.getInformerStoppedHandler()
.ifPresent(ish -> {
@@ -66,6 +62,23 @@ public void start() throws OperatorException {
}
});
+ if (!configService.stopOnInformerErrorDuringStartup()) {
+ informer.exceptionHandler((b, t) -> !ExceptionHandler.isDeserializationException(t));
+ }
+ try {
+ var start = informer.start();
+ // todo configurable timeout, also timeout for run?
+ start.toCompletableFuture().get(5000, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException | ExecutionException e) {
+ log.warn("Informer startup error. Informer: {}", informer, e);
+ if (configService.stopOnInformerErrorDuringStartup()) {
+ throw new OperatorException(e);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException(e);
+ }
+
} catch (Exception e) {
log.error("Couldn't start informer for " + versionedFullResourceName() + " resources", e);
ReconcilerUtils.handleKubernetesClientException(e,
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/MockKubernetesClient.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/MockKubernetesClient.java
index 2589f566da..076e13b15b 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/MockKubernetesClient.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/MockKubernetesClient.java
@@ -17,7 +17,6 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -44,19 +43,10 @@ public static KubernetesClient client(Class clazz,
when(resources.inAnyNamespace()).thenReturn(inAnyNamespace);
when(inAnyNamespace.withLabelSelector(nullable(String.class))).thenReturn(filterable);
SharedIndexInformer informer = mock(SharedIndexInformer.class);
- CompletableFuture stopped = new CompletableFuture<>();
- when(informer.stopped()).thenReturn(stopped);
- if (informerRunBehavior != null) {
- doAnswer(invocation -> {
- try {
- informerRunBehavior.accept(null);
- } catch (Exception e) {
- stopped.completeExceptionally(e);
- }
- return null;
- }).when(informer).run();
- }
- doAnswer(invocation -> null).when(informer).stop();
+ CompletableFuture informerStartRes = new CompletableFuture<>();
+ informerStartRes.complete(null);
+ when(informer.start()).thenReturn(informerStartRes);
+
Indexer mockIndexer = mock(Indexer.class);
when(informer.getIndexer()).thenReturn(mockIndexer);
when(filterable.runnableInformer(anyLong())).thenReturn(informer);
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
index e941e8390d..355dd23bb3 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
@@ -243,7 +243,8 @@ void filtersOnDeleteEvents() {
verify(eventHandlerMock, never()).handleEvent(any());
}
- @Test
+ // todo add integration test
+ // @Test
void informerStoppedHandlerShouldBeCalledWhenInformerStops() {
try {
final var exception = new RuntimeException("Informer stopped exceptionally!");
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
index 732cfc134b..0a998b485f 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
@@ -17,12 +17,14 @@
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
+import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.sample.rbacbehavior.RBACBehaviorTestCustomResource;
import io.javaoperatorsdk.operator.sample.rbacbehavior.RBACBehaviorTestReconciler;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertThrows;
class RBACBehaviorIT {
@@ -52,13 +54,21 @@ void cleanup() {
adminClient.resource(namespace()).delete();
}
+ @Test
+ void notStartsUpWithoutPermissionIfInstructed() {
+ adminClient.resource(testCustomResource()).createOrReplace();
+ setNoCustomResourceAccess();
+
+ assertThrows(OperatorException.class, () -> startOperator(true));
+ assertNotReconciled();
+ }
+
@Test
void startsUpWhenNoPermissionToCustomResource() {
adminClient.resource(testCustomResource()).createOrReplace();
setNoCustomResourceAccess();
startOperator(false);
-
assertNotReconciled();
setFullResourcesAccess();
@@ -68,7 +78,15 @@ void startsUpWhenNoPermissionToCustomResource() {
@Test
void startsUpWhenNoPermissionToSecondaryResource() {
+ adminClient.resource(testCustomResource()).createOrReplace();
+ setNoConfigMapAccess();
+ startOperator(false);
+ assertNotReconciled();
+
+ setFullResourcesAccess();
+ waitForWatchReconnect();
+ assertReconciled();
}
@Test
@@ -121,11 +139,6 @@ private void assertNotReconciled() {
});
}
- @Test
- void notStartsUpWithoutPermissionIfInstructed() {
-
- }
-
RBACBehaviorTestCustomResource testCustomResource() {
RBACBehaviorTestCustomResource testCustomResource = new RBACBehaviorTestCustomResource();
testCustomResource.setMetadata(new ObjectMetaBuilder()
@@ -156,6 +169,7 @@ KubernetesClient clientUsingServiceAccount() {
}
Operator startOperator(boolean stopOnInformerErrorDuringStartup) {
+ ConfigurationServiceProvider.reset();
reconciler = new RBACBehaviorTestReconciler();
Operator operator = new Operator(clientUsingServiceAccount(),
From 6783d41a35e0b1230c922385108f606a340f9003 Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 11:01:07 +0200
Subject: [PATCH 10/25] tests
---
.../api/config/ConfigurationService.java | 8 ++++
.../config/ConfigurationServiceOverrider.java | 13 ++++++-
.../source/informer/InformerWrapper.java | 4 +-
.../operator/MockKubernetesClient.java | 19 ++++++++--
.../informer/InformerEventSourceTest.java | 7 ++--
...IT.java => InformerRelatedBehaviorIT.java} | 38 ++++++++++++-------
.../ConfigMapDependentResource.java | 8 ++--
...merRelatedBehaviorTestCustomResource.java} | 4 +-
...nformerRelatedBehaviorTestReconciler.java} | 12 +++---
.../operator/rback-test-full-access-role.yaml | 2 +-
.../rback-test-no-configmap-access.yaml | 2 +-
11 files changed, 79 insertions(+), 38 deletions(-)
rename operator-framework/src/test/java/io/javaoperatorsdk/operator/{RBACBehaviorIT.java => InformerRelatedBehaviorIT.java} (83%)
rename operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/{rbacbehavior => informerrelatedbehavior}/ConfigMapDependentResource.java (76%)
rename operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/{rbacbehavior/RBACBehaviorTestCustomResource.java => informerrelatedbehavior/InformerRelatedBehaviorTestCustomResource.java} (76%)
rename operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/{rbacbehavior/RBACBehaviorTestReconciler.java => informerrelatedbehavior/InformerRelatedBehaviorTestReconciler.java} (67%)
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
index 6ea1f143f5..fc61a80392 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
@@ -156,6 +156,14 @@ default boolean stopOnInformerErrorDuringStartup() {
return true;
}
+ /**
+ * Timeout for cache sync in milliseconds. In other words source start timeout. Note that is
+ * "stopOnInformerErrorDuringStartup" is true, this will be resulted in an operator stop.
+ */
+ default int cacheSyncTimeout() {
+ return 2 * 60 * 1000;
+ }
+
default Optional getInformerStoppedHandler() {
return Optional.of((informer, ex) -> {
if (ex != null) {
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
index 97f0db1967..9cb9dae521 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
@@ -28,6 +28,7 @@ public class ConfigurationServiceOverrider {
private LeaderElectionConfiguration leaderElectionConfiguration;
private InformerStoppedHandler informerStoppedHandler;
private Boolean stopOnInformerErrorDuringStartup;
+ private Integer cacheSyncTimeout;
ConfigurationServiceOverrider(ConfigurationService original) {
this.original = original;
@@ -101,11 +102,16 @@ public ConfigurationServiceOverrider withInformerStoppedHandler(InformerStoppedH
}
public ConfigurationServiceOverrider withStopOnInformerErrorDuringStartup(
- Boolean stopOnInformerErrorDuringStartup) {
+ boolean stopOnInformerErrorDuringStartup) {
this.stopOnInformerErrorDuringStartup = stopOnInformerErrorDuringStartup;
return this;
}
+ public ConfigurationServiceOverrider withCacheSyncTimeout(int cacheSyncTimeout) {
+ this.cacheSyncTimeout = cacheSyncTimeout;
+ return this;
+ }
+
public ConfigurationService build() {
return new BaseConfigurationService(original.getVersion(), cloner, objectMapper) {
@Override
@@ -184,6 +190,11 @@ public boolean stopOnInformerErrorDuringStartup() {
return stopOnInformerErrorDuringStartup != null ? stopOnInformerErrorDuringStartup
: super.stopOnInformerErrorDuringStartup();
}
+
+ @Override
+ public int cacheSyncTimeout() {
+ return cacheSyncTimeout != null ? cacheSyncTimeout : super.cacheSyncTimeout();
+ }
};
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
index 3b11b7755d..533a22c513 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
@@ -61,14 +61,12 @@ public void start() throws OperatorException {
+ fullResourceName + "/" + version);
}
});
-
if (!configService.stopOnInformerErrorDuringStartup()) {
informer.exceptionHandler((b, t) -> !ExceptionHandler.isDeserializationException(t));
}
try {
var start = informer.start();
- // todo configurable timeout, also timeout for run?
- start.toCompletableFuture().get(5000, TimeUnit.MILLISECONDS);
+ start.toCompletableFuture().get(configService.cacheSyncTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException | ExecutionException e) {
log.warn("Informer startup error. Informer: {}", informer, e);
if (configService.stopOnInformerErrorDuringStartup()) {
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/MockKubernetesClient.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/MockKubernetesClient.java
index 076e13b15b..81f8741de9 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/MockKubernetesClient.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/MockKubernetesClient.java
@@ -17,8 +17,8 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.doAnswer;
public class MockKubernetesClient {
@@ -46,7 +46,20 @@ public static KubernetesClient client(Class clazz,
CompletableFuture informerStartRes = new CompletableFuture<>();
informerStartRes.complete(null);
when(informer.start()).thenReturn(informerStartRes);
-
+ CompletableFuture stopped = new CompletableFuture<>();
+ when(informer.stopped()).thenReturn(stopped);
+ when(informer.getApiTypeClass()).thenReturn(clazz);
+ if (informerRunBehavior != null) {
+ doAnswer(invocation -> {
+ try {
+ informerRunBehavior.accept(null);
+ } catch (Exception e) {
+ stopped.completeExceptionally(e);
+ }
+ return stopped;
+ }).when(informer).start();
+ }
+ doAnswer(invocation -> null).when(informer).stop();
Indexer mockIndexer = mock(Indexer.class);
when(informer.getIndexer()).thenReturn(mockIndexer);
when(filterable.runnableInformer(anyLong())).thenReturn(informer);
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
index 355dd23bb3..ec4ef7b5a8 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
@@ -19,6 +19,7 @@
import io.javaoperatorsdk.operator.sample.simple.TestCustomResource;
import static io.javaoperatorsdk.operator.api.reconciler.Constants.DEFAULT_NAMESPACES_SET;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
@@ -243,8 +244,7 @@ void filtersOnDeleteEvents() {
verify(eventHandlerMock, never()).handleEvent(any());
}
- // todo add integration test
- // @Test
+ @Test
void informerStoppedHandlerShouldBeCalledWhenInformerStops() {
try {
final var exception = new RuntimeException("Informer stopped exceptionally!");
@@ -256,7 +256,8 @@ void informerStoppedHandlerShouldBeCalledWhenInformerStops() {
MockKubernetesClient.client(Deployment.class, unused -> {
throw exception;
}));
- informerEventSource.start();
+
+ assertThrows(RuntimeException.class, () -> informerEventSource.start());
verify(informerStoppedHandler, atLeastOnce()).onStop(any(), eq(exception));
} finally {
ConfigurationServiceProvider.reset();
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
similarity index 83%
rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
index 0a998b485f..88f9b01abd 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/RBACBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
@@ -19,29 +19,30 @@
import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
-import io.javaoperatorsdk.operator.sample.rbacbehavior.RBACBehaviorTestCustomResource;
-import io.javaoperatorsdk.operator.sample.rbacbehavior.RBACBehaviorTestReconciler;
+import io.javaoperatorsdk.operator.sample.informerrelatedbehavior.InformerRelatedBehaviorTestCustomResource;
+import io.javaoperatorsdk.operator.sample.informerrelatedbehavior.InformerRelatedBehaviorTestReconciler;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertThrows;
-class RBACBehaviorIT {
+class InformerRelatedBehaviorIT {
- private final static Logger log = LoggerFactory.getLogger(RBACBehaviorIT.class);
+ private final static Logger log = LoggerFactory.getLogger(InformerRelatedBehaviorIT.class);
public static final String TEST_RESOURCE_NAME = "test1";
- // https://junit.org/junit5/docs/5.1.1/api/org/junit/jupiter/api/extension/TestInstancePostProcessor.html
// minikube start --extra-config=apiserver.min-request-timeout=3
KubernetesClient adminClient = new KubernetesClientBuilder().build();
- RBACBehaviorTestReconciler reconciler;
+ InformerRelatedBehaviorTestReconciler reconciler;
String actualNamespace;
+ volatile boolean stopHandlerCalled = false;
@BeforeEach
void beforeEach(TestInfo testInfo) {
- LocallyRunOperatorExtension.applyCrd(RBACBehaviorTestCustomResource.class, adminClient);
+ LocallyRunOperatorExtension.applyCrd(InformerRelatedBehaviorTestCustomResource.class,
+ adminClient);
testInfo.getTestMethod().ifPresent(method -> {
actualNamespace = KubernetesResourceUtil.sanitizeName(method.getName());
adminClient.resource(namespace()).createOrReplace();
@@ -124,6 +125,16 @@ void resilientForLoosingPermissionForSecondaryResource() {
assertReconciled();
}
+ @Test
+ void callsStopHandlerOnStartupFail() {
+ setNoCustomResourceAccess();
+ adminClient.resource(testCustomResource()).createOrReplace();
+
+ assertThrows(OperatorException.class, () -> startOperator(true));
+
+ await().untilAsserted(() -> assertThat(stopHandlerCalled).isTrue());
+ }
+
private static void waitForWatchReconnect() {
try {
Thread.sleep(6000);
@@ -132,15 +143,15 @@ private static void waitForWatchReconnect() {
}
}
-
private void assertNotReconciled() {
await().pollDelay(Duration.ofMillis(2000)).untilAsserted(() -> {
assertThat(reconciler.getNumberOfExecutions()).isEqualTo(0);
});
}
- RBACBehaviorTestCustomResource testCustomResource() {
- RBACBehaviorTestCustomResource testCustomResource = new RBACBehaviorTestCustomResource();
+ InformerRelatedBehaviorTestCustomResource testCustomResource() {
+ InformerRelatedBehaviorTestCustomResource testCustomResource =
+ new InformerRelatedBehaviorTestCustomResource();
testCustomResource.setMetadata(new ObjectMetaBuilder()
.withNamespace(actualNamespace)
.withName(TEST_RESOURCE_NAME)
@@ -148,7 +159,6 @@ RBACBehaviorTestCustomResource testCustomResource() {
return testCustomResource;
}
-
private void assertReconciled() {
await().untilAsserted(() -> {
assertThat(reconciler.getNumberOfExecutions()).isGreaterThan(0);
@@ -170,14 +180,14 @@ KubernetesClient clientUsingServiceAccount() {
Operator startOperator(boolean stopOnInformerErrorDuringStartup) {
ConfigurationServiceProvider.reset();
- reconciler = new RBACBehaviorTestReconciler();
+ reconciler = new InformerRelatedBehaviorTestReconciler();
Operator operator = new Operator(clientUsingServiceAccount(),
co -> {
co.withStopOnInformerErrorDuringStartup(stopOnInformerErrorDuringStartup);
+ co.withCacheSyncTimeout(3000);
co.withInformerStoppedHandler((informer, ex) -> {
- informer.start();
- log.error("Stop handler: {}", informer, ex);
+ stopHandlerCalled = true;
});
});
operator.register(reconciler);
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/ConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/ConfigMapDependentResource.java
similarity index 76%
rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/ConfigMapDependentResource.java
rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/ConfigMapDependentResource.java
index 463543835f..c9747cbd00 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/ConfigMapDependentResource.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/ConfigMapDependentResource.java
@@ -1,4 +1,4 @@
-package io.javaoperatorsdk.operator.sample.rbacbehavior;
+package io.javaoperatorsdk.operator.sample.informerrelatedbehavior;
import java.util.Map;
@@ -11,7 +11,7 @@
@KubernetesDependent(labelSelector = "app=rbac-test")
public class ConfigMapDependentResource
- extends CRUDKubernetesDependentResource {
+ extends CRUDKubernetesDependentResource {
public static final String DATA_KEY = "key";
@@ -20,8 +20,8 @@ public ConfigMapDependentResource() {
}
@Override
- protected ConfigMap desired(RBACBehaviorTestCustomResource primary,
- Context context) {
+ protected ConfigMap desired(InformerRelatedBehaviorTestCustomResource primary,
+ Context context) {
return new ConfigMapBuilder()
.withMetadata(new ObjectMetaBuilder()
.withLabels(Map.of("app", "rbac-test"))
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/InformerRelatedBehaviorTestCustomResource.java
similarity index 76%
rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestCustomResource.java
rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/InformerRelatedBehaviorTestCustomResource.java
index 6c6879e7c3..fa59c15831 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestCustomResource.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/InformerRelatedBehaviorTestCustomResource.java
@@ -1,4 +1,4 @@
-package io.javaoperatorsdk.operator.sample.rbacbehavior;
+package io.javaoperatorsdk.operator.sample.informerrelatedbehavior;
import io.fabric8.kubernetes.api.model.Namespaced;
import io.fabric8.kubernetes.client.CustomResource;
@@ -9,7 +9,7 @@
@Group("sample.javaoperatorsdk")
@Version("v1")
@ShortNames("rbt")
-public class RBACBehaviorTestCustomResource
+public class InformerRelatedBehaviorTestCustomResource
extends CustomResource
implements Namespaced {
}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/InformerRelatedBehaviorTestReconciler.java
similarity index 67%
rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java
rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/InformerRelatedBehaviorTestReconciler.java
index 0f71e49b46..baeff08478 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/rbacbehavior/RBACBehaviorTestReconciler.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informerrelatedbehavior/InformerRelatedBehaviorTestReconciler.java
@@ -1,4 +1,4 @@
-package io.javaoperatorsdk.operator.sample.rbacbehavior;
+package io.javaoperatorsdk.operator.sample.informerrelatedbehavior;
import java.util.concurrent.atomic.AtomicInteger;
@@ -11,17 +11,17 @@
import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider;
@ControllerConfiguration(dependents = @Dependent(type = ConfigMapDependentResource.class))
-public class RBACBehaviorTestReconciler
- implements Reconciler, TestExecutionInfoProvider {
+public class InformerRelatedBehaviorTestReconciler
+ implements Reconciler, TestExecutionInfoProvider {
private final AtomicInteger numberOfExecutions = new AtomicInteger(0);
private KubernetesClient client;
@Override
- public UpdateControl reconcile(
- RBACBehaviorTestCustomResource resource,
- Context context) {
+ public UpdateControl reconcile(
+ InformerRelatedBehaviorTestCustomResource resource,
+ Context context) {
numberOfExecutions.addAndGet(1);
return UpdateControl.noUpdate();
}
diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
index c27febb067..024f298462 100644
--- a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
+++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-full-access-role.yaml
@@ -5,7 +5,7 @@ metadata:
name: rbac-behavior
rules:
- apiGroups: [ "sample.javaoperatorsdk" ]
- resources: [ "rbacbehaviortestcustomresources" ]
+ resources: [ "informerrelatedbehaviortestcustomresources" ]
verbs: [ "get", "watch", "list","post", "delete" ]
- apiGroups: [ "" ]
resources: [ "configmaps" ]
diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-configmap-access.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-configmap-access.yaml
index 16e52add81..bac8c1149f 100644
--- a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-configmap-access.yaml
+++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/rback-test-no-configmap-access.yaml
@@ -5,7 +5,7 @@ metadata:
name: rbac-behavior
rules:
- apiGroups: [ "sample.javaoperatorsdk" ]
- resources: [ "rbacbehaviortestcustomresources" ]
+ resources: [ "informerrelatedbehaviortestcustomresources" ]
verbs: [ "get", "watch", "list","post", "delete" ]
From 9a83f7d35ec3a629c38d31073c38394054673ec1 Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 11:13:58 +0200
Subject: [PATCH 11/25] docs
---
.../api/config/ConfigurationService.java | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
index fc61a80392..6a016340ca 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
@@ -152,18 +152,35 @@ default Optional getLeaderElectionConfiguration() {
return Optional.empty();
}
+ /**
+ *
+ * if true, operator stops if there are some issues with informers
+ * {@link io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource} or
+ * {@link io.javaoperatorsdk.operator.processing.event.source.controller.ControllerResourceEventSource}
+ * on startup. Other event sources may also respect this flag.
+ *
+ *
+ * if false, the startup will ignore recoverable errors, caused for example by RBAC issues, and
+ * will try to reconnect periodically in the background.
+ *
+ */
default boolean stopOnInformerErrorDuringStartup() {
return true;
}
/**
* Timeout for cache sync in milliseconds. In other words source start timeout. Note that is
- * "stopOnInformerErrorDuringStartup" is true, this will be resulted in an operator stop.
+ * "stopOnInformerErrorDuringStartup" is true the operator will stop on timeout. Default is 2
+ * minutes.
*/
default int cacheSyncTimeout() {
return 2 * 60 * 1000;
}
+ /**
+ * Handler for an informer stop. Informer stops if there is a non-recoverable error. Like received
+ * a resource that cannot be deserialized.
+ */
default Optional getInformerStoppedHandler() {
return Optional.of((informer, ex) -> {
if (ex != null) {
From 4a8e23b215a0ccde33199b8813c9b41c6f99117a Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 11:25:45 +0200
Subject: [PATCH 12/25] test category
---
.../operator/InformerRelatedBehaviorIT.java | 24 ++++++++++---------
pom.xml | 16 +++++++++++++
2 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
index 88f9b01abd..0c35dc9d99 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
@@ -2,12 +2,7 @@
import java.time.Duration;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.junit.jupiter.api.*;
import io.fabric8.kubernetes.api.model.Namespace;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
@@ -26,14 +21,21 @@
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertThrows;
+/**
+ * The test relies on a special minikube configuration: "min-request-timeout" to have a very low value, see:
+ * "minikube start --extra-config=apiserver.min-request-timeout=3"
+ *
+ *
+ * This is important when tests are affected by permission changes, since the watch permissions are
+ * just checked when established a watch request. So minimal request timeout is set to make sure
+ * that with periodical watch reconnect the permission is tested again.
+ *
+ */
+@Tag("WatchPermissionAwareTest")
class InformerRelatedBehaviorIT {
- private final static Logger log = LoggerFactory.getLogger(InformerRelatedBehaviorIT.class);
-
public static final String TEST_RESOURCE_NAME = "test1";
-
- // minikube start --extra-config=apiserver.min-request-timeout=3
-
+
KubernetesClient adminClient = new KubernetesClientBuilder().build();
InformerRelatedBehaviorTestReconciler reconciler;
String actualNamespace;
diff --git a/pom.xml b/pom.xml
index 521ab7bffb..9e21b8d131 100644
--- a/pom.xml
+++ b/pom.xml
@@ -372,6 +372,22 @@
**/*Test.java
**/*E2E.java
+ WatchPermissionAwareTest
+
+
+
+
+
+
+
+ minimal-watch-timeout-dependent-it
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ WatchPermissionAwareTest
From 4b9bcb7e3dd2b69710dcf7b7d2ef3cdbe429c2c1 Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 11:29:57 +0200
Subject: [PATCH 13/25] format fix
---
.../javaoperatorsdk/operator/InformerRelatedBehaviorIT.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
index 0c35dc9d99..1267d5155e 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
@@ -22,8 +22,8 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
- * The test relies on a special minikube configuration: "min-request-timeout" to have a very low value, see:
- * "minikube start --extra-config=apiserver.min-request-timeout=3"
+ * The test relies on a special minikube configuration: "min-request-timeout" to have a very low
+ * value, see: "minikube start --extra-config=apiserver.min-request-timeout=3"
*
*
* This is important when tests are affected by permission changes, since the watch permissions are
@@ -35,7 +35,7 @@
class InformerRelatedBehaviorIT {
public static final String TEST_RESOURCE_NAME = "test1";
-
+
KubernetesClient adminClient = new KubernetesClientBuilder().build();
InformerRelatedBehaviorTestReconciler reconciler;
String actualNamespace;
From 1b4c0e5cfe7553b8e89dd303acec2ac4f2c98179 Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 11:52:55 +0200
Subject: [PATCH 14/25] PR workflow update
---
.github/workflows/pr.yml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index e7ba5d1efc..188207996d 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -53,3 +53,12 @@ jobs:
driver: 'docker'
- name: Run integration tests
run: ./mvnw ${MAVEN_ARGS} -B package -P no-unit-tests --file pom.xml
+ - name: Set up Minikube
+ uses: manusa/actions-setup-minikube@v2.7.0
+ with:
+ minikube version: 'v1.26.0'
+ kubernetes version: ${{ matrix.kubernetes }}
+ driver: 'docker'
+ start args: '--extra-config=apiserver.min-request-timeout=3'
+ - name: Run integration tests
+ run: ./mvnw ${MAVEN_ARGS} -B package -P minimal-watch-timeout-dependent-it --file pom.xml
\ No newline at end of file
From 959c544e83903737c414a470198b7531e50edc84 Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 13:04:12 +0200
Subject: [PATCH 15/25] PR CI facelift
---
.github/workflows/pr.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 188207996d..e38bc77726 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -53,12 +53,12 @@ jobs:
driver: 'docker'
- name: Run integration tests
run: ./mvnw ${MAVEN_ARGS} -B package -P no-unit-tests --file pom.xml
- - name: Set up Minikube
+ - name: Adjusting Minikube Settings
uses: manusa/actions-setup-minikube@v2.7.0
with:
minikube version: 'v1.26.0'
kubernetes version: ${{ matrix.kubernetes }}
driver: 'docker'
start args: '--extra-config=apiserver.min-request-timeout=3'
- - name: Run integration tests
+ - name: Run WatchPermissionAwareTest Category
run: ./mvnw ${MAVEN_ARGS} -B package -P minimal-watch-timeout-dependent-it --file pom.xml
\ No newline at end of file
From 384462dd17ccd080220c507d7d2f2a1e3bb508ac Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 13:09:43 +0200
Subject: [PATCH 16/25] fix: watch test run ?
---
pom.xml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pom.xml b/pom.xml
index 9e21b8d131..cfe9f71bb4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -387,6 +387,9 @@
org.apache.maven.plugins
maven-surefire-plugin
+
+ **/*IT.java
+
WatchPermissionAwareTest
From 64638e8f3abc8ebe6b64c9d19227b17c7b5d883a Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 13:39:59 +0200
Subject: [PATCH 17/25] fix running test
---
...latedBehaviorIT.java => InformerRelatedBehaviorTest.java} | 5 ++++-
pom.xml | 3 ---
2 files changed, 4 insertions(+), 4 deletions(-)
rename operator-framework/src/test/java/io/javaoperatorsdk/operator/{InformerRelatedBehaviorIT.java => InformerRelatedBehaviorTest.java} (98%)
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorTest.java
similarity index 98%
rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorTest.java
index 1267d5155e..4b25a47f46 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorTest.java
@@ -30,9 +30,12 @@
* just checked when established a watch request. So minimal request timeout is set to make sure
* that with periodical watch reconnect the permission is tested again.
*
+ *
+ * The test does not end with "IT" since that did not work with tags.
+ *
*/
@Tag("WatchPermissionAwareTest")
-class InformerRelatedBehaviorIT {
+class InformerRelatedBehaviorTest {
public static final String TEST_RESOURCE_NAME = "test1";
diff --git a/pom.xml b/pom.xml
index cfe9f71bb4..9e21b8d131 100644
--- a/pom.xml
+++ b/pom.xml
@@ -387,9 +387,6 @@
org.apache.maven.plugins
maven-surefire-plugin
-
- **/*IT.java
-
WatchPermissionAwareTest
From c5f28d8cb5a4bfe8f588e20ab8723fded0b9d318 Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 13:42:18 +0200
Subject: [PATCH 18/25] not run integration tests with tags with unit tests
---
pom.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/pom.xml b/pom.xml
index 9e21b8d131..d83531c6dd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -307,6 +307,7 @@
**/*IT.java
**/*E2E.java
+ WatchPermissionAwareTest
From a8c9e8df9a8325c87265d13643d2f342a9b9f481 Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 14:59:36 +0200
Subject: [PATCH 19/25] test run fix
---
.../event/source/informer/InformerWrapper.java | 3 +++
...viorTest.java => InformerRelatedBehaviorITS.java} | 5 ++---
pom.xml | 12 +++++++++---
3 files changed, 14 insertions(+), 6 deletions(-)
rename operator-framework/src/test/java/io/javaoperatorsdk/operator/{InformerRelatedBehaviorTest.java => InformerRelatedBehaviorITS.java} (98%)
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
index 533a22c513..ffb3b7d15e 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
@@ -66,6 +66,9 @@ public void start() throws OperatorException {
}
try {
var start = informer.start();
+ // note that in case we don't put here timeout and stopOnInformerErrorDuringStartup is
+ // false, and there is a rbac issue the get never returns; therefore operator never really
+ // starts
start.toCompletableFuture().get(configService.cacheSyncTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException | ExecutionException e) {
log.warn("Informer startup error. Informer: {}", informer, e);
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorITS.java
similarity index 98%
rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorTest.java
rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorITS.java
index 4b25a47f46..e3ddb3a1e0 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorTest.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorITS.java
@@ -31,11 +31,10 @@
* that with periodical watch reconnect the permission is tested again.
*
*
- * The test does not end with "IT" since that did not work with tags.
+ * The test ends with "ITS" (Special) since it needs to run separately from other ITs
*
*/
-@Tag("WatchPermissionAwareTest")
-class InformerRelatedBehaviorTest {
+class InformerRelatedBehaviorITS {
public static final String TEST_RESOURCE_NAME = "test1";
diff --git a/pom.xml b/pom.xml
index d83531c6dd..953b8befc6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -373,7 +373,6 @@
**/*Test.java
**/*E2E.java
- WatchPermissionAwareTest
@@ -388,7 +387,14 @@
org.apache.maven.plugins
maven-surefire-plugin
- WatchPermissionAwareTest
+
+ **/*ITS.java
+
+
+ **/*Test.java
+ **/*E2E.java
+ **/*IT.java
+
@@ -418,7 +424,6 @@
release
-
org.apache.maven.plugins
maven-surefire-plugin
@@ -426,6 +431,7 @@
**/*IT.java
**/*E2E.java
+ **/InformerRelatedBehaviorTest.java
From 6b8cfb69d0170865267d9c92ea6a1334c318e92c Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 15:08:56 +0200
Subject: [PATCH 20/25] action name
---
.github/workflows/pr.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index e38bc77726..f3ec0d3397 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -53,7 +53,7 @@ jobs:
driver: 'docker'
- name: Run integration tests
run: ./mvnw ${MAVEN_ARGS} -B package -P no-unit-tests --file pom.xml
- - name: Adjusting Minikube Settings
+ - name: Adjust Minikube Min Request Timeout Setting
uses: manusa/actions-setup-minikube@v2.7.0
with:
minikube version: 'v1.26.0'
From 2dff5520d2231cb86e36831880534e2e262b056d Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 15:19:14 +0200
Subject: [PATCH 21/25] naming
---
.github/workflows/pr.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index f3ec0d3397..ec64e93a39 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -60,5 +60,5 @@ jobs:
kubernetes version: ${{ matrix.kubernetes }}
driver: 'docker'
start args: '--extra-config=apiserver.min-request-timeout=3'
- - name: Run WatchPermissionAwareTest Category
+ - name: Run Special Integration Test
run: ./mvnw ${MAVEN_ARGS} -B package -P minimal-watch-timeout-dependent-it --file pom.xml
\ No newline at end of file
From 336f759995e79f557a324ea6ab8b5abd1b65a80e Mon Sep 17 00:00:00 2001
From: csviri
Date: Wed, 26 Oct 2022 15:19:24 +0200
Subject: [PATCH 22/25] naming
---
.github/workflows/pr.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index ec64e93a39..e5627d1e0a 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -60,5 +60,5 @@ jobs:
kubernetes version: ${{ matrix.kubernetes }}
driver: 'docker'
start args: '--extra-config=apiserver.min-request-timeout=3'
- - name: Run Special Integration Test
+ - name: Run Special Integration Tests
run: ./mvnw ${MAVEN_ARGS} -B package -P minimal-watch-timeout-dependent-it --file pom.xml
\ No newline at end of file
From cd1c5bf66fb6280480229b7ad7896d4699feb311 Mon Sep 17 00:00:00 2001
From: csviri
Date: Thu, 27 Oct 2022 09:24:09 +0200
Subject: [PATCH 23/25] fixes from CR
---
.../operator/api/config/ConfigurationService.java | 5 +++--
.../operator/api/config/ConfigurationServiceOverrider.java | 7 ++++---
.../processing/event/source/informer/InformerWrapper.java | 3 ++-
.../operator/InformerRelatedBehaviorITS.java | 2 +-
4 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
index 6a016340ca..16faa0e9f0 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
@@ -1,5 +1,6 @@
package io.javaoperatorsdk.operator.api.config;
+import java.time.Duration;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -173,8 +174,8 @@ default boolean stopOnInformerErrorDuringStartup() {
* "stopOnInformerErrorDuringStartup" is true the operator will stop on timeout. Default is 2
* minutes.
*/
- default int cacheSyncTimeout() {
- return 2 * 60 * 1000;
+ default Duration cacheSyncTimeout() {
+ return Duration.ofMinutes(2);
}
/**
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
index 9cb9dae521..2b8aee9708 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
@@ -1,5 +1,6 @@
package io.javaoperatorsdk.operator.api.config;
+import java.time.Duration;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -28,7 +29,7 @@ public class ConfigurationServiceOverrider {
private LeaderElectionConfiguration leaderElectionConfiguration;
private InformerStoppedHandler informerStoppedHandler;
private Boolean stopOnInformerErrorDuringStartup;
- private Integer cacheSyncTimeout;
+ private Duration cacheSyncTimeout;
ConfigurationServiceOverrider(ConfigurationService original) {
this.original = original;
@@ -107,7 +108,7 @@ public ConfigurationServiceOverrider withStopOnInformerErrorDuringStartup(
return this;
}
- public ConfigurationServiceOverrider withCacheSyncTimeout(int cacheSyncTimeout) {
+ public ConfigurationServiceOverrider withCacheSyncTimeout(Duration cacheSyncTimeout) {
this.cacheSyncTimeout = cacheSyncTimeout;
return this;
}
@@ -192,7 +193,7 @@ public boolean stopOnInformerErrorDuringStartup() {
}
@Override
- public int cacheSyncTimeout() {
+ public Duration cacheSyncTimeout() {
return cacheSyncTimeout != null ? cacheSyncTimeout : super.cacheSyncTimeout();
}
};
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
index ffb3b7d15e..77d2977cab 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
@@ -69,7 +69,8 @@ public void start() throws OperatorException {
// note that in case we don't put here timeout and stopOnInformerErrorDuringStartup is
// false, and there is a rbac issue the get never returns; therefore operator never really
// starts
- start.toCompletableFuture().get(configService.cacheSyncTimeout(), TimeUnit.MILLISECONDS);
+ start.toCompletableFuture().get(configService.cacheSyncTimeout().toMillis(),
+ TimeUnit.MILLISECONDS);
} catch (TimeoutException | ExecutionException e) {
log.warn("Informer startup error. Informer: {}", informer, e);
if (configService.stopOnInformerErrorDuringStartup()) {
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorITS.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorITS.java
index e3ddb3a1e0..bfc0e4c02f 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorITS.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerRelatedBehaviorITS.java
@@ -189,7 +189,7 @@ Operator startOperator(boolean stopOnInformerErrorDuringStartup) {
Operator operator = new Operator(clientUsingServiceAccount(),
co -> {
co.withStopOnInformerErrorDuringStartup(stopOnInformerErrorDuringStartup);
- co.withCacheSyncTimeout(3000);
+ co.withCacheSyncTimeout(Duration.ofMillis(3000));
co.withInformerStoppedHandler((informer, ex) -> {
stopHandlerCalled = true;
});
From 66bc0398ec06db97628cd7c49880e447ae834350 Mon Sep 17 00:00:00 2001
From: csviri
Date: Thu, 27 Oct 2022 09:48:10 +0200
Subject: [PATCH 24/25] fixes
---
.../event/source/informer/InformerEventSourceTest.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
index ec4ef7b5a8..8b5c0202c0 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java
@@ -257,6 +257,8 @@ void informerStoppedHandlerShouldBeCalledWhenInformerStops() {
throw exception;
}));
+ // by default informer fails to start if there is an exception in the client on start.
+ // Throws the exception further.
assertThrows(RuntimeException.class, () -> informerEventSource.start());
verify(informerStoppedHandler, atLeastOnce()).onStop(any(), eq(exception));
} finally {
From d6329fec9129de64afcb2702b15b96bfd022dbd9 Mon Sep 17 00:00:00 2001
From: csviri
Date: Thu, 27 Oct 2022 10:31:33 +0200
Subject: [PATCH 25/25] improved logging
---
.../processing/event/source/informer/InformerWrapper.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
index 77d2977cab..601cb0c10c 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java
@@ -72,9 +72,11 @@ public void start() throws OperatorException {
start.toCompletableFuture().get(configService.cacheSyncTimeout().toMillis(),
TimeUnit.MILLISECONDS);
} catch (TimeoutException | ExecutionException e) {
- log.warn("Informer startup error. Informer: {}", informer, e);
if (configService.stopOnInformerErrorDuringStartup()) {
+ log.error("Informer startup error. Operator will be stopped. Informer: {}", informer, e);
throw new OperatorException(e);
+ } else {
+ log.warn("Informer startup error. Will periodically retry. Informer: {}", informer, e);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();