kopf icon indicating copy to clipboard operation
kopf copied to clipboard

Question: Dynamically adding events

Open dgr237 opened this issue 5 years ago • 2 comments

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?

dgr237 avatar Dec 11 '19 13:12 dgr237

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 or asyncio.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 as memo.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.

nolar avatar Dec 11 '19 13:12 nolar

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.

fsniper avatar Jan 28 '20 23:01 fsniper