kopf
kopf copied to clipboard
Question: Dynamically adding events
Is it possible to dynamically register/unregister event handlers? I have a use case where when a Custom Resource Definition is created/deleted (which I am handling through on.delete and on.create handlers) I want to dynamically listen with an on.event handler for instances of the crd being created/updated/deleted.
Is this possible and if so how would I do this?
I think, it is possible. Though it was never an intended use-case, probably can be broken in the future, and the consequences of doing so are unknown.
One problem that I see right now: there is not un-registering the handlers at the moment, but it can be easily added.
Another way is to use the operator embedding with kopf.operator()
. The intention is to embed operator pattern ("watch-and-react") to arbitrary applications like UIs, etc. But a CRD-operator can be such a top-level application, with the per-kind-operators being the embedded operators.
- whenever a CRD is created, construct a
kopf.OperatorRegistry()
, create a flag (threading.Event
orasyncio.Event
), and spawn (fire-and-forget) an asyncio task or a new thread with these registry+flag as arguments. - remember the flag in the
memo
kwarg asmemo.stopmenow = flag
. - whenever a CRD is deleted, raise the flag as
memo.stopmenow.set()
.
Or, similarly, you can remember and then cancel an asyncio.Task
.
Do I get it right that you want to watch for the CRD definitions directly, and then additionally operate the resources of that CRD?
That case can be covered by #85 — though not implemented now. E.g., you would be able to watch for:
@kopf.on.event('*', '*', '*')
def create_anything(resource, body, **_):
pass
@kopf.on.event('zalando.org', '*', 'kopfexamples')
def create_any_version_of_kex(resource, body, **_):
pass
@kopf.on.event('zalando.org', 'v1', '*')
def create_any_resource_type(resource, body, **_):
pass
... and the framework would do the discovery and live-updating of the CRDs (actually, of any RDs, custom and built-in).
Since recently, when kopf.clients.discovery
and background activities (now: startup, cleanup, authentication) were added, this feature is at least implementable.
Though, I never put it to a priority list, as could not find a realistic use-case.
I am also working on a kind of related use case.
I have a static CRD that I watch, and this CRD has a list of other kinds (group/version/kind) to watch and operate on.
I started calling kopf.on.event decorators as methods to register new watchers. This works as expected.
def manifest_created(**kwargs):
print("A new manifest is created")
@kop.on.create('group','v1', 'crd')
def create(**kwargs):
# this is acquired from the watched manifest
r = ('group', 'version', 'kind')
kopf.on.create(*r)(manifest_created)
Of course unregister problem still applies. Probably looking into operator embedding would be easier than trying to unregister handlers.