diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9fa3a779da..36c44f0d5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,5 +33,5 @@ jobs: kubernetes version: ${{ matrix.kubernetes }} driver: 'docker' - name: Run integration tests - run: mvn -B package -P no-unit-tests --file pom.xml + run: mvn -e -B package -P no-unit-tests --file pom.xml diff --git a/README.md b/README.md index 10d53fbc66..4750b11212 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ The Controller implements the business logic and describes all the classes neede ```java @Controller(customResourceClass = WebServer.class, - crdName = "webservers.sample.javaoperatorsdk") + crdName = "webservers.sample.javaoperatorsdk.io") public class WebServerController implements ResourceController { @Override diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index a5be06a274..88c800374a 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -36,10 +36,6 @@ io.fabric8 openshift-client - - org.apache.commons - commons-lang3 - org.slf4j slf4j-api diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerUtils.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerUtils.java index ee55c152f3..2c9b79c2b4 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerUtils.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerUtils.java @@ -1,89 +1,48 @@ package io.javaoperatorsdk.operator; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.CustomResource; import io.javaoperatorsdk.operator.api.Controller; import io.javaoperatorsdk.operator.api.ResourceController; -import io.fabric8.kubernetes.api.builder.Function; -import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.client.CustomResourceDoneable; -import javassist.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; public class ControllerUtils { - - private final static double JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version")); private static final String FINALIZER_NAME_SUFFIX = "/finalizer"; - - // this is just to support testing, this way we don't try to create class multiple times in memory with same name. - // note that other solution is to add a random string to doneable class name - private static Map, Class>> - doneableClassCache = new HashMap<>(); - + static String getFinalizer(ResourceController controller) { final String annotationFinalizerName = getAnnotation(controller).finalizerName(); if (!Controller.NULL.equals(annotationFinalizerName)) { return annotationFinalizerName; } - final String crdName = getAnnotation(controller).crdName() + FINALIZER_NAME_SUFFIX; - return crdName; + return getDefaultFinalizerIdentifier(controller); } - + + static String getDefaultFinalizerIdentifier(ResourceController controller) { + return getAnnotation(controller).crdName() + FINALIZER_NAME_SUFFIX; + } + + /** + * @param finalizer + * @return + * @deprecated this should be removed once k8s client provides that method on HasMetadata + */ + static boolean isFinalizerValid(String finalizer) { + return HasMetadata.FINALIZER_NAME_MATCHER.reset(finalizer).matches(); + } + static boolean getGenerationEventProcessing(ResourceController controller) { return getAnnotation(controller).generationAwareEventProcessing(); } - + static Class getCustomResourceClass(ResourceController controller) { return (Class) getAnnotation(controller).customResourceClass(); } - + static String getCrdName(ResourceController controller) { return getAnnotation(controller).crdName(); } - - - public static Class> - getCustomResourceDoneableClass(ResourceController controller) { - try { - Class customResourceClass = getAnnotation(controller).customResourceClass(); - String className = customResourceClass.getPackage().getName() + "." + customResourceClass.getSimpleName() + "CustomResourceDoneable"; - - if (doneableClassCache.containsKey(customResourceClass)) { - return (Class>) doneableClassCache.get(customResourceClass); - } - - ClassPool pool = ClassPool.getDefault(); - pool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader())); - - CtClass superClass = pool.get(CustomResourceDoneable.class.getName()); - CtClass function = pool.get(Function.class.getName()); - CtClass customResource = pool.get(customResourceClass.getName()); - CtClass[] argTypes = {customResource, function}; - CtClass customDoneable = pool.makeClass(className, superClass); - CtConstructor ctConstructor = CtNewConstructor.make(argTypes, null, "super($1, $2);", customDoneable); - customDoneable.addConstructor(ctConstructor); - - Class> doneableClass; - if (JAVA_VERSION >= 9) { - doneableClass = (Class>) customDoneable.toClass(customResourceClass); - } else { - doneableClass = (Class>) customDoneable.toClass(); - } - doneableClassCache.put(customResourceClass, doneableClass); - return doneableClass; - } catch (CannotCompileException | NotFoundException e) { - throw new IllegalStateException(e); - } - } - + private static Controller getAnnotation(ResourceController controller) { return controller.getClass().getAnnotation(Controller.class); } - - public static boolean hasGivenFinalizer(CustomResource resource, String finalizer) { - return resource.getMetadata().getFinalizers() != null && resource.getMetadata().getFinalizers().contains(finalizer); - } } diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/Operator.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/Operator.java index 73e03a44c2..d86630afba 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/Operator.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/Operator.java @@ -1,33 +1,28 @@ package io.javaoperatorsdk.operator; -import io.javaoperatorsdk.operator.api.ResourceController; -import io.javaoperatorsdk.operator.processing.EventDispatcher; -import io.javaoperatorsdk.operator.processing.EventScheduler; -import io.javaoperatorsdk.operator.processing.retry.GenericRetry; -import io.javaoperatorsdk.operator.processing.retry.Retry; +import java.util.Arrays; + import io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinition; import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.client.CustomResourceDoneable; import io.fabric8.kubernetes.client.CustomResourceList; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; import io.fabric8.kubernetes.client.dsl.internal.CustomResourceOperationsImpl; -import io.fabric8.kubernetes.internal.KubernetesDeserializer; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.processing.EventDispatcher; +import io.javaoperatorsdk.operator.processing.EventScheduler; +import io.javaoperatorsdk.operator.processing.retry.GenericRetry; +import io.javaoperatorsdk.operator.processing.retry.Retry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - @SuppressWarnings("rawtypes") public class Operator { private final static Logger log = LoggerFactory.getLogger(Operator.class); private final KubernetesClient k8sClient; - private Map, CustomResourceOperationsImpl> customResourceClients = new HashMap<>(); - + public Operator(KubernetesClient k8sClient) { this.k8sClient = k8sClient; } @@ -53,12 +48,10 @@ public void registerController(ResourceController private void registerController(ResourceController controller, boolean watchAllNamespaces, Retry retry, String... targetNamespaces) throws OperatorException { Class resClass = ControllerUtils.getCustomResourceClass(controller); - CustomResourceDefinitionContext crd = getCustomResourceDefinitionForController(controller); - KubernetesDeserializer.registerCustomKind(crd.getVersion(), crd.getKind(), resClass); String finalizer = ControllerUtils.getFinalizer(controller); - MixedOperation client = k8sClient.customResources(crd, resClass, CustomResourceList.class, ControllerUtils.getCustomResourceDoneableClass(controller)); + MixedOperation client = k8sClient.customResources(resClass, CustomResourceList.class); EventDispatcher eventDispatcher = new EventDispatcher(controller, - finalizer, new EventDispatcher.CustomResourceFacade(client), ControllerUtils.getGenerationEventProcessing(controller)); + finalizer, new EventDispatcher.CustomResourceFacade(client), ControllerUtils.getGenerationEventProcessing(controller)); EventScheduler eventScheduler = new EventScheduler(eventDispatcher, retry); registerWatches(controller, client, resClass, watchAllNamespaces, targetNamespaces, eventScheduler); } @@ -79,7 +72,6 @@ private void registerWatches(ResourceController co log.debug("Registered controller for namespace: {}", targetNamespace); } } - customResourceClients.put(resClass, (CustomResourceOperationsImpl) client); log.info("Registered Controller: '{}' for CRD: '{}' for namespaces: {}", controller.getClass().getSimpleName(), resClass, targetNamespaces.length == 0 ? "[all/client namespace]" : Arrays.toString(targetNamespaces)); } @@ -93,21 +85,4 @@ private CustomResourceDefinitionContext getCustomResourceDefinitionForController CustomResourceDefinitionContext context = CustomResourceDefinitionContext.fromCrd(customResourceDefinition); return context; } - - public Map, CustomResourceOperationsImpl> getCustomResourceClients() { - return customResourceClients; - } - - public , D extends CustomResourceDoneable> CustomResourceOperationsImpl - getCustomResourceClients(Class customResourceClass) { - return customResourceClients.get(customResourceClass); - } - - private String getKind(CustomResourceDefinition crd) { - return crd.getSpec().getNames().getKind(); - } - - private String getApiVersion(CustomResourceDefinition crd) { - return crd.getSpec().getGroup() + "/" + crd.getSpec().getVersion(); - } } diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Controller.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Controller.java index 9edec45c75..59b8993c5e 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Controller.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Controller.java @@ -1,12 +1,12 @@ package io.javaoperatorsdk.operator.api; -import io.fabric8.kubernetes.client.CustomResource; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import io.fabric8.kubernetes.client.CustomResource; + @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface Controller { diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventDispatcher.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventDispatcher.java index 2b102e8471..f53d0a18f2 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventDispatcher.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventDispatcher.java @@ -1,18 +1,20 @@ package io.javaoperatorsdk.operator.processing; -import io.javaoperatorsdk.operator.ControllerUtils; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.client.Watcher; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.javaoperatorsdk.operator.api.*; +import io.javaoperatorsdk.operator.api.Context; +import io.javaoperatorsdk.operator.api.DefaultContext; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.api.RetryInfo; +import io.javaoperatorsdk.operator.api.UpdateControl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - /** * Dispatches events to the Controller and handles Finalizers for a single type of Custom Resource. */ @@ -43,23 +45,24 @@ public void handleEvent(CustomResourceEvent event) { log.error("Received error for resource: {}", resource.getMetadata().getName()); return; } - if (markedForDeletion(resource) && !ControllerUtils.hasGivenFinalizer(resource, resourceFinalizer)) { - log.debug("Skipping event dispatching since its marked for deletion but does not have finalizer: {}", event); - return; - } + final boolean markedForDeletion = resource.isMarkedForDeletion(); + final boolean hasFinalizer = resource.hasFinalizer(resourceFinalizer); Context context = new DefaultContext(new RetryInfo(event.getRetryCount(), event.getRetryExecution().isLastExecution())); - if (markedForDeletion(resource)) { + if (markedForDeletion) { + if (!hasFinalizer) { + log.debug("Skipping event dispatching since its marked for deletion but has no default finalizer: {}", event); + return; + } boolean removeFinalizer = controller.deleteResource(resource, context); - boolean hasFinalizer = ControllerUtils.hasGivenFinalizer(resource, resourceFinalizer); - if (removeFinalizer && hasFinalizer) { + if (removeFinalizer) { removeFinalizer(resource); } else { log.debug("Skipping finalizer remove. removeFinalizer: {}, hasFinalizer: {} ", - removeFinalizer, hasFinalizer); + removeFinalizer, hasFinalizer); } cleanup(resource); } else { - if (!ControllerUtils.hasGivenFinalizer(resource, resourceFinalizer) && !markedForDeletion(resource)) { + if (!hasFinalizer) { /* We always add a finalizer if missing and not marked for deletion. We execute the controller processing only for processing the event sent as a results of the finalizer add. This will make sure that the resources are not created before @@ -105,8 +108,10 @@ private void markLastGenerationProcessed(CustomResource resource) { private void updateCustomResourceWithFinalizer(CustomResource resource) { log.debug("Adding finalizer for resource: {} version: {}", resource.getMetadata().getName(), - resource.getMetadata().getResourceVersion()); - addFinalizerIfNotPresent(resource); + resource.getMetadata().getResourceVersion()); + if (resource.addFinalizer(resourceFinalizer)) { + log.info("Adding default finalizer to {}", resource.getMetadata()); + } replace(resource); } @@ -128,27 +133,13 @@ private void replace(CustomResource resource) { log.debug("Trying to replace resource {}, version: {}", resource.getMetadata().getName(), resource.getMetadata().getResourceVersion()); customResourceFacade.replaceWithLock(resource); } - - private void addFinalizerIfNotPresent(CustomResource resource) { - if (!ControllerUtils.hasGivenFinalizer(resource, resourceFinalizer) && !markedForDeletion(resource)) { - log.info("Adding finalizer {} to {}", resourceFinalizer, resource.getMetadata()); - if (resource.getMetadata().getFinalizers() == null) { - resource.getMetadata().setFinalizers(new ArrayList<>(1)); - } - resource.getMetadata().getFinalizers().add(resourceFinalizer); - } - } - - private boolean markedForDeletion(CustomResource resource) { - return resource.getMetadata().getDeletionTimestamp() != null && !resource.getMetadata().getDeletionTimestamp().isEmpty(); - } - + // created to support unit testing public static class CustomResourceFacade { - - private final MixedOperation> resourceOperation; - - public CustomResourceFacade(MixedOperation> resourceOperation) { + + private final MixedOperation> resourceOperation; + + public CustomResourceFacade(MixedOperation> resourceOperation) { this.resourceOperation = resourceOperation; } diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventScheduler.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventScheduler.java index d2ed63a218..92e3aa43bf 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventScheduler.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventScheduler.java @@ -1,18 +1,18 @@ package io.javaoperatorsdk.operator.processing; -import io.javaoperatorsdk.operator.processing.retry.Retry; -import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.client.KubernetesClientException; -import io.fabric8.kubernetes.client.Watcher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.Optional; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.WatcherException; +import io.javaoperatorsdk.operator.processing.retry.Retry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Requirements: *
    @@ -57,7 +57,7 @@ public void eventReceived(Watcher.Action action, CustomResource resource) { CustomResourceEvent event = new CustomResourceEvent(action, resource, retry); scheduleEventFromApi(event); } - + void scheduleEventFromApi(CustomResourceEvent event) { try { lock.lock(); @@ -137,9 +137,9 @@ private void scheduleNotYetScheduledEventForExecution(String uuid) { CustomResourceEvent notScheduledEvent = eventStore.removeEventNotScheduled(uuid); scheduleEventForExecution(notScheduledEvent); } - + @Override - public void onClose(KubernetesClientException e) { + public void onClose(WatcherException e) { log.error("Error: ", e); // we will exit the application if there was a watching exception, because of the bug in fabric8 client // see https://github.com/fabric8io/kubernetes-client/issues/1318 diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ConcurrencyIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ConcurrencyIT.java index 845ab3a26c..f13a4d4846 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ConcurrencyIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ConcurrencyIT.java @@ -1,10 +1,14 @@ package io.javaoperatorsdk.operator; -import io.javaoperatorsdk.operator.sample.TestCustomResource; -import io.javaoperatorsdk.operator.sample.TestCustomResourceController; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.client.DefaultKubernetesClient; import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.sample.TestCustomResource; +import io.javaoperatorsdk.operator.sample.TestCustomResourceController; import org.awaitility.Awaitility; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -13,10 +17,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - import static org.assertj.core.api.Assertions.assertThat; @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -32,10 +32,10 @@ public class ConcurrencyIT { @BeforeAll public void setup() { KubernetesClient k8sClient = new DefaultKubernetesClient(); - integrationTest.initialize(k8sClient, new TestCustomResourceController(k8sClient, true), - "test-crd.yaml"); + final TestCustomResourceController controller = new TestCustomResourceController(k8sClient, true); + integrationTest.initialize(k8sClient, controller, "test-crd.yaml"); } - + @BeforeEach public void cleanup() { integrationTest.cleanup(); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerExecutionIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerExecutionIT.java index e20492103a..a54d669f9f 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerExecutionIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerExecutionIT.java @@ -1,19 +1,17 @@ package io.javaoperatorsdk.operator; -import io.javaoperatorsdk.operator.sample.TestCustomResource; -import io.javaoperatorsdk.operator.sample.TestCustomResourceController; -import io.javaoperatorsdk.operator.sample.TestCustomResourceSpec; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.client.DefaultKubernetesClient; import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.sample.TestCustomResource; +import io.javaoperatorsdk.operator.sample.TestCustomResourceController; +import io.javaoperatorsdk.operator.sample.TestCustomResourceSpec; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; @@ -106,7 +104,6 @@ private TestCustomResource testCustomResource() { .withNamespace(IntegrationTestSupport.TEST_NAMESPACE) .build()); resource.getMetadata().setAnnotations(new HashMap<>()); - resource.setKind("CustomService"); resource.setSpec(new TestCustomResourceSpec()); resource.getSpec().setConfigMapName("test-config-map"); resource.getSpec().setKey("test-key"); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerUtilsTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerUtilsTest.java index 4c8b48a009..c78f4f8454 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerUtilsTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerUtilsTest.java @@ -1,6 +1,5 @@ package io.javaoperatorsdk.operator; -import io.fabric8.kubernetes.client.CustomResourceDoneable; import io.javaoperatorsdk.operator.api.Context; import io.javaoperatorsdk.operator.api.Controller; import io.javaoperatorsdk.operator.api.ResourceController; @@ -10,35 +9,38 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; class ControllerUtilsTest { - + public static final String CUSTOM_FINALIZER_NAME = "a.custom/finalizer"; - + @Test public void returnsValuesFromControllerAnnotationFinalizer() { - Assertions.assertEquals(TestCustomResourceController.CRD_NAME + "/finalizer", ControllerUtils.getFinalizer(new TestCustomResourceController(null))); - assertEquals(TestCustomResource.class, ControllerUtils.getCustomResourceClass(new TestCustomResourceController(null))); - Assertions.assertEquals(TestCustomResourceController.CRD_NAME, ControllerUtils.getCrdName(new TestCustomResourceController(null))); - assertFalse(ControllerUtils.getGenerationEventProcessing(new TestCustomResourceController(null))); - assertTrue(CustomResourceDoneable.class.isAssignableFrom(ControllerUtils.getCustomResourceDoneableClass(new TestCustomResourceController(null)))); + final TestCustomResourceController controller = new TestCustomResourceController(null); + final String finalizer = ControllerUtils.getFinalizer(controller); + Assertions.assertEquals(TestCustomResourceController.FINALIZER_NAME, finalizer); + Assertions.assertTrue(ControllerUtils.isFinalizerValid(finalizer)); + assertEquals(TestCustomResource.class, ControllerUtils.getCustomResourceClass(controller)); + Assertions.assertEquals(TestCustomResourceController.CRD_NAME, ControllerUtils.getCrdName(controller)); + assertFalse(ControllerUtils.getGenerationEventProcessing(controller)); } - + @Controller(crdName = "test.crd", customResourceClass = TestCustomResource.class, finalizerName = CUSTOM_FINALIZER_NAME) static class TestCustomFinalizerController implements ResourceController { - + @Override public boolean deleteResource(TestCustomResource resource, Context context) { return false; } - + @Override public UpdateControl createOrUpdateResource(TestCustomResource resource, Context context) { return null; } } - + @Test public void returnCustomerFinalizerNameIfSet() { assertEquals(CUSTOM_FINALIZER_NAME, ControllerUtils.getFinalizer(new TestCustomFinalizerController())); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/EventDispatcherTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/EventDispatcherTest.java index eb120fbdb7..e51ff1fe64 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/EventDispatcherTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/EventDispatcherTest.java @@ -1,26 +1,32 @@ package io.javaoperatorsdk.operator; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.client.Watcher; import io.javaoperatorsdk.operator.api.ResourceController; import io.javaoperatorsdk.operator.api.UpdateControl; import io.javaoperatorsdk.operator.processing.CustomResourceEvent; import io.javaoperatorsdk.operator.processing.EventDispatcher; import io.javaoperatorsdk.operator.processing.retry.GenericRetry; import io.javaoperatorsdk.operator.sample.TestCustomResource; -import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.client.Watcher; -import io.javaoperatorsdk.operator.api.Controller; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class EventDispatcherTest { - - public static final String FINALIZER_NAME = "finalizer"; + + public static final String FINALIZER_NAME = "example.com/finalizer"; private CustomResource testCustomResource; private EventDispatcher eventDispatcher; private final ResourceController controller = mock(ResourceController.class); @@ -28,8 +34,7 @@ class EventDispatcherTest { @BeforeEach void setup() { - eventDispatcher = new EventDispatcher(controller, - FINALIZER_NAME, customResourceFacade, false); + eventDispatcher = new EventDispatcher(controller, FINALIZER_NAME, customResourceFacade, false); testCustomResource = getResource(); @@ -46,9 +51,9 @@ void callCreateOrUpdateOnNewResource() { @Test void updatesOnlyStatusSubResource() { - testCustomResource.getMetadata().getFinalizers().add(FINALIZER_NAME); + testCustomResource.addFinalizer(FINALIZER_NAME); when(controller.createOrUpdateResource(eq(testCustomResource), any())) - .thenReturn(UpdateControl.updateStatusSubResource(testCustomResource)); + .thenReturn(UpdateControl.updateStatusSubResource(testCustomResource)); eventDispatcher.handleEvent(customResourceEvent(Watcher.Action.ADDED, testCustomResource)); @@ -67,14 +72,14 @@ void callCreateOrUpdateOnModifiedResource() { void addsFinalizerOnCreateIfNotThere() { eventDispatcher.handleEvent(customResourceEvent(Watcher.Action.MODIFIED, testCustomResource)); verify(controller, times(1)) - .createOrUpdateResource(argThat(testCustomResource -> - testCustomResource.getMetadata().getFinalizers().contains(FINALIZER_NAME)), any()); + .createOrUpdateResource(argThat(testCustomResource -> + testCustomResource.hasFinalizer(FINALIZER_NAME)), any()); } @Test void callsDeleteIfObjectHasFinalizerAndMarkedForDelete() { testCustomResource.getMetadata().setDeletionTimestamp("2019-8-10"); - testCustomResource.getMetadata().getFinalizers().add(FINALIZER_NAME); + testCustomResource.addFinalizer(FINALIZER_NAME); eventDispatcher.handleEvent(customResourceEvent(Watcher.Action.MODIFIED, testCustomResource)); @@ -182,8 +187,7 @@ void doesNotMarkNewGenerationInCaseOfException() { } void generationAwareMode() { - eventDispatcher = new EventDispatcher(controller, - FINALIZER_NAME, customResourceFacade, true); + eventDispatcher = new EventDispatcher(controller, FINALIZER_NAME, customResourceFacade, true); } private void markForDeletion(CustomResource customResource) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/IntegrationTestSupport.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/IntegrationTestSupport.java index 2c6e0274ce..2844cdb4f9 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/IntegrationTestSupport.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/IntegrationTestSupport.java @@ -1,27 +1,25 @@ package io.javaoperatorsdk.operator; -import io.javaoperatorsdk.operator.api.ResourceController; -import io.javaoperatorsdk.operator.sample.TestCustomResource; -import io.javaoperatorsdk.operator.sample.TestCustomResourceSpec; +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.TimeUnit; + import io.fabric8.kubernetes.api.model.Namespace; import io.fabric8.kubernetes.api.model.NamespaceBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinition; import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.client.CustomResourceDoneable; import io.fabric8.kubernetes.client.CustomResourceList; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; import io.fabric8.kubernetes.client.utils.Serialization; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.sample.TestCustomResource; +import io.javaoperatorsdk.operator.sample.TestCustomResourceSpec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.TimeUnit; - import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; @@ -31,22 +29,21 @@ public class IntegrationTestSupport { public static final String TEST_CUSTOM_RESOURCE_PREFIX = "test-custom-resource-"; private final static Logger log = LoggerFactory.getLogger(IntegrationTestSupport.class); private KubernetesClient k8sClient; - private MixedOperation> crOperations; + private MixedOperation> crOperations; private Operator operator; private ResourceController controller; public void initialize(KubernetesClient k8sClient, ResourceController controller, String crdPath) { + assertThat(ControllerUtils.isFinalizerValid(ControllerUtils.getDefaultFinalizerIdentifier(controller))).isTrue(); + log.info("Initializing integration test in namespace {}", TEST_NAMESPACE); this.k8sClient = k8sClient; - CustomResourceDefinition crd = loadCRDAndApplyToCluster(crdPath); - CustomResourceDefinitionContext crdContext = CustomResourceDefinitionContext.fromCrd(crd); + loadCRDAndApplyToCluster(crdPath); this.controller = controller; - - Class doneableClass = ControllerUtils.getCustomResourceDoneableClass(controller); + Class customResourceClass = ControllerUtils.getCustomResourceClass(controller); - crOperations = k8sClient.customResources(crdContext, customResourceClass, CustomResourceList.class, doneableClass); - + this.crOperations = k8sClient.customResources(customResourceClass, CustomResourceList.class); + if (k8sClient.namespaces().withName(TEST_NAMESPACE).get() == null) { k8sClient.namespaces().create(new NamespaceBuilder() .withMetadata(new ObjectMetaBuilder().withName(TEST_NAMESPACE).build()).build()); @@ -145,8 +142,8 @@ public TestCustomResource createTestCustomResource(String id) { public KubernetesClient getK8sClient() { return k8sClient; } - - public MixedOperation> getCrOperations() { + + public MixedOperation> getCrOperations() { return crOperations; } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/SubResourceUpdateIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/SubResourceUpdateIT.java index 540001c5e1..9a68ee27ac 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/SubResourceUpdateIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/SubResourceUpdateIT.java @@ -1,36 +1,34 @@ package io.javaoperatorsdk.operator; -import io.javaoperatorsdk.operator.sample.subresource.SubResourceTestCustomResource; -import io.javaoperatorsdk.operator.sample.subresource.SubResourceTestCustomResourceController; -import io.javaoperatorsdk.operator.sample.subresource.SubResourceTestCustomResourceSpec; +import java.util.concurrent.TimeUnit; + import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.client.DefaultKubernetesClient; import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.api.Controller; +import io.javaoperatorsdk.operator.sample.subresource.SubResourceTestCustomResource; +import io.javaoperatorsdk.operator.sample.subresource.SubResourceTestCustomResourceController; +import io.javaoperatorsdk.operator.sample.subresource.SubResourceTestCustomResourceSpec; import io.javaoperatorsdk.operator.sample.subresource.SubResourceTestCustomResourceStatus; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; -import java.util.concurrent.TimeUnit; - import static io.javaoperatorsdk.operator.IntegrationTestSupport.TEST_NAMESPACE; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SubResourceUpdateIT { - + private IntegrationTestSupport integrationTestSupport = new IntegrationTestSupport(); - + @BeforeEach public void initAndCleanup() { KubernetesClient k8sClient = new DefaultKubernetesClient(); - integrationTestSupport.initialize(k8sClient, new SubResourceTestCustomResourceController(), - "subresource-test-crd.yaml"); + integrationTestSupport.initialize(k8sClient, new SubResourceTestCustomResourceController(), "subresource-test-crd.yaml"); integrationTestSupport.cleanup(); } - + @Test public void updatesSubResourceStatus() { integrationTestSupport.teardownIfSuccess(() -> { @@ -106,7 +104,6 @@ public SubResourceTestCustomResource createTestCustomResource(String id) { .withNamespace(TEST_NAMESPACE) .withFinalizers(SubResourceTestCustomResourceController.FINALIZER_NAME) .build()); - resource.setKind("SubresourceSample"); resource.setSpec(new SubResourceTestCustomResourceSpec()); resource.getSpec().setValue(id); return resource; diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResource.java index 3a2110960c..a868035934 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResource.java @@ -1,17 +1,18 @@ package io.javaoperatorsdk.operator.sample; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; -public class TestCustomResource extends CustomResource { - +public class TestCustomResource extends CustomResource implements Namespaced { + private TestCustomResourceSpec spec; - + private TestCustomResourceStatus status; - + public TestCustomResourceSpec getSpec() { return spec; } - + public void setSpec(TestCustomResourceSpec spec) { this.spec = spec; } @@ -23,13 +24,23 @@ public TestCustomResourceStatus getStatus() { public void setStatus(TestCustomResourceStatus status) { this.status = status; } - + @Override public String toString() { return "TestCustomResource{" + - "spec=" + spec + - ", status=" + status + - ", extendedFrom=" + super.toString() + - '}'; + "spec=" + spec + + ", status=" + status + + ", extendedFrom=" + super.toString() + + '}'; + } + + @Override + public String getKind() { + return "CustomService"; + } + + @Override + public String getApiVersion() { + return "sample.javaoperatorsdk.io/v1"; } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResourceController.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResourceController.java index 9f27896914..ff7eca2da1 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResourceController.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResourceController.java @@ -1,31 +1,32 @@ package io.javaoperatorsdk.operator.sample; +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.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.TestExecutionInfoProvider; import io.javaoperatorsdk.operator.api.Context; import io.javaoperatorsdk.operator.api.Controller; import io.javaoperatorsdk.operator.api.ResourceController; import io.javaoperatorsdk.operator.api.UpdateControl; -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.ConfigMapBuilder; -import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - @Controller( - generationAwareEventProcessing = false, - crdName = TestCustomResourceController.CRD_NAME, - customResourceClass = TestCustomResource.class) + generationAwareEventProcessing = false, + crdName = TestCustomResourceController.CRD_NAME, + finalizerName = TestCustomResourceController.FINALIZER_NAME, + customResourceClass = TestCustomResource.class) public class TestCustomResourceController implements ResourceController, TestExecutionInfoProvider { private static final Logger log = LoggerFactory.getLogger(TestCustomResourceController.class); - - public static final String CRD_NAME = "customservices.sample.javaoperatorsdk"; - public static final String FINALIZER_NAME = CRD_NAME + "/finalizer"; + + public static final String CRD_NAME = "customservices.sample.javaoperatorsdk.io"; + public static final String FINALIZER_NAME = CRD_NAME + ".io/finalizer"; private final KubernetesClient kubernetesClient; private final boolean updateStatus; diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResource.java index caab91bfe6..80a50631df 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResource.java @@ -1,17 +1,18 @@ package io.javaoperatorsdk.operator.sample.subresource; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; -public class SubResourceTestCustomResource extends CustomResource { - +public class SubResourceTestCustomResource extends CustomResource implements Namespaced { + private SubResourceTestCustomResourceSpec spec; - + private SubResourceTestCustomResourceStatus status; - + public SubResourceTestCustomResourceSpec getSpec() { return spec; } - + public void setSpec(SubResourceTestCustomResourceSpec spec) { this.spec = spec; } @@ -23,13 +24,23 @@ public SubResourceTestCustomResourceStatus getStatus() { public void setStatus(SubResourceTestCustomResourceStatus status) { this.status = status; } - + @Override public String toString() { return "TestCustomResource{" + - "spec=" + spec + - ", status=" + status + - ", extendedFrom=" + super.toString() + - '}'; + "spec=" + spec + + ", status=" + status + + ", extendedFrom=" + super.toString() + + '}'; + } + + @Override + public String getKind() { + return "SubresourceSample"; + } + + @Override + public String getApiVersion() { + return "sample.javaoperatorsdk.io/v1"; } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResourceController.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResourceController.java index 9b47305490..36c78bf68b 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResourceController.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResourceController.java @@ -1,5 +1,7 @@ package io.javaoperatorsdk.operator.sample.subresource; +import java.util.concurrent.atomic.AtomicInteger; + import io.javaoperatorsdk.operator.TestExecutionInfoProvider; import io.javaoperatorsdk.operator.api.Context; import io.javaoperatorsdk.operator.api.Controller; @@ -8,20 +10,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.atomic.AtomicInteger; - @Controller( - crdName = SubResourceTestCustomResourceController.CRD_NAME, - customResourceClass = SubResourceTestCustomResource.class, - generationAwareEventProcessing = false) + crdName = SubResourceTestCustomResourceController.CRD_NAME, + finalizerName = SubResourceTestCustomResourceController.FINALIZER_NAME, + customResourceClass = SubResourceTestCustomResource.class, + generationAwareEventProcessing = false) public class SubResourceTestCustomResourceController implements ResourceController, TestExecutionInfoProvider { - - public static final String CRD_NAME = "subresourcesample.sample.javaoperatorsdk"; - public static final String FINALIZER_NAME = CRD_NAME + "/finalizer"; + + public static final String CRD_NAME = "subresourcesamples.sample.javaoperatorsdk.io"; + public static final String FINALIZER_NAME = CRD_NAME + ".io/finalizer"; private static final Logger log = LoggerFactory.getLogger(SubResourceTestCustomResourceController.class); private final AtomicInteger numberOfExecutions = new AtomicInteger(0); - + @Override public boolean deleteResource(SubResourceTestCustomResource resource, Context context) { return true; diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/subresource-test-crd.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/subresource-test-crd.yaml index c39b9c117f..858998f5eb 100644 --- a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/subresource-test-crd.yaml +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/subresource-test-crd.yaml @@ -1,15 +1,15 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: subresourcesample.sample.javaoperatorsdk + name: subresourcesamples.sample.javaoperatorsdk.io spec: - group: sample.javaoperatorsdk + group: sample.javaoperatorsdk.io version: v1 subresources: status: {} scope: Namespaced names: - plural: subresourcesample + plural: subresourcesamples singular: subresourcesample kind: SubresourceSample shortNames: diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/test-crd.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/test-crd.yaml index ecc3a38587..2c1d2254c6 100644 --- a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/test-crd.yaml +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/test-crd.yaml @@ -1,9 +1,9 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: customservices.sample.javaoperatorsdk + name: customservices.sample.javaoperatorsdk.io spec: - group: sample.javaoperatorsdk + group: sample.javaoperatorsdk.io version: v1 scope: Namespaced names: diff --git a/pom.xml b/pom.xml index 8ec9328cbf..c74328321e 100644 --- a/pom.xml +++ b/pom.xml @@ -52,12 +52,7 @@ io.fabric8 openshift-client - 4.12.0 - - - org.apache.commons - commons-lang3 - 3.11 + 5.0.0-alpha-2 org.slf4j diff --git a/samples/common/crd/crd.yaml b/samples/common/crd/crd.yaml index 67d2b82ecb..9fa67a28b9 100644 --- a/samples/common/crd/crd.yaml +++ b/samples/common/crd/crd.yaml @@ -1,9 +1,9 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: customservices.sample.javaoperatorsdk + name: customservices.sample.javaoperatorsdk.io spec: - group: sample.javaoperatorsdk + group: sample.javaoperatorsdk.io version: v1 scope: Namespaced names: diff --git a/samples/common/crd/test_object.yaml b/samples/common/crd/test_object.yaml index f8e23e387b..c36212e256 100644 --- a/samples/common/crd/test_object.yaml +++ b/samples/common/crd/test_object.yaml @@ -1,4 +1,4 @@ -apiVersion: "sample.javaoperatorsdk/v1" +apiVersion: "sample.javaoperatorsdk.io/v1" kind: CustomService metadata: name: custom-service1 diff --git a/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomService.java b/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomService.java index 404a07c672..2b39f172fe 100644 --- a/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomService.java +++ b/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomService.java @@ -1,16 +1,22 @@ package io.javaoperatorsdk.operator.sample; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; -public class CustomService extends CustomResource { - +public class CustomService extends CustomResource implements Namespaced { + private ServiceSpec spec; - + public ServiceSpec getSpec() { return spec; } - + public void setSpec(ServiceSpec spec) { this.spec = spec; } + + @Override + public String getApiVersion() { + return "sample.javaoperatorsdk.io/v1"; + } } diff --git a/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomServiceController.java b/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomServiceController.java index 1f489d81dc..13ff1e62de 100644 --- a/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomServiceController.java +++ b/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomServiceController.java @@ -1,22 +1,23 @@ package io.javaoperatorsdk.operator.sample; +import java.util.Collections; + +import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.fabric8.kubernetes.api.model.ServicePort; +import io.fabric8.kubernetes.api.model.ServiceSpec; +import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.Context; import io.javaoperatorsdk.operator.api.Controller; import io.javaoperatorsdk.operator.api.ResourceController; import io.javaoperatorsdk.operator.api.UpdateControl; -import io.fabric8.kubernetes.api.model.ServicePort; -import io.fabric8.kubernetes.api.model.ServiceSpec; -import io.fabric8.kubernetes.client.KubernetesClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collections; - /** * A very simple sample controller that creates a service with a label. */ @Controller(customResourceClass = CustomService.class, - crdName = "customservices.sample.javaoperatorsdk") + crdName = "customservices.sample.javaoperatorsdk.io") public class CustomServiceController implements ResourceController { public static final String KIND = "CustomService"; @@ -39,19 +40,19 @@ public boolean deleteResource(CustomService resource, Context con @Override public UpdateControl createOrUpdateResource(CustomService resource, Context context) { log.info("Execution createOrUpdateResource for: {}", resource.getMetadata().getName()); - + ServicePort servicePort = new ServicePort(); servicePort.setPort(8080); ServiceSpec serviceSpec = new ServiceSpec(); serviceSpec.setPorts(Collections.singletonList(servicePort)); - - kubernetesClient.services().inNamespace(resource.getMetadata().getNamespace()).createOrReplaceWithNew() - .withNewMetadata() - .withName(resource.getSpec().getName()) - .addToLabels("testLabel", resource.getSpec().getLabel()) - .endMetadata() - .withSpec(serviceSpec) - .done(); + + kubernetesClient.services().inNamespace(resource.getMetadata().getNamespace()).createOrReplace(new ServiceBuilder() + .withNewMetadata() + .withName(resource.getSpec().getName()) + .addToLabels("testLabel", resource.getSpec().getLabel()) + .endMetadata() + .withSpec(serviceSpec) + .build()); return UpdateControl.updateCustomResource(resource); } } diff --git a/samples/mysql-schema/README.md b/samples/mysql-schema/README.md index 2860d5ee47..ec558b343f 100644 --- a/samples/mysql-schema/README.md +++ b/samples/mysql-schema/README.md @@ -8,7 +8,7 @@ Access to the MySQL server is configured in the configuration of the operator, s This is an example input: ```yaml -apiVersion: "mysql.sample.javaoperatorsdk/v1" +apiVersion: "mysql.sample.javaoperatorsdk.io/v1" kind: MySQLSchema metadata: name: mydb diff --git a/samples/mysql-schema/k8s/crd.yaml b/samples/mysql-schema/k8s/crd.yaml index ef3aef057e..a877df8883 100644 --- a/samples/mysql-schema/k8s/crd.yaml +++ b/samples/mysql-schema/k8s/crd.yaml @@ -1,9 +1,9 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: schemas.mysql.sample.javaoperatorsdk + name: schemas.mysql.sample.javaoperatorsdk.io spec: - group: mysql.sample.javaoperatorsdk + group: mysql.sample.javaoperatorsdk.io version: v1 subresources: status: {} diff --git a/samples/mysql-schema/k8s/example.yaml b/samples/mysql-schema/k8s/example.yaml index 054c9a1695..3117eb095c 100644 --- a/samples/mysql-schema/k8s/example.yaml +++ b/samples/mysql-schema/k8s/example.yaml @@ -1,4 +1,4 @@ -apiVersion: "mysql.sample.javaoperatorsdk/v1" +apiVersion: "mysql.sample.javaoperatorsdk.io/v1" kind: MySQLSchema metadata: name: mydb diff --git a/samples/mysql-schema/k8s/rbac.yaml b/samples/mysql-schema/k8s/rbac.yaml index ddd05d3b76..28b363a05a 100644 --- a/samples/mysql-schema/k8s/rbac.yaml +++ b/samples/mysql-schema/k8s/rbac.yaml @@ -4,13 +4,13 @@ metadata: name: mysql-schema-operator rules: - apiGroups: - - mysql.sample.javaoperatorsdk + - mysql.sample.javaoperatorsdk.io resources: - schemas verbs: - "*" - apiGroups: - - mysql.sample.javaoperatorsdk + - mysql.sample.javaoperatorsdk.io resources: - schemas/status verbs: diff --git a/samples/mysql-schema/pom.xml b/samples/mysql-schema/pom.xml index 88b943b7ef..e6ea90ea4d 100644 --- a/samples/mysql-schema/pom.xml +++ b/samples/mysql-schema/pom.xml @@ -51,10 +51,6 @@ mysql-connector-java 8.0.22 - - org.apache.commons - commons-lang3 - diff --git a/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/Schema.java b/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/Schema.java index 93e028b716..a7f8fe2e29 100644 --- a/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/Schema.java +++ b/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/Schema.java @@ -1,26 +1,32 @@ package io.javaoperatorsdk.operator.sample; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; -public class Schema extends CustomResource { - +public class Schema extends CustomResource implements Namespaced { + private SchemaSpec spec; - + private SchemaStatus status; - + public SchemaSpec getSpec() { return spec; } - + public void setSpec(SchemaSpec spec) { this.spec = spec; } - + public SchemaStatus getStatus() { return status; } - + public void setStatus(SchemaStatus status) { this.status = status; } + + @Override + public String getApiVersion() { + return "mysql.sample.javaoperatorsdk.io/v1"; + } } diff --git a/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaController.java b/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaController.java index bda42ac066..69b31914f8 100644 --- a/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaController.java +++ b/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaController.java @@ -1,16 +1,5 @@ package io.javaoperatorsdk.operator.sample; -import io.javaoperatorsdk.operator.api.Context; -import io.javaoperatorsdk.operator.api.Controller; -import io.javaoperatorsdk.operator.api.ResourceController; -import io.javaoperatorsdk.operator.api.UpdateControl; -import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.api.model.SecretBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; -import org.apache.commons.lang3.RandomStringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -19,11 +8,22 @@ import java.sql.Statement; import java.util.Base64; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.Context; +import io.javaoperatorsdk.operator.api.Controller; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.api.UpdateControl; +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import static java.lang.String.format; @Controller( - crdName = "schemas.mysql.sample.javaoperatorsdk", - customResourceClass = Schema.class) + crdName = "schemas.mysql.sample.javaoperatorsdk.io", + customResourceClass = Schema.class) public class SchemaController implements ResourceController { static final String USERNAME_FORMAT = "%s-user"; static final String SECRET_FORMAT = "%s-secret"; diff --git a/samples/tomcat/pom.xml b/samples/tomcat/pom.xml index 65b4ca7712..f2dfabd6d8 100644 --- a/samples/tomcat/pom.xml +++ b/samples/tomcat/pom.xml @@ -45,11 +45,6 @@ commons-io 2.8.0 - - io.fabric8 - kubernetes-client - 4.12.0 - diff --git a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Tomcat.java b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Tomcat.java index 749048945f..8e18ed66ab 100644 --- a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Tomcat.java +++ b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Tomcat.java @@ -1,13 +1,14 @@ package io.javaoperatorsdk.operator.sample; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; -public class Tomcat extends CustomResource { - +public class Tomcat extends CustomResource implements Namespaced { + private TomcatSpec spec; - + private TomcatStatus status; - + public TomcatSpec getSpec() { if (spec == null) { spec = new TomcatSpec(); @@ -18,15 +19,20 @@ public TomcatSpec getSpec() { public void setSpec(TomcatSpec spec) { this.spec = spec; } - + public TomcatStatus getStatus() { if (status == null) { status = new TomcatStatus(); } return status; } - + public void setStatus(TomcatStatus status) { this.status = status; } + + @Override + public String getApiVersion() { + return "tomcatoperator.io/v1"; + } } \ No newline at end of file diff --git a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java index 1034ce1b39..7c65350cef 100644 --- a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java +++ b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java @@ -1,31 +1,32 @@ package io.javaoperatorsdk.operator.sample; -import io.javaoperatorsdk.operator.api.Context; -import io.javaoperatorsdk.operator.api.Controller; -import io.javaoperatorsdk.operator.api.ResourceController; -import io.javaoperatorsdk.operator.api.UpdateControl; -import io.fabric8.kubernetes.api.model.DoneableService; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.apps.Deployment; -import io.fabric8.kubernetes.api.model.apps.DoneableDeployment; -import io.fabric8.kubernetes.client.*; +import io.fabric8.kubernetes.client.CustomResourceList; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.WatcherException; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.dsl.RollableScalableResource; import io.fabric8.kubernetes.client.dsl.ServiceResource; import io.fabric8.kubernetes.client.utils.Serialization; +import io.javaoperatorsdk.operator.api.Context; +import io.javaoperatorsdk.operator.api.Controller; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.api.UpdateControl; import org.apache.commons.lang3.builder.EqualsBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; - @Controller(customResourceClass = Tomcat.class, crdName = "tomcats.tomcatoperator.io") public class TomcatController implements ResourceController { @@ -33,13 +34,14 @@ public class TomcatController implements ResourceController { private final Logger log = LoggerFactory.getLogger(getClass()); private final KubernetesClient kubernetesClient; - - private MixedOperation, CustomResourceDoneable, Resource>> tomcatOperations; + + private MixedOperation> tomcatOperations; private final List watchedResources = new ArrayList<>(); public TomcatController(KubernetesClient client) { this.kubernetesClient = client; + this.tomcatOperations = client.customResources(Tomcat.class, CustomResourceList.class); } private void updateTomcatStatus(Context context, Tomcat tomcat, Deployment deployment) { @@ -73,9 +75,9 @@ public void eventReceived(Action action, Deployment deployment) { log.error(ex.getMessage()); } } - + @Override - public void onClose(KubernetesClientException cause) { + public void onClose(WatcherException e) { } }); watchedResources.add(WatchedResource.fromResource(deployment)); @@ -121,9 +123,9 @@ private Deployment createOrUpdateDeployment(Tomcat tomcat) { private void deleteDeployment(Tomcat tomcat) { log.info("Deleting Deployment {}", tomcat.getMetadata().getName()); - RollableScalableResource deployment = kubernetesClient.apps().deployments() - .inNamespace(tomcat.getMetadata().getNamespace()) - .withName(tomcat.getMetadata().getName()); + final RollableScalableResource deployment = kubernetesClient.apps().deployments() + .inNamespace(tomcat.getMetadata().getNamespace()) + .withName(tomcat.getMetadata().getName()); if (deployment.get() != null) { deployment.delete(); } @@ -141,9 +143,9 @@ private void createOrUpdateService(Tomcat tomcat) { private void deleteService(Tomcat tomcat) { log.info("Deleting Service {}", tomcat.getMetadata().getName()); - ServiceResource service = kubernetesClient.services() - .inNamespace(tomcat.getMetadata().getNamespace()) - .withName(tomcat.getMetadata().getName()); + ServiceResource service = kubernetesClient.services() + .inNamespace(tomcat.getMetadata().getNamespace()) + .withName(tomcat.getMetadata().getName()); if (service.get() != null) { service.delete(); } @@ -157,10 +159,6 @@ private T loadYaml(Class clazz, String yaml) { } } - public void setTomcatOperations(MixedOperation, CustomResourceDoneable, Resource>> tomcatOperations) { - this.tomcatOperations = tomcatOperations; - } - private static class WatchedResource { private final String type; private final String name; diff --git a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatOperator.java b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatOperator.java index fe1efe418f..7cc45d0e68 100644 --- a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatOperator.java +++ b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatOperator.java @@ -1,10 +1,12 @@ package io.javaoperatorsdk.operator.sample; -import io.javaoperatorsdk.operator.Operator; +import java.io.IOException; + import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.DefaultKubernetesClient; import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.Operator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.takes.facets.fork.FkRegex; @@ -12,8 +14,6 @@ import org.takes.http.Exit; import org.takes.http.FtBasic; -import java.io.IOException; - public class TomcatOperator { private static final Logger log = LoggerFactory.getLogger(TomcatOperator.class); @@ -26,7 +26,6 @@ public static void main(String[] args) throws IOException { TomcatController tomcatController = new TomcatController(client); operator.registerControllerForAllNamespaces(tomcatController); - tomcatController.setTomcatOperations(operator.getCustomResourceClients(Tomcat.class)); operator.registerControllerForAllNamespaces(new WebappController(client)); diff --git a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Webapp.java b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Webapp.java index 124a2ed454..a5ea879795 100644 --- a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Webapp.java +++ b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Webapp.java @@ -1,29 +1,35 @@ package io.javaoperatorsdk.operator.sample; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; -public class Webapp extends CustomResource { - +public class Webapp extends CustomResource implements Namespaced { + private WebappSpec spec; - + private WebappStatus status; - + public WebappSpec getSpec() { return spec; } - + public void setSpec(WebappSpec spec) { this.spec = spec; } - + public WebappStatus getStatus() { if (status == null) { status = new WebappStatus(); } return status; } - + public void setStatus(WebappStatus status) { this.status = status; } + + @Override + public String getApiVersion() { + return "tomcatoperator.io/v1"; + } } \ No newline at end of file diff --git a/samples/webserver/README.md b/samples/webserver/README.md index e9ac920442..160500ad44 100644 --- a/samples/webserver/README.md +++ b/samples/webserver/README.md @@ -7,7 +7,7 @@ the html. This is an example input: ```yaml -apiVersion: "sample.javaoperatorsdk/v1" +apiVersion: "sample.javaoperatorsdk.io/v1" kind: WebServer metadata: name: mynginx-hello diff --git a/samples/webserver/crd/crd.yaml b/samples/webserver/crd/crd.yaml index 0ed1d373a7..f66b2141fe 100644 --- a/samples/webserver/crd/crd.yaml +++ b/samples/webserver/crd/crd.yaml @@ -1,9 +1,9 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: webservers.sample.javaoperatorsdk + name: webservers.sample.javaoperatorsdk.io spec: - group: sample.javaoperatorsdk + group: sample.javaoperatorsdk.io version: v1 scope: Namespaced names: diff --git a/samples/webserver/crd/webserver.yaml b/samples/webserver/crd/webserver.yaml index 0260bfb30f..d47875619d 100644 --- a/samples/webserver/crd/webserver.yaml +++ b/samples/webserver/crd/webserver.yaml @@ -1,4 +1,4 @@ -apiVersion: "sample.javaoperatorsdk/v1" +apiVersion: "sample.javaoperatorsdk.io/v1" kind: WebServer metadata: name: hellows diff --git a/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServer.java b/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServer.java index 9ec51c6954..5830fe269c 100644 --- a/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServer.java +++ b/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServer.java @@ -1,26 +1,32 @@ package io.javaoperatorsdk.operator.sample; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; -public class WebServer extends CustomResource { - +public class WebServer extends CustomResource implements Namespaced { + private WebServerSpec spec; - + private WebServerStatus status; - + public WebServerSpec getSpec() { return spec; } - + public void setSpec(WebServerSpec spec) { this.spec = spec; } - + public WebServerStatus getStatus() { return status; } - + public void setStatus(WebServerStatus status) { this.status = status; } + + @Override + public String getApiVersion() { + return "sample.javaoperatorsdk.io/v1"; + } } diff --git a/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServerController.java b/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServerController.java index 984e6d3d43..388dba938f 100644 --- a/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServerController.java +++ b/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServerController.java @@ -1,91 +1,95 @@ package io.javaoperatorsdk.operator.sample; -import io.javaoperatorsdk.operator.api.Context; -import io.javaoperatorsdk.operator.api.Controller; -import io.javaoperatorsdk.operator.api.ResourceController; -import io.javaoperatorsdk.operator.api.UpdateControl; -import io.fabric8.kubernetes.api.model.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; +import io.fabric8.kubernetes.api.model.DeletionPropagation; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.apps.Deployment; -import io.fabric8.kubernetes.api.model.apps.DoneableDeployment; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.dsl.RollableScalableResource; import io.fabric8.kubernetes.client.dsl.ServiceResource; import io.fabric8.kubernetes.client.utils.Serialization; +import io.javaoperatorsdk.operator.api.Context; +import io.javaoperatorsdk.operator.api.Controller; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.api.UpdateControl; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - @Controller(customResourceClass = WebServer.class, - crdName = "webservers.sample.javaoperatorsdk") + crdName = "webservers.sample.javaoperatorsdk.io") public class WebServerController implements ResourceController { - + private final Logger log = LoggerFactory.getLogger(getClass()); - + private final KubernetesClient kubernetesClient; - + public WebServerController(KubernetesClient kubernetesClient) { this.kubernetesClient = kubernetesClient; } - + @Override public UpdateControl createOrUpdateResource(WebServer webServer, Context context) { if (webServer.getSpec().getHtml().contains("error")) { throw new ErrorSimulationException("Simulating error"); } - + String ns = webServer.getMetadata().getNamespace(); - + Map data = new HashMap<>(); data.put("index.html", webServer.getSpec().getHtml()); - + ConfigMap htmlConfigMap = new ConfigMapBuilder() - .withMetadata(new ObjectMetaBuilder() - .withName(configMapName(webServer)) - .withNamespace(ns) - .build()) - .withData(data) - .build(); - + .withMetadata(new ObjectMetaBuilder() + .withName(configMapName(webServer)) + .withNamespace(ns) + .build()) + .withData(data) + .build(); + Deployment deployment = loadYaml(Deployment.class, "deployment.yaml"); deployment.getMetadata().setName(deploymentName(webServer)); deployment.getMetadata().setNamespace(ns); deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName(webServer)); deployment.getSpec().getTemplate().getMetadata().getLabels().put("app", deploymentName(webServer)); deployment.getSpec().getTemplate().getSpec().getVolumes().get(0).setConfigMap( - new ConfigMapVolumeSourceBuilder().withName(configMapName(webServer)).build()); - + new ConfigMapVolumeSourceBuilder().withName(configMapName(webServer)).build()); + Service service = loadYaml(Service.class, "service.yaml"); service.getMetadata().setName(serviceName(webServer)); service.getMetadata().setNamespace(ns); service.getSpec().setSelector(deployment.getSpec().getTemplate().getMetadata().getLabels()); - + ConfigMap existingConfigMap = kubernetesClient.configMaps() - .inNamespace(htmlConfigMap.getMetadata().getNamespace()) - .withName(htmlConfigMap.getMetadata().getName()).get(); - + .inNamespace(htmlConfigMap.getMetadata().getNamespace()) + .withName(htmlConfigMap.getMetadata().getName()).get(); + log.info("Creating or updating ConfigMap {} in {}", htmlConfigMap.getMetadata().getName(), ns); kubernetesClient.configMaps().inNamespace(ns).createOrReplace(htmlConfigMap); log.info("Creating or updating Deployment {} in {}", deployment.getMetadata().getName(), ns); kubernetesClient.apps().deployments().inNamespace(ns).createOrReplace(deployment); - + if (kubernetesClient.services().inNamespace(ns).withName(service.getMetadata().getName()).get() == null) { log.info("Creating Service {} in {}", service.getMetadata().getName(), ns); kubernetesClient.services().inNamespace(ns).createOrReplace(service); } - + if (existingConfigMap != null) { if (!StringUtils.equals(existingConfigMap.getData().get("index.html"), htmlConfigMap.getData().get("index.html"))) { log.info("Restarting pods because HTML has changed in {}", ns); kubernetesClient.pods().inNamespace(ns).withLabel("app", deploymentName(webServer)).delete(); } } - + WebServerStatus status = new WebServerStatus(); status.setHtmlConfigMap(htmlConfigMap.getMetadata().getName()); status.setAreWeGood("Yes!"); @@ -93,49 +97,49 @@ public UpdateControl createOrUpdateResource(WebServer webServer, Cont // throw new RuntimeException("Creating object failed, because it failed"); return UpdateControl.updateCustomResource(webServer); } - + @Override public boolean deleteResource(WebServer nginx, Context context) { log.info("Execution deleteResource for: {}", nginx.getMetadata().getName()); - + log.info("Deleting ConfigMap {}", configMapName(nginx)); - Resource configMap = kubernetesClient.configMaps() - .inNamespace(nginx.getMetadata().getNamespace()) - .withName(configMapName(nginx)); + Resource configMap = kubernetesClient.configMaps() + .inNamespace(nginx.getMetadata().getNamespace()) + .withName(configMapName(nginx)); if (configMap.get() != null) { configMap.delete(); } - + log.info("Deleting Deployment {}", deploymentName(nginx)); - RollableScalableResource deployment = kubernetesClient.apps().deployments() - .inNamespace(nginx.getMetadata().getNamespace()) - .withName(deploymentName(nginx)); + RollableScalableResource deployment = kubernetesClient.apps().deployments() + .inNamespace(nginx.getMetadata().getNamespace()) + .withName(deploymentName(nginx)); if (deployment.get() != null) { - deployment.cascading(true).delete(); + deployment.withPropagationPolicy(DeletionPropagation.FOREGROUND).delete(); } - + log.info("Deleting Service {}", serviceName(nginx)); - ServiceResource service = kubernetesClient.services() - .inNamespace(nginx.getMetadata().getNamespace()) - .withName(serviceName(nginx)); + ServiceResource service = kubernetesClient.services() + .inNamespace(nginx.getMetadata().getNamespace()) + .withName(serviceName(nginx)); if (service.get() != null) { service.delete(); } return true; } - + private static String configMapName(WebServer nginx) { return nginx.getMetadata().getName() + "-html"; } - + private static String deploymentName(WebServer nginx) { return nginx.getMetadata().getName(); } - + private static String serviceName(WebServer nginx) { return nginx.getMetadata().getName(); } - + private T loadYaml(Class clazz, String yaml) { try (InputStream is = getClass().getResourceAsStream(yaml)) { return Serialization.unmarshal(is, clazz); diff --git a/spring-boot-starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorAutoConfiguration.java b/spring-boot-starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorAutoConfiguration.java index b3c0b65656..c93d080675 100644 --- a/spring-boot-starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorAutoConfiguration.java +++ b/spring-boot-starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorAutoConfiguration.java @@ -1,6 +1,7 @@ package io.javaoperatorsdk.operator.springboot.starter; import java.util.List; +import java.util.Optional; import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.DefaultKubernetesClient; @@ -10,7 +11,6 @@ import io.javaoperatorsdk.operator.api.ResourceController; import io.javaoperatorsdk.operator.processing.retry.GenericRetry; import io.javaoperatorsdk.operator.processing.retry.Retry; -import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -22,24 +22,22 @@ @EnableConfigurationProperties({OperatorProperties.class, RetryProperties.class}) public class OperatorAutoConfiguration { private static final Logger log = LoggerFactory.getLogger(OperatorAutoConfiguration.class); - + @Bean @ConditionalOnMissingBean public KubernetesClient kubernetesClient(OperatorProperties operatorProperties) { ConfigBuilder config = new ConfigBuilder(); config.withTrustCerts(operatorProperties.isTrustSelfSignedCertificates()); - if (StringUtils.isNotBlank(operatorProperties.getUsername())) { - config.withUsername(operatorProperties.getUsername()); - } - if (StringUtils.isNotBlank(operatorProperties.getPassword())) { - config.withUsername(operatorProperties.getPassword()); - } - if (StringUtils.isNotBlank(operatorProperties.getMasterUrl())) { - config.withMasterUrl(operatorProperties.getMasterUrl()); - } + trimmedPropertyIfPresent(operatorProperties.getUsername()).ifPresent(config::withUsername); + trimmedPropertyIfPresent(operatorProperties.getPassword()).ifPresent(config::withPassword); + trimmedPropertyIfPresent(operatorProperties.getMasterUrl()).ifPresent(config::withMasterUrl); return operatorProperties.isOpenshift() ? new DefaultOpenShiftClient(config.build()) : new DefaultKubernetesClient(config.build()); } - + + private static Optional trimmedPropertyIfPresent(String string) { + return Optional.ofNullable(string).map(String::trim); + } + @Bean @ConditionalOnMissingBean(Operator.class) public Operator operator(KubernetesClient kubernetesClient, Retry retry, List resourceControllers) { @@ -47,7 +45,7 @@ public Operator operator(KubernetesClient kubernetesClient, Retry retry, List operator.registerControllerForAllNamespaces(r, retry)); return operator; } - + @Bean @ConditionalOnMissingBean public Retry retry(RetryProperties retryProperties) { diff --git a/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/model/TestResource.java b/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/model/TestResource.java index 06e41ad613..06e0924e6b 100644 --- a/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/model/TestResource.java +++ b/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/model/TestResource.java @@ -1,7 +1,8 @@ package io.javaoperatorsdk.operator.springboot.starter.model; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; -public class TestResource extends CustomResource { +public class TestResource extends CustomResource implements Namespaced { } diff --git a/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/model/TestResourceDoneable.java b/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/model/TestResourceDoneable.java deleted file mode 100644 index d3b249a134..0000000000 --- a/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/model/TestResourceDoneable.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.javaoperatorsdk.operator.springboot.starter.model; - -import io.fabric8.kubernetes.api.builder.Function; -import io.fabric8.kubernetes.client.CustomResourceDoneable; - -public class TestResourceDoneable extends CustomResourceDoneable { - public TestResourceDoneable(TestResource resource, Function function) { - super(resource, function); - } -}