diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/NonComparableResourceVersionException.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/NonComparableResourceVersionException.java new file mode 100644 index 0000000000..03045ed88a --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/NonComparableResourceVersionException.java @@ -0,0 +1,25 @@ +/* + * Copyright Java Operator SDK Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.javaoperatorsdk.operator.api.reconciler; + +import io.javaoperatorsdk.operator.OperatorException; + +public class NonComparableResourceVersionException extends OperatorException { + + public NonComparableResourceVersionException(String message) { + super(message); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java index 6103b4b12b..b4b3405ec4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java @@ -450,4 +450,58 @@ public static
P addFinalizerWithSSA(
e);
}
}
+
+ public static int compareResourceVersions(String v1, String v2) {
+ var v1Length = v1.length();
+ if (v1Length == 0) {
+ throw new NonComparableResourceVersionException("Resource version (1) is empty");
+ }
+ var v2Length = v2.length();
+ if (v2Length == 0) {
+ throw new NonComparableResourceVersionException("Resource version (2) is empty");
+ }
+ var maxLength = Math.max(v1Length, v2Length);
+ boolean v1LeadingZero = true;
+ boolean v2LeadingZero = true;
+ int comparison = 0;
+ for (int i = 0; i < maxLength; i++) {
+ char char1 = 0;
+ if (i < v1Length) {
+ char1 = v1.charAt(i);
+ if (v1LeadingZero) {
+ if (char1 == '0') {
+ throw new NonComparableResourceVersionException(
+ "Resource version (1) cannot begin with 0");
+ }
+ v1LeadingZero = false;
+ }
+ if (!Character.isDigit(char1)) {
+ throw new NonComparableResourceVersionException(
+ "Non numeric characters in resource version (1): " + char1);
+ }
+ }
+ if (i < v2Length) {
+ var char2 = v2.charAt(i);
+ if (v2LeadingZero) {
+ if (char2 == '0') {
+ throw new NonComparableResourceVersionException(
+ "Resource version (2) cannot begin with 0");
+ }
+ v2LeadingZero = false;
+ }
+ if (!Character.isDigit(char2)) {
+ throw new NonComparableResourceVersionException(
+ "Non numeric characters in resource version (2): " + char2);
+ }
+ if (char1 == 0) {
+ comparison = -1;
+ } else if (comparison == 0) {
+ comparison = Character.compare(char1, char2);
+ }
+ } else {
+ comparison = 1;
+ }
+ }
+ return comparison;
+ }
}
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtilsTest.java
index c85442f00a..8918ba4f25 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtilsTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtilsTest.java
@@ -20,6 +20,8 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.KubernetesClient;
@@ -37,6 +39,7 @@
import io.javaoperatorsdk.operator.sample.simple.TestCustomResource;
import static io.javaoperatorsdk.operator.api.reconciler.PrimaryUpdateAndCacheUtils.DEFAULT_MAX_RETRY;
+import static io.javaoperatorsdk.operator.api.reconciler.PrimaryUpdateAndCacheUtils.compareResourceVersions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
@@ -47,6 +50,8 @@
class PrimaryUpdateAndCacheUtilsTest {
+ private static final Logger log = LoggerFactory.getLogger(PrimaryUpdateAndCacheUtilsTest.class);
+
Context