Skip to content

Event sources M1 #235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 95 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
dde1d48
Update control changes
csviri Aug 6, 2020
4e98dea
- create dispatch control class
csviri Aug 6, 2020
ee58fb5
Merge branch 'master' into event_put_back
csviri Aug 24, 2020
a4e6773
- intermediate structure for event propagation
csviri Aug 24, 2020
5aed016
- steps for reprocessing related changes
csviri Aug 28, 2020
47b12b3
design-docs
csviri Aug 28, 2020
d25a8c6
impl skeleton
csviri Sep 6, 2020
49a546f
impl skeleton
csviri Sep 6, 2020
4c263d6
impl skeleton progress
csviri Sep 7, 2020
bcc5d5f
progress on event sourcing
csviri Sep 14, 2020
8f9fe23
progress on event sourcing
csviri Sep 18, 2020
75e2b47
progress on event sourcing ...
csviri Sep 18, 2020
18772de
progress on event sourcing ...
csviri Sep 29, 2020
98a0960
progress on event sourcing ...
csviri Oct 3, 2020
9fd4935
progress on event sourcing ...
csviri Oct 3, 2020
b76ebbd
progress on event sourcing ... build the app
csviri Oct 3, 2020
fe8f781
progress on event sourcing ... normal handling of delete
csviri Oct 3, 2020
082dc86
progress on event sourcing ...
csviri Oct 3, 2020
2142695
progress on event sourcing ...
csviri Oct 3, 2020
2bc21ba
progress on event sourcing - cleanup
csviri Oct 4, 2020
e65987a
progress on event sourcing - retry
csviri Oct 4, 2020
f1ee2b8
progress on event sourcing
csviri Oct 8, 2020
af4b45f
progress on event sourcing
csviri Oct 14, 2020
e8d55aa
Merge branch 'master' into event-sources
csviri Oct 23, 2020
9ddf03f
merged master
csviri Oct 23, 2020
e9a0095
event design update
csviri Nov 4, 2020
96c3a82
Merge branch 'master' into event-sources
csviri Nov 4, 2020
cce39fd
delayed event processing
csviri Nov 4, 2020
6bb95bd
post review meeting updates
csviri Nov 11, 2020
10be8fa
Merge branch 'master' into event-sources
csviri Nov 13, 2020
c4651ef
merged master after refactor
csviri Nov 13, 2020
66cdcb4
remove retry from the API
csviri Nov 13, 2020
5b71dcf
Better naming for event handler
csviri Nov 13, 2020
f8c253f
Merge branch 'master' into event-sources
csviri Nov 19, 2020
be6b165
merge master fix
csviri Nov 19, 2020
c26f157
dispatcher improvements, timer skeleton
csviri Nov 19, 2020
f46ca07
Merge branch 'master' into event-sources
csviri Nov 19, 2020
0467f07
merged master, build fix
csviri Nov 19, 2020
e974467
default finalizer naming correction, timer event source
csviri Nov 19, 2020
def23c5
CR and improvements
csviri Nov 19, 2020
5552ecb
tests, improvements
csviri Nov 24, 2020
94a59d9
tests, improvements
csviri Nov 24, 2020
1ce3316
Merge branch 'master' into event-sources
csviri Nov 24, 2020
8103a2e
timer event source tests, improvements
csviri Nov 24, 2020
36f594e
DefaultEventSourceManager tests
csviri Nov 24, 2020
970426a
Update DECISION_LOG.md
csviri Nov 25, 2020
0f7b846
Update operator-framework/src/main/java/io/javaoperatorsdk/operator/p…
csviri Nov 25, 2020
95fc68b
Update operator-framework/src/main/java/io/javaoperatorsdk/operator/p…
csviri Nov 25, 2020
b2b8c86
Update operator-framework/src/main/java/io/javaoperatorsdk/operator/p…
csviri Nov 25, 2020
5e916e5
Update operator-framework/src/main/java/io/javaoperatorsdk/operator/p…
csviri Nov 25, 2020
b0f5bd7
Update operator-framework/src/main/java/io/javaoperatorsdk/operator/p…
csviri Nov 25, 2020
5dc2a36
Update operator-framework/src/main/java/io/javaoperatorsdk/operator/p…
csviri Nov 25, 2020
8149fe8
Update operator-framework/src/main/java/io/javaoperatorsdk/operator/p…
csviri Nov 25, 2020
37c6ef6
fixes
csviri Nov 25, 2020
1e40d29
build fix
csviri Nov 25, 2020
b43cd0b
naming Threads
csviri Nov 25, 2020
9939058
Delete control as enum
csviri Nov 25, 2020
4961697
formatting
csviri Nov 25, 2020
dd572ca
reconnect because of "resource version too old"
csviri Nov 25, 2020
d627e95
Update operator-framework/src/main/java/io/javaoperatorsdk/operator/p…
csviri Nov 27, 2020
28af82d
Merge branch 'master' into event-sources
csviri Nov 27, 2020
e18532f
fixed test for new api
csviri Nov 27, 2020
68d76a1
logging improvements
csviri Nov 27, 2020
3b19eac
additional dispatcher tests
csviri Nov 27, 2020
f0481be
decorational changes
csviri Nov 27, 2020
8eab7fe
supplier for registering event sources
csviri Nov 27, 2020
3564f04
experimental implementation of dependent resources
csviri Nov 27, 2020
0782fac
fix log message
adam-sandor Nov 28, 2020
0214a8a
make interface more generic
adam-sandor Nov 28, 2020
1d7e80b
refactor utils class to make for clearer responsibilities
adam-sandor Nov 28, 2020
e5e5b02
fix null event source manager from context
csviri Nov 28, 2020
31f8fb5
Merge branch 'eventsourcetest' into event-sources
adam-sandor Nov 28, 2020
ae4533b
delete of experimental package
csviri Nov 30, 2020
f276ff6
Merge remote-tracking branch 'origin/event-sources' into event-sources
csviri Nov 30, 2020
8d11728
simple event source integration test
csviri Nov 30, 2020
1288657
naming improvement
csviri Nov 30, 2020
134dd05
event sources improvements, simplified APIs
csviri Nov 30, 2020
b9748ca
* Event becomes non generic
adam-sandor Nov 30, 2020
740efac
Merge pull request #242 from java-operator-sdk/event-sources-adam
adam-sandor Nov 30, 2020
c8ee02c
make internal list in EventList public
adam-sandor Nov 30, 2020
988fe7b
Merge pull request #244 from java-operator-sdk/event-sources-adam
adam-sandor Nov 30, 2020
f59f274
improvements on post execution control
csviri Dec 2, 2020
476d512
Merge remote-tracking branch 'origin/event-sources' into event-sources
csviri Dec 2, 2020
3527250
event list fix, unit test
csviri Dec 2, 2020
a389ecf
imports fix
csviri Dec 2, 2020
323e2a8
once event source
csviri Dec 2, 2020
1548361
caching of resources from update
csviri Dec 2, 2020
9f55ecb
test improvements
csviri Dec 2, 2020
a17ec3b
fixing bug with test
csviri Dec 2, 2020
f917aaa
cache update improvements
csviri Dec 2, 2020
7bb065a
call init method before registering custom resource event-source
csviri Dec 3, 2020
5e5423b
moving generation handling to custom resource event source. Better ha…
csviri Dec 3, 2020
5162f4d
Merge branch 'master' into event-sources
csviri Dec 3, 2020
b879a97
Merge branch 'master' into event-sources
csviri Dec 3, 2020
d4cda3d
docs update
csviri Dec 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions DECISION_LOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Decision Log


## Event Sources

### 1. Move Retries to an Abstract Controller.

The original idea was to explicitly support retry in the scheduler. However, this turned out to complicate the algorithm
in case of event sources. Mostly it would be harder to manage the buffer, and the other event sources, thus what
does it mean for other event sources that there was a failed controller execution? Probably it would be better to
manage this in an abstract controller, and just use the "reprocess event-source" source in case of an error.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ The Controller implements the business logic and describes all the classes neede
public class WebServerController implements ResourceController<WebServer> {

@Override
public boolean deleteResource(CustomService resource, Context<WebServer> context) {
public DeleteControl deleteResource(CustomService resource, Context<WebServer> context) {
// ... your logic ...
return true;
return DeleteControl.DEFAULT_DELETE;
}

// Return the changed resource, so it gets updated. See javadoc for details.
Expand Down
1 change: 1 addition & 0 deletions docs/event-design.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2020-11-11T11:37:34.373Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36" etag="RN6pgE0b8M6KAgj9wCQV" version="13.8.8" type="device"><diagram id="YHX19W9oFLqZG9bJU0nv" name="Page-1">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</diagram></mxfile>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


class ControllerToCustomResourceMappingsProvider {
private static final Logger log = LoggerFactory.getLogger(ControllerUtils.class);
private static final Logger log = LoggerFactory.getLogger(ControllerToCustomResourceMappingsProvider.class);

static Map<Class<? extends ResourceController>, Class<? extends CustomResource>> provide(final String resourcePath) {
Map<Class<? extends ResourceController>, Class<? extends CustomResource>> controllerToCustomResourceMappings = new HashMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ static String getCrdName(ResourceController controller) {
return getAnnotation(controller).crdName();
}


public static <T extends CustomResource> Class<? extends CustomResourceDoneable<T>>
getCustomResourceDoneableClass(ResourceController<T> controller) {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.javaoperatorsdk.operator;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.Watcher;
import io.javaoperatorsdk.operator.processing.event.Event;
import io.javaoperatorsdk.operator.processing.event.internal.CustomResourceEvent;

import java.util.List;

public class EventListUtils {

public static boolean containsCustomResourceDeletedEvent(List<Event> events) {
return events.stream().anyMatch(e -> {
if (e instanceof CustomResourceEvent) {
return ((CustomResourceEvent) e).getAction() == Watcher.Action.DELETED;
} else {
return false;
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
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 io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinition;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.client.CustomResourceDoneable;
Expand All @@ -14,13 +9,22 @@
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.DefaultEventHandler;
import io.javaoperatorsdk.operator.processing.CustomResourceCache;
import io.javaoperatorsdk.operator.processing.event.DefaultEventSourceManager;
import io.javaoperatorsdk.operator.processing.event.internal.CustomResourceEventSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static io.javaoperatorsdk.operator.ControllerUtils.*;


@SuppressWarnings("rawtypes")
public class Operator {

Expand All @@ -34,58 +38,61 @@ public Operator(KubernetesClient k8sClient) {


public <R extends CustomResource> void registerControllerForAllNamespaces(ResourceController<R> controller) throws OperatorException {
registerController(controller, true, GenericRetry.defaultLimitedExponentialRetry());
}

public <R extends CustomResource> void registerControllerForAllNamespaces(ResourceController<R> controller, Retry retry) throws OperatorException {
registerController(controller, true, retry);
registerController(controller, true);
}

public <R extends CustomResource> void registerController(ResourceController<R> controller, String... targetNamespaces) throws OperatorException {
registerController(controller, false, GenericRetry.defaultLimitedExponentialRetry(), targetNamespaces);
}

public <R extends CustomResource> void registerController(ResourceController<R> controller, Retry retry, String... targetNamespaces) throws OperatorException {
registerController(controller, false, retry, targetNamespaces);
registerController(controller, false, targetNamespaces);
}

@SuppressWarnings("rawtypes")
private <R extends CustomResource> void registerController(ResourceController<R> controller,
boolean watchAllNamespaces, Retry retry, String... targetNamespaces) throws OperatorException {
Class<R> resClass = ControllerUtils.getCustomResourceClass(controller);
boolean watchAllNamespaces, String... targetNamespaces) throws OperatorException {
Class<R> resClass = 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));
EventDispatcher eventDispatcher = new EventDispatcher(controller,
finalizer, new EventDispatcher.CustomResourceFacade(client), ControllerUtils.getGenerationEventProcessing(controller));
EventScheduler eventScheduler = new EventScheduler(eventDispatcher, retry);
registerWatches(controller, client, resClass, watchAllNamespaces, targetNamespaces, eventScheduler);
}
finalizer, new EventDispatcher.CustomResourceFacade(client));


private <R extends CustomResource> void registerWatches(ResourceController<R> controller, MixedOperation client,
Class<R> resClass,
boolean watchAllNamespaces, String[] targetNamespaces, EventScheduler eventScheduler) {

CustomResourceOperationsImpl crClient = (CustomResourceOperationsImpl) client;
if (watchAllNamespaces) {
crClient.inAnyNamespace().watch(eventScheduler);
} else if (targetNamespaces.length == 0) {
client.watch(eventScheduler);
} else {
for (String targetNamespace : targetNamespaces) {
crClient.inNamespace(targetNamespace).watch(eventScheduler);
log.debug("Registered controller for namespace: {}", targetNamespace);
}
}
CustomResourceCache customResourceCache = new CustomResourceCache();
DefaultEventHandler defaultEventHandler = new DefaultEventHandler(customResourceCache, eventDispatcher, controller.getClass().getName());
DefaultEventSourceManager eventSourceManager = new DefaultEventSourceManager(defaultEventHandler);
defaultEventHandler.setDefaultEventSourceManager(eventSourceManager);
eventDispatcher.setEventSourceManager(eventSourceManager);

customResourceClients.put(resClass, (CustomResourceOperationsImpl) client);

controller.init(eventSourceManager);
CustomResourceEventSource customResourceEventSource
= createCustomResourceEventSource(client, customResourceCache, watchAllNamespaces, targetNamespaces,
defaultEventHandler, ControllerUtils.getGenerationEventProcessing(controller));
eventSourceManager.registerCustomResourceEventSource(customResourceEventSource);


log.info("Registered Controller: '{}' for CRD: '{}' for namespaces: {}", controller.getClass().getSimpleName(),
resClass, targetNamespaces.length == 0 ? "[all/client namespace]" : Arrays.toString(targetNamespaces));
}

private CustomResourceEventSource createCustomResourceEventSource(MixedOperation client,
CustomResourceCache customResourceCache,
boolean watchAllNamespaces,
String[] targetNamespaces,
DefaultEventHandler defaultEventHandler,
boolean generationAware) {
CustomResourceEventSource customResourceEventSource = watchAllNamespaces ?
CustomResourceEventSource.customResourceEventSourceForAllNamespaces(customResourceCache, client, generationAware) :
CustomResourceEventSource.customResourceEventSourceForTargetNamespaces(customResourceCache, client, targetNamespaces, generationAware);

customResourceEventSource.setEventHandler(defaultEventHandler);

return customResourceEventSource;
}

private CustomResourceDefinitionContext getCustomResourceDefinitionForController(ResourceController controller) {
String crdName = ControllerUtils.getCrdName(controller);
String crdName = getCrdName(controller);
CustomResourceDefinition customResourceDefinition = k8sClient.customResourceDefinitions().withName(crdName).get();
if (customResourceDefinition == null) {
throw new OperatorException("Cannot find Custom Resource Definition with name: " + crdName);
Expand All @@ -103,11 +110,4 @@ public Map<Class<? extends CustomResource>, CustomResourceOperationsImpl> getCus
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();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package io.javaoperatorsdk.operator.api;

import io.fabric8.kubernetes.client.CustomResource;
import io.javaoperatorsdk.operator.processing.event.Event;
import io.javaoperatorsdk.operator.processing.event.EventList;
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;

import java.util.List;

public interface Context<T extends CustomResource> {

RetryInfo retryInfo();
EventSourceManager getEventSourceManager();

EventList getEvents();

}
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
package io.javaoperatorsdk.operator.api;

import io.fabric8.kubernetes.client.CustomResource;
import io.javaoperatorsdk.operator.processing.event.Event;
import io.javaoperatorsdk.operator.processing.event.EventList;
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;

import java.util.List;

public class DefaultContext<T extends CustomResource> implements Context<T> {

private final RetryInfo retryInfo;
private final EventList events;
private final EventSourceManager eventSourceManager;

public DefaultContext(RetryInfo retryInfo) {
this.retryInfo = retryInfo;
public DefaultContext(EventSourceManager eventSourceManager, EventList events) {
this.events = events;
this.eventSourceManager = eventSourceManager;
}

@Override
public RetryInfo retryInfo() {
return retryInfo;
public EventSourceManager getEventSourceManager() {
return eventSourceManager;
}

@Override
public EventList getEvents() {
return events;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.javaoperatorsdk.operator.api;

public enum DeleteControl {

DEFAULT_DELETE,
NO_FINALIZER_REMOVAL

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.javaoperatorsdk.operator.api;

import io.fabric8.kubernetes.client.CustomResource;
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;

public interface ResourceController<R extends CustomResource> {

Expand All @@ -15,10 +16,12 @@ public interface ResourceController<R extends CustomResource> {
* @return true - so the finalizer is automatically removed after the call.
* false if you don't want to remove the finalizer. Note that this is ALMOST NEVER the case.
*/
boolean deleteResource(R resource, Context<R> context);
DeleteControl deleteResource(R resource, Context<R> context);

/**
* The implementation of this operation is required to be idempotent.
* Always use the UpdateControl object to make updates on custom resource if possible.
* Also always use the custom resource parameter (not the custom resource that might be in the events)
*
* @return The resource is updated in api server if the return value is present
* within Optional. This the common use cases. However in cases, for example the operator is restarted,
Expand All @@ -27,4 +30,10 @@ public interface ResourceController<R extends CustomResource> {
* <b>However we will always call an update if there is no finalizer on object and its not marked for deletion.</b>
*/
UpdateControl<R> createOrUpdateResource(R resource, Context<R> context);

/**
* In init typically you might want to register event sources.
* @param eventSourceManager
*/
default void init(EventSourceManager eventSourceManager) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package io.javaoperatorsdk.operator.processing;

import io.fabric8.kubernetes.client.CustomResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;

public class CustomResourceCache {
private static final Logger log = LoggerFactory.getLogger(CustomResourceCache.class);

private final Map<String, CustomResource> resources = new ConcurrentHashMap<>();
private final Lock lock = new ReentrantLock();

public void cacheResource(CustomResource resource) {
try {
lock.lock();
resources.put(KubernetesResourceUtils.getUID(resource), resource);
} finally {
lock.unlock();
}
}

public void cacheResource(CustomResource resource, Predicate<CustomResource> predicate) {
try {
lock.lock();
if (predicate.test(resources.get(KubernetesResourceUtils.getUID(resource)))) {
log.trace("Update cache after condition is true: {}", resource);
resources.put(resource.getMetadata().getUid(), resource);
}
} finally {
lock.unlock();
}
}

public Optional<CustomResource> getLatestResource(String uuid) {
return Optional.ofNullable(resources.get(uuid));
}

public CustomResource cleanup(String customResourceUid) {
return resources.remove(customResourceUid);
}
}
Loading