Comments (2)
I am not sure that I got the idea right. So the answer may be wrong or irrelevant. But this is how I would approach it:
Since there are pods involved, there is a need for pod-handler. Since not all pods should be involved, we have to filter them. Since the criteria of filtering are quite sophisticated, I would use callbacks:
import kopf
def does_it_match(**_) -> bool:
return True
@kopf.on.event('', 'v1', 'pods', when=does_it_match)
def pod_event(**_):
pass
So, at this moment, all pods in the cluster/namespace will be intercepted. Now, we need to narrow the criteria. Since there is a selector in a CR, I would keep that global state of all selectors in memory, mapping to the original CRs they came from:
from typing import MutableMapping, Mapping
import kopf
SelectorKey = Tuple[str, str] # (namespace, name)
SelectorLabels = Mapping[str, str]
SELECTORS: MutableMapping[SelectorKey, SelectorLabels] = {}
@kopf.on.create('zalando.org', 'v1', 'kopfexamples')
@kopf.on.resume('zalando.org', 'v1', 'kopfexamples')
@kopf.on.update('zalando.org', 'v1', 'kopfexamples') # optionally
def cr_appears(namespace, name, spec, **_):
key = (namespace, name)
SELECTORS[key] = spec.get('selector', {})
@kopf.on.delete('zalando.org', 'v1', 'kopfexamples')
def cr_disappears(spec, **_):
key = (namespace, name)
try:
del SELECTORS[key]
except KeyError:
pass
So, at this point, we would have data for filtering the pods. Now, I would actually filter in that function above:
def does_it_match(labels: Mapping[str, str], **_) -> bool:
for (namespace, name), selector_labels in SELECTORS.items():
if all(labels.get(key) == val for key, val in selector_labels.items()):
return True
return False
Now, the pods that do not match any known selector, will be silently ignored. Notice: they will get into the sight of the operator itself — in one and only one watch-stream — but will be filtered out in the earliest stages, with no logs produced (silently).
This is a difference here from your suggested approach: instead of having N watch-stream with labels in the URL (where N is the number of CRs with selectors), there will be one and only one watch-stream (and therefore TCP/HTTP/API connection), seeing all the pods, and just picking those of our interest, and ignoring others.
This will easy the API side, but will put some CPU load to the operator. The RAM footprint will be minimal, though not zero: every pod will spawn its own worker task (asyncio.Task), where the pod events will be routed to, and almost instantly ignored; but the tasks are objects too — on a cluster with thousands of pods this can be noticed.
As a continuation, using the same for
+ if
, I would be able to detect to which CRs each individual pod corresponds (one or or even a few of them) — in the handler itself. And do something with that pod as the contextual object (in kwargs) and the detected CRs. Perhaps, the CRs' spec should be also preserved somewhere in the global state, so that we would know what to do specifically — after the matching CRs are identified by their selectors.
The downside here is that you have to keep some state in memory — for all the CRs, or all the pods, or all of something, depending on which of them you expect to be the least memory consuming.
I am not yet sure if it is possible to solve the cross-resource communication in any other way: when an event happens on a pod, no events happen on the CRs, so we have nothing to "join". You either scan your own in-memory state, or K8s's in-memory state via the K8s API on every pod event (costly!). But the up-to-date state must be somewhere there.
PS: The typing thing is fully optional, and is ignored at runtime. I just got a habit of using it for clarity.
from kopf.
I still think the dynamic handler registration is a bit more convenient, but you are right that it is less scalable than the approach you outlined.
However, with your approach, it might happen that a pod is created (and generates no events afterwards) before the corresponding CR appears in the system or vice versa, so I think the operator should store all the relevant info for both CRs and pods. This is doable but gets complicated when the CRD contains a namespace field in addition to the selector field.
At any rate, I'm going to ignore the namespace field in my operator and go with your idea. Thank you for enlightening me.
from kopf.
Related Issues (20)
- Force-kill the operator from inside if stuck at exiting HOT 1
- Resource grows too big with multiple operators for same resource HOT 5
- Watch for changes in array items.
- Resources filtered out in event handlers still get annotated by Kopf HOT 1
- Field handler is trigger even if the field does not exist in the resource at the time. HOT 2
- Need advice on the way to achieve service monitoring using a daemon HOT 3
- Is there any real world use of kopf,like rook/ceph? HOT 3
- Root task 'watcher of kopfexamples.zalando.org' is failed: 403, message='Forbidden' - EKS HOT 2
- Can't apply turtorial crd.yaml example,The CustomResourceDefinition "ephemeralvolumeclaims.zalando.org" is invalid HOT 1
- Creating a filter based on metadata.ownerReferences.kind == Statefulset HOT 1
- Subhandler states are not cleared at the end of handling cycle HOT 3
- All handlers succeeded for creation despite raising kopf.HandlerFatalError HOT 3
- Docs use wrong name for kopf.AnnotationsDiffBaseStorage HOT 1
- @kopf.timer continues to run after CR is deleted HOT 2
- client_timeout on watch results in a fatal error HOT 1
- AttributeError: 'NoneType' object has no attribute 'loader' HOT 1
- Reload / Restart all Kopf handlers when a configmap changes.
- Dedicated channel for asking questions regarding kopf usage?
- Exceptions for kopf on event for network connectivity delayed / issues
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from kopf.