def decorator( fn: callbacks.ResourceHandlerFn) -> callbacks.ResourceHandlerFn: parent_handler = handling.handler_var.get() real_registry = registry if registry is not None else handling.subregistry_var.get( ) real_id = registries.generate_id( fn=fn, id=id, prefix=parent_handler.id if parent_handler else None) handler = handlers.ResourceHandler( fn=fn, id=real_id, field=None, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, labels=labels, annotations=annotations, when=when, initial=None, deleted=None, requires_finalizer=None, reason=None, ) real_registry.append(handler) return fn
def decorator( fn: callbacks.ResourceHandlerFn) -> callbacks.ResourceHandlerFn: real_registry = registry if registry is not None else registries.get_default_registry( ) real_resource = resources.Resource(group, version, plural) real_id = registries.generate_id(fn=fn, id=id) handler = handlers.ResourceHandler( fn=fn, id=real_id, field=None, errors=None, timeout=None, retries=None, backoff=None, cooldown=None, labels=labels, annotations=annotations, when=when, initial=None, deleted=None, requires_finalizer=None, reason=None, ) real_registry.resource_watching_handlers[real_resource].append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceChangingFn, ) -> callbacks.ResourceChangingFn: _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) _warn_conflicting_values(field, value) real_registry = registry if registry is not None else registries.get_default_registry( ) real_field = dicts.parse_field( field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id) selector = references.Selector(group, version, plural) handler = handlers.ResourceChangingHandler( fn=fn, id=real_id, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, selector=selector, labels=labels, annotations=annotations, when=when, field=real_field, value=value, old=None, new=None, field_needs_change=False, initial=None, deleted=None, requires_finalizer=bool(not optional), reason=handlers.Reason.DELETE, ) real_registry.resource_changing_handlers.append(handler) return fn
def decorator(fn: callbacks.ResourceTimerFn) -> callbacks.ResourceTimerFn: _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) real_registry = registry if registry is not None else registries.get_default_registry( ) real_resource = resources.Resource(group, version, plural) real_id = registries.generate_id(fn=fn, id=id) handler = handlers.ResourceTimerHandler( fn=fn, id=real_id, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, labels=labels, annotations=annotations, when=when, initial_delay=initial_delay, requires_finalizer=None, sharp=sharp, idle=idle, interval=interval, ) real_registry.resource_spawning_handlers[real_resource].append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceWatchingFn, ) -> callbacks.ResourceWatchingFn: _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) _warn_conflicting_values(field, value) real_registry = registry if registry is not None else registries.get_default_registry( ) real_field = dicts.parse_field( field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id) selector = references.Selector(group, version, plural) handler = handlers.ResourceWatchingHandler( fn=fn, id=real_id, errors=None, timeout=None, retries=None, backoff=None, cooldown=None, selector=selector, labels=labels, annotations=annotations, when=when, field=real_field, value=value, ) real_registry.resource_watching_handlers.append(handler) return fn
def decorator( fn: callbacks.ResourceDaemonFn) -> callbacks.ResourceDaemonFn: _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) real_registry = registry if registry is not None else registries.get_default_registry( ) real_resource = resources.Resource(group, version, plural) real_id = registries.generate_id(fn=fn, id=id) handler = handlers.ResourceDaemonHandler( fn=fn, id=real_id, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, labels=labels, annotations=annotations, when=when, initial_delay=initial_delay, requires_finalizer=True, #TODO: requires_finalizer? "optional"? cancellation_backoff=cancellation_backoff, cancellation_timeout=cancellation_timeout, cancellation_polling=cancellation_polling, ) real_registry.resource_spawning_handlers[real_resource].append(handler) return fn
def decorator( fn: callbacks.ResourceChangingFn) -> callbacks.ResourceChangingFn: _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) real_registry = registry if registry is not None else registries.get_default_registry( ) real_resource = resources.Resource(group, version, plural) real_id = registries.generate_id(fn=fn, id=id) handler = handlers.ResourceChangingHandler( fn=fn, id=real_id, field=None, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, labels=labels, annotations=annotations, when=when, initial=None, deleted=None, requires_finalizer=bool(not optional), reason=handlers.Reason.DELETE, ) real_registry.resource_changing_handlers[real_resource].append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceTimerFn, ) -> callbacks.ResourceTimerFn: _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) _warn_conflicting_values(field, value) real_registry = registry if registry is not None else registries.get_default_registry( ) real_field = dicts.parse_field( field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id) selector = references.Selector(group, version, plural) handler = handlers.ResourceTimerHandler( fn=fn, id=real_id, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, selector=selector, labels=labels, annotations=annotations, when=when, field=real_field, value=value, initial_delay=initial_delay, requires_finalizer=True, sharp=sharp, idle=idle, interval=interval, ) real_registry.resource_spawning_handlers.append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceChangingFn, ) -> callbacks.ResourceChangingFn: _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) parent_handler = handling.handler_var.get() real_registry = registry if registry is not None else handling.subregistry_var.get( ) real_id = registries.generate_id( fn=fn, id=id, prefix=parent_handler.id if parent_handler else None) handler = handlers.ResourceChangingHandler( fn=fn, id=real_id, field=None, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, labels=labels, annotations=annotations, when=when, initial=None, deleted=None, requires_finalizer=None, reason=None, ) real_registry.append(handler) return fn
def decorator( fn: callbacks.ResourceHandlerFn) -> callbacks.ResourceHandlerFn: real_registry = registry if registry is not None else registries.get_default_registry( ) real_resource = resources.Resource(group, version, plural) real_field = dicts.parse_field( field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id, suffix=".".join(real_field or [])) handler = handlers.ResourceHandler( fn=fn, id=real_id, field=real_field, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, labels=labels, annotations=annotations, when=when, initial=None, deleted=None, requires_finalizer=None, reason=None, ) real_registry.resource_changing_handlers[real_resource].append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceDaemonFn, ) -> callbacks.ResourceDaemonFn: _warn_conflicting_values(field, value) _verify_filters(labels, annotations) real_registry = registry if registry is not None else registries.get_default_registry() real_field = dicts.parse_field(field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id, suffix=".".join(real_field or [])) selector = references.Selector( __group_or_groupversion_or_name, __version_or_name, __name, group=group, version=version, kind=kind, plural=plural, singular=singular, shortcut=shortcut, category=category, ) handler = handlers.ResourceDaemonHandler( fn=fn, id=real_id, param=param, errors=errors, timeout=timeout, retries=retries, backoff=backoff, selector=selector, labels=labels, annotations=annotations, when=when, field=real_field, value=value, initial_delay=initial_delay, requires_finalizer=True, cancellation_backoff=cancellation_backoff, cancellation_timeout=cancellation_timeout, cancellation_polling=cancellation_polling, ) real_registry._resource_spawning.append(handler) return fn
def register( self, fn: AnyHandlerFn, *, id: Optional[str] = None, reason: Optional[handlers.Reason] = None, event: Optional[str] = None, # deprecated, use `reason` field: Optional[dicts.FieldSpec] = None, errors: Optional[handlers.ErrorsMode] = None, timeout: Optional[float] = None, retries: Optional[int] = None, backoff: Optional[float] = None, cooldown: Optional[float] = None, # deprecated, use `backoff` initial: Optional[bool] = None, deleted: Optional[bool] = None, requires_finalizer: bool = False, labels: Optional[filters.MetaFilter] = None, annotations: Optional[filters.MetaFilter] = None, when: Optional[callbacks.WhenFilterFn] = None, ) -> AnyHandlerFn: warnings.warn( "registry.register() is deprecated; " "use @kopf.on... decorators with registry= kwarg.", DeprecationWarning) if reason is None and event is not None: reason = handlers.Reason(event) real_field = dicts.parse_field( field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id, suffix=".".join(real_field or [])) handler = LegacyAllPurposeResourcerHandler( id=real_id, fn=fn, # type: ignore reason=reason, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, initial=initial, deleted=deleted, requires_finalizer=requires_finalizer, selector=None, labels=labels, annotations=annotations, when=when, field=real_field, value=None, old=None, new=None, field_needs_change=None, ) self.append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ActivityFn, ) -> callbacks.ActivityFn: real_registry = registry if registry is not None else registries.get_default_registry() real_id = registries.generate_id(fn=fn, id=id) handler = handlers.ActivityHandler( fn=fn, id=real_id, param=param, errors=errors, timeout=timeout, retries=retries, backoff=backoff, activity=handlers.Activity.AUTHENTICATION, ) real_registry._activities.append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceChangingFn, ) -> callbacks.ResourceChangingFn: _warn_conflicting_values(field, value) _verify_filters(labels, annotations) real_registry = registry if registry is not None else registries.get_default_registry( ) real_field = dicts.parse_field( field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id, suffix=".".join(real_field or [])) selector = references.Selector( __group_or_groupversion_or_name, __version_or_name, __name, group=group, version=version, kind=kind, plural=plural, singular=singular, shortcut=shortcut, category=category, ) handler = handlers.ResourceChangingHandler( fn=fn, id=real_id, param=param, errors=errors, timeout=timeout, retries=retries, backoff=backoff, selector=selector, labels=labels, annotations=annotations, when=when, field=real_field, value=value, old=None, new=None, field_needs_change=False, initial=None, deleted=None, requires_finalizer=bool(not optional), reason=handlers.Reason.DELETE, ) real_registry._resource_changing.append(handler) return fn
def decorator(fn: callbacks.ActivityFn) -> callbacks.ActivityFn: _warn_deprecated_signatures(fn) real_registry = registry if registry is not None else registries.get_default_registry( ) real_id = registries.generate_id(fn=fn, id=id) handler = handlers.ActivityHandler( fn=fn, id=real_id, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, activity=handlers.Activity.STARTUP, ) real_registry.activity_handlers.append(handler) return fn
def decorator( fn: callbacks.ActivityHandlerFn) -> callbacks.ActivityHandlerFn: real_registry = registry if registry is not None else registries.get_default_registry( ) real_id = registries.generate_id(fn=fn, id=id) handler = handlers.ActivityHandler( fn=fn, id=real_id, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, activity=causation.Activity.CLEANUP, ) real_registry.activity_handlers.append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceChangingFn, ) -> callbacks.ResourceChangingFn: parent_handler = handling.handler_var.get() if not isinstance(parent_handler, handlers.ResourceChangingHandler): raise TypeError( "Sub-handlers are only supported for resource-changing handlers." ) _warn_incompatible_parent_with_oldnew(parent_handler, old, new) _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) _warn_conflicting_values(field, value, old, new) real_registry = registry if registry is not None else handling.subregistry_var.get( ) real_field = dicts.parse_field( field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id( fn=fn, id=id, prefix=parent_handler.id if parent_handler else None) handler = handlers.ResourceChangingHandler( fn=fn, id=real_id, errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown, selector=None, labels=labels, annotations=annotations, when=when, field=real_field, value=value, old=old, new=new, field_needs_change=parent_handler. field_needs_change, # inherit dymaically initial=None, deleted=None, requires_finalizer=None, reason=None, ) real_registry.append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceWatchingFn, ) -> callbacks.ResourceWatchingFn: _warn_conflicting_values(field, value) _verify_filters(labels, annotations) real_registry = registry if registry is not None else registries.get_default_registry() real_field = dicts.parse_field(field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id) selector = references.Selector( __group_or_groupversion_or_name, __version_or_name, __name, group=group, version=version, kind=kind, plural=plural, singular=singular, shortcut=shortcut, category=category, ) handler = handlers.ResourceWatchingHandler( fn=fn, id=real_id, errors=None, timeout=None, retries=None, backoff=None, selector=selector, labels=labels, annotations=annotations, when=when, field=real_field, value=value, ) real_registry._resource_watching.append(handler) return fn
def decorator( fn: callbacks.ResourceWatchingFn) -> callbacks.ResourceWatchingFn: _warn_deprecated_signatures(fn) _warn_deprecated_filters(labels, annotations) real_registry = registry if registry is not None else registries.get_default_registry( ) real_resource = resources.Resource(group, version, plural) real_id = registries.generate_id(fn=fn, id=id) handler = handlers.ResourceWatchingHandler( fn=fn, id=real_id, errors=None, timeout=None, retries=None, backoff=None, cooldown=None, labels=labels, annotations=annotations, when=when, ) real_registry.resource_watching_handlers[real_resource].append(handler) return fn
def decorator( # lgtm[py/similar-function] fn: callbacks.ResourceWebhookFn, ) -> callbacks.ResourceWebhookFn: _warn_conflicting_values(field, value) _verify_filters(labels, annotations) real_registry = registry if registry is not None else registries.get_default_registry() real_field = dicts.parse_field(field) or None # to not store tuple() as a no-field case. real_id = registries.generate_id(fn=fn, id=id, suffix=".".join(real_field or [])) selector = references.Selector( __group_or_groupversion_or_name, __version_or_name, __name, group=group, version=version, kind=kind, plural=plural, singular=singular, shortcut=shortcut, category=category, ) handler = handlers.ResourceWebhookHandler( fn=fn, id=real_id, param=param, errors=None, timeout=None, retries=None, backoff=None, # TODO: add some meaning later selector=selector, labels=labels, annotations=annotations, when=when, field=real_field, value=value, reason=handlers.WebhookType.MUTATING, operation=operation, persistent=persistent, side_effects=side_effects, ignore_failures=ignore_failures, ) real_registry._resource_webhooks.append(handler) return fn
async def execute( *, fns: Optional[Iterable[callbacks.ResourceChangingFn]] = None, handlers: Optional[Iterable[handlers_.ResourceChangingHandler]] = None, registry: Optional[registries.ResourceChangingRegistry] = None, lifecycle: Optional[lifecycles.LifeCycleFn] = None, cause: Optional[causation.BaseCause] = None, ) -> None: """ Execute the handlers in an isolated lifecycle. This function is just a public wrapper for `execute` with multiple ways to specify the handlers: either as the raw functions, or as the pre-created handlers, or as a registry (as used in the object handling). If no explicit functions or handlers or registry are passed, the sub-handlers of the current handler are assumed, as accumulated in the per-handler registry with ``@kopf.subhandler``. If the call to this method for the sub-handlers is not done explicitly in the handler, it is done implicitly after the handler is exited. One way or another, it is executed for the sub-handlers. """ # Restore the current context as set in the handler execution cycle. lifecycle = lifecycle if lifecycle is not None else sublifecycle_var.get() lifecycle = lifecycle if lifecycle is not None else lifecycles.get_default_lifecycle( ) cause = cause if cause is not None else cause_var.get() parent_handler: handlers_.BaseHandler = handler_var.get() parent_prefix = parent_handler.id if parent_handler is not None else None # Validate the inputs; the function signatures cannot put these kind of restrictions, so we do. if len([v for v in [fns, handlers, registry] if v is not None]) > 1: raise TypeError( "Only one of the fns, handlers, registry can be passed. Got more.") elif fns is not None and isinstance(fns, collections.abc.Mapping): subregistry = registries.ResourceChangingRegistry() for id, fn in fns.items(): real_id = registries.generate_id(fn=fn, id=id, prefix=parent_prefix) handler = handlers_.ResourceChangingHandler( fn=fn, id=real_id, errors=None, timeout=None, retries=None, backoff=None, cooldown=None, selector=None, labels=None, annotations=None, when=None, initial=None, deleted=None, requires_finalizer=None, reason=None, field=None, value=None, old=None, new=None, field_needs_change=None, ) subregistry.append(handler) elif fns is not None and isinstance(fns, collections.abc.Iterable): subregistry = registries.ResourceChangingRegistry() for fn in fns: real_id = registries.generate_id(fn=fn, id=None, prefix=parent_prefix) handler = handlers_.ResourceChangingHandler( fn=fn, id=real_id, errors=None, timeout=None, retries=None, backoff=None, cooldown=None, selector=None, labels=None, annotations=None, when=None, initial=None, deleted=None, requires_finalizer=None, reason=None, field=None, value=None, old=None, new=None, field_needs_change=None, ) subregistry.append(handler) elif fns is not None: raise ValueError( f"fns must be a mapping or an iterable, got {fns.__class__}.") elif handlers is not None: subregistry = registries.ResourceChangingRegistry() for handler in handlers: subregistry.append(handler) # Use the registry as is; assume that the caller knows what they do. elif registry is not None: subregistry = registry # Prevent double implicit execution. elif subexecuted_var.get(): return # If no explicit args were passed, use the accumulated handlers from `@kopf.subhandler`. else: subexecuted_var.set(True) subregistry = subregistry_var.get() # The sub-handlers are only for upper-level causes, not for lower-level events. if not isinstance(cause, causation.ResourceChangingCause): raise RuntimeError( "Sub-handlers of event-handlers are not supported and have " "no practical use (there are no retries or state tracking).") # Execute the real handlers (all or few or one of them, as per the lifecycle). settings: configuration.OperatorSettings = subsettings_var.get() owned_handlers = subregistry.get_resource_handlers(resource=cause.resource) cause_handlers = subregistry.get_handlers(cause=cause) storage = settings.persistence.progress_storage state = states.State.from_storage(body=cause.body, storage=storage, handlers=owned_handlers) state = state.with_purpose(cause.reason).with_handlers(cause_handlers) outcomes = await execute_handlers_once( lifecycle=lifecycle, settings=settings, handlers=cause_handlers, cause=cause, state=state, ) state = state.with_outcomes(outcomes) state.store(body=cause.body, patch=cause.patch, storage=storage) states.deliver_results(outcomes=outcomes, patch=cause.patch) # Enrich all parents with references to sub-handlers of any level deep (sub-sub-handlers, etc). # There is at least one container, as this function can be called only from a handler. subrefs_containers: Iterable[Set[handlers_.HandlerId]] = subrefs_var.get() for key in state: for subrefs_container in subrefs_containers: subrefs_container.add(key) # Escalate `HandlerChildrenRetry` if the execute should be continued on the next iteration. if not state.done: raise HandlerChildrenRetry(delay=state.delay)