def _matches_metadata( *, pattern: filters.MetaFilter, # from the handler content: Mapping[str, str], # from the body kwargs: MutableMapping[str, Any], cause: causation.ResourceCause, ) -> bool: for key, value in pattern.items(): if value is filters.MetaFilterToken.ABSENT and key not in content: continue elif value is filters.MetaFilterToken.PRESENT and key in content: continue elif value is None and key in content: # deprecated; warned in @kopf.on continue elif callable(value): if not kwargs: kwargs.update(invocation.build_kwargs(cause=cause)) if value(content.get(key, None), **kwargs): continue else: return False elif key not in content: return False elif value != content[key]: return False else: continue return True
def _matches_field_values( handler: handlers.ResourceHandler, cause: causation.ResourceCause, kwargs: MutableMapping[str, Any], ) -> bool: if not handler.field: return True if not kwargs: kwargs.update(invocation.build_kwargs(cause=cause)) absent = _UNSET.token # or any other identifyable object if isinstance(cause, causation.ResourceChangingCause): # For on.update/on.field, so as for on.create/resume/delete for uniformity and simplicity: old = dicts.resolve(cause.old, handler.field, absent) new = dicts.resolve(cause.new, handler.field, absent) values = [ new, old ] # keep "new" first, to avoid "old" callbacks if "new" works. else: # For event-watching, timers/daemons (could also work for on.create/resume/delete): val = dicts.resolve(cause.body, handler.field, absent) values = [val] return ((handler.value is None and any(value is not absent for value in values)) or (handler.value is filters.PRESENT and any(value is not absent for value in values)) or (handler.value is filters.ABSENT and any(value is absent for value in values)) or (callable(handler.value) and any(handler.value(value, **kwargs) for value in values)) or (any(handler.value == value for value in values)))
def _matches_field_changes( handler: handlers.ResourceHandler, cause: causation.ResourceCause, kwargs: MutableMapping[str, Any], ) -> bool: if not isinstance(handler, handlers.ResourceChangingHandler): return True if not isinstance(cause, causation.ResourceChangingCause): return True if not handler.field: return True if not kwargs: kwargs.update(invocation.build_kwargs(cause=cause)) absent = _UNSET.token # or any other identifyable object old = dicts.resolve(cause.old, handler.field, absent) new = dicts.resolve(cause.new, handler.field, absent) return (( not handler.field_needs_change or old != new # ... or there IS a change. ) and ((handler.old is None) or (handler.old is filters.ABSENT and old is absent) or (handler.old is filters.PRESENT and old is not absent) or (callable(handler.old) and handler.old(old, **kwargs)) or (handler.old == old)) and ((handler.new is None) or (handler.new is filters.ABSENT and new is absent) or (handler.new is filters.PRESENT and new is not absent) or (callable(handler.new) and handler.new(new, **kwargs)) or (handler.new == new)))
def _matches_filter_callback( handler: handlers.ResourceHandler, cause: causation.ResourceCause, ) -> bool: if not handler.when: return True return handler.when(**invocation.build_kwargs(cause=cause))
def test_resource_changing_kwargs(resource, indices): body = { 'metadata': { 'uid': 'uid1', 'name': 'name1', 'namespace': 'ns1', 'labels': { 'l1': 'v1' }, 'annotations': { 'a1': 'v1' } }, 'spec': { 'field': 'value' }, 'status': { 'info': 'payload' } } cause = ResourceChangingCause( logger=logging.getLogger('kopf.test.fake.logger'), indices=indices, resource=resource, patch=Patch(), initial=False, reason=Reason.NOOP, memo=Memo(), body=Body(body), diff=Diff([]), old=BodyEssence(), new=BodyEssence(), ) kwargs = build_kwargs(cause=cause, extrakwarg=123) assert set(kwargs) == { 'extrakwarg', 'logger', 'index1', 'index2', 'resource', 'patch', 'reason', 'memo', 'body', 'spec', 'status', 'meta', 'uid', 'name', 'namespace', 'labels', 'annotations', 'diff', 'old', 'new' } assert kwargs['extrakwarg'] == 123 assert kwargs['resource'] is cause.resource assert kwargs['index1'] is indices['index1'] assert kwargs['index2'] is indices['index2'] assert kwargs['reason'] is cause.reason assert kwargs['logger'] is cause.logger assert kwargs['patch'] is cause.patch assert kwargs['memo'] is cause.memo assert kwargs['diff'] is cause.diff assert kwargs['old'] is cause.old assert kwargs['new'] is cause.new assert kwargs['body'] is cause.body assert kwargs['spec'] is cause.body.spec assert kwargs['meta'] is cause.body.metadata assert kwargs['status'] is cause.body.status assert kwargs['labels'] is cause.body.metadata.labels assert kwargs['annotations'] is cause.body.metadata.annotations assert kwargs['uid'] == cause.body.metadata.uid assert kwargs['name'] == cause.body.metadata.name assert kwargs['namespace'] == cause.body.metadata.namespace
def test_resource_watching_kwargs(resource, indices): body = { 'metadata': { 'uid': 'uid1', 'name': 'name1', 'namespace': 'ns1', 'labels': { 'l1': 'v1' }, 'annotations': { 'a1': 'v1' } }, 'spec': { 'field': 'value' }, 'status': { 'info': 'payload' } } cause = ResourceWatchingCause( logger=logging.getLogger('kopf.test.fake.logger'), indices=indices, resource=resource, patch=Patch(), memo=Memo(), body=Body(body), type='ADDED', raw={ 'type': 'ADDED', 'object': {} }, ) kwargs = build_kwargs(cause=cause, extrakwarg=123) assert set(kwargs) == { 'extrakwarg', 'logger', 'index1', 'index2', 'resource', 'patch', 'event', 'type', 'memo', 'body', 'spec', 'status', 'meta', 'uid', 'name', 'namespace', 'labels', 'annotations' } assert kwargs['extrakwarg'] == 123 assert kwargs['resource'] is cause.resource assert kwargs['index1'] is indices['index1'] assert kwargs['index2'] is indices['index2'] assert kwargs['logger'] is cause.logger assert kwargs['patch'] is cause.patch assert kwargs['event'] is cause.raw assert kwargs['memo'] is cause.memo assert kwargs['type'] is cause.type assert kwargs['body'] is cause.body assert kwargs['spec'] is cause.body.spec assert kwargs['meta'] is cause.body.metadata assert kwargs['status'] is cause.body.status assert kwargs['labels'] is cause.body.metadata.labels assert kwargs['annotations'] is cause.body.metadata.annotations assert kwargs['uid'] == cause.body.metadata.uid assert kwargs['name'] == cause.body.metadata.name assert kwargs['namespace'] == cause.body.metadata.namespace
def _matches_filter_callback( handler: handlers.ResourceHandler, cause: causation.ResourceCause, kwargs: MutableMapping[str, Any], ) -> bool: if handler.when is None: return True if not kwargs: kwargs.update(invocation.build_kwargs(cause=cause)) return handler.when(**kwargs)
def test_daemon_async_stopper(resource): cause = DaemonCause( logger=logging.getLogger('kopf.test.fake.logger'), resource=resource, patch=Patch(), memo=Memo(), body=Body({}), stopper=DaemonStopper(), ) kwargs = build_kwargs(cause=cause, _sync=False) assert kwargs['stopped'] is cause.stopper.async_checker
def test_activity_kwargs(resource, activity): cause = ActivityCause( logger=logging.getLogger('kopf.test.fake.logger'), activity=activity, settings=OperatorSettings(), ) kwargs = build_kwargs(cause=cause, extrakwarg=123) assert set(kwargs) == {'extrakwarg', 'logger', 'activity'} assert kwargs['extrakwarg'] == 123 assert kwargs['logger'] is cause.logger assert kwargs['activity'] is activity
def test_daemon_kwargs(resource, indices): body = { 'metadata': { 'uid': 'uid1', 'name': 'name1', 'namespace': 'ns1', 'labels': { 'l1': 'v1' }, 'annotations': { 'a1': 'v1' } }, 'spec': { 'field': 'value' }, 'status': { 'info': 'payload' } } cause = DaemonCause( logger=logging.getLogger('kopf.test.fake.logger'), indices=indices, resource=resource, patch=Patch(), memo=Memo(), body=Body(body), stopper=DaemonStopper(), ) kwargs = build_kwargs(cause=cause, extrakwarg=123) assert set(kwargs) == { 'extrakwarg', 'logger', 'index1', 'index2', 'resource', 'patch', 'memo', 'body', 'spec', 'status', 'meta', 'uid', 'name', 'namespace', 'labels', 'annotations' } assert kwargs['extrakwarg'] == 123 assert kwargs['resource'] is cause.resource assert kwargs['index1'] is indices['index1'] assert kwargs['index2'] is indices['index2'] assert kwargs['logger'] is cause.logger assert kwargs['patch'] is cause.patch assert kwargs['memo'] is cause.memo assert kwargs['body'] is cause.body assert kwargs['spec'] is cause.body.spec assert kwargs['meta'] is cause.body.metadata assert kwargs['status'] is cause.body.status assert kwargs['labels'] is cause.body.metadata.labels assert kwargs['annotations'] is cause.body.metadata.annotations assert kwargs['uid'] == cause.body.metadata.uid assert kwargs['name'] == cause.body.metadata.name assert kwargs['namespace'] == cause.body.metadata.namespace assert 'stopped' not in kwargs
def test_resource_spawning_kwargs(resource): body = { 'metadata': { 'uid': 'uid1', 'name': 'name1', 'namespace': 'ns1', 'labels': { 'l1': 'v1' }, 'annotations': { 'a1': 'v1' } }, 'spec': { 'field': 'value' }, 'status': { 'info': 'payload' } } cause = ResourceSpawningCause( logger=logging.getLogger('kopf.test.fake.logger'), resource=resource, patch=Patch(), memo=Memo(), body=Body(body), reset=False, ) kwargs = build_kwargs(cause=cause, extrakwarg=123) assert set(kwargs) == { 'extrakwarg', 'logger', 'resource', 'patch', 'memo', 'body', 'spec', 'status', 'meta', 'uid', 'name', 'namespace', 'labels', 'annotations' } assert kwargs['extrakwarg'] == 123 assert kwargs['resource'] is cause.resource assert kwargs['logger'] is cause.logger assert kwargs['patch'] is cause.patch assert kwargs['memo'] is cause.memo assert kwargs['body'] is cause.body assert kwargs['spec'] is cause.body.spec assert kwargs['meta'] is cause.body.metadata assert kwargs['status'] is cause.body.status assert kwargs['labels'] is cause.body.metadata.labels assert kwargs['annotations'] is cause.body.metadata.annotations assert kwargs['uid'] == cause.body.metadata.uid assert kwargs['name'] == cause.body.metadata.name assert kwargs['namespace'] == cause.body.metadata.namespace
def test_activity_kwargs(resource, activity, indices): cause = ActivityCause( memo=Memo(), logger=logging.getLogger('kopf.test.fake.logger'), indices=indices, activity=activity, settings=OperatorSettings(), ) kwargs = build_kwargs(cause=cause, extrakwarg=123) assert set(kwargs) == { 'extrakwarg', 'memo', 'logger', 'index1', 'index2', 'activity' } assert kwargs['extrakwarg'] == 123 assert kwargs['index1'] is indices['index1'] assert kwargs['index2'] is indices['index2'] assert kwargs['logger'] is cause.logger assert kwargs['activity'] is activity
async def execute_handlers_once( lifecycle: lifecycles.LifeCycleFn, settings: configuration.OperatorSettings, handlers: Collection[handlers_.BaseHandler], cause: causation.BaseCause, state: states.State, default_errors: handlers_.ErrorsMode = handlers_.ErrorsMode.TEMPORARY, ) -> Mapping[handlers_.HandlerId, states.HandlerOutcome]: """ Call the next handler(s) from the chain of the handlers. Keep the record on the progression of the handlers in the object's state, and use it on the next invocation to determined which handler(s) to call. This routine is used both for the global handlers (via global registry), and for the sub-handlers (via a simple registry of the current handler). """ # Filter and select the handlers to be executed right now, on this event reaction cycle. handlers_todo = [h for h in handlers if state[h.id].awakened] handlers_plan = lifecycle( handlers_todo, **invocation.build_kwargs(cause=cause, state=state)) # Execute all planned (selected) handlers in one event reaction cycle, even if there are few. outcomes: MutableMapping[handlers_.HandlerId, states.HandlerOutcome] = {} for handler in handlers_plan: outcome = await execute_handler_once( settings=settings, handler=handler, state=state[handler.id], cause=cause, lifecycle= lifecycle, # just a default for the sub-handlers, not used directly. default_errors=default_errors, ) outcomes[handler.id] = outcome return outcomes
def test_resource_admission_kwargs(resource, indices): body = { 'metadata': { 'uid': 'uid1', 'name': 'name1', 'namespace': 'ns1', 'labels': { 'l1': 'v1' }, 'annotations': { 'a1': 'v1' } }, 'spec': { 'field': 'value' }, 'status': { 'info': 'payload' } } cause = ResourceWebhookCause( logger=logging.getLogger('kopf.test.fake.logger'), indices=indices, resource=resource, patch=Patch(), memo=Memo(), body=Body(body), dryrun=False, headers={'k1': 'v1'}, sslpeer={'k2': 'v2'}, userinfo={'k3': 'v3'}, warnings=['w1'], webhook=None, reason=None, operation=None, ) kwargs = build_kwargs(cause=cause, extrakwarg=123) assert set(kwargs) == { 'extrakwarg', 'logger', 'index1', 'index2', 'resource', 'dryrun', 'headers', 'sslpeer', 'userinfo', 'warnings', 'patch', 'memo', 'body', 'spec', 'status', 'meta', 'uid', 'name', 'namespace', 'labels', 'annotations' } assert kwargs['extrakwarg'] == 123 assert kwargs['resource'] is cause.resource assert kwargs['index1'] is indices['index1'] assert kwargs['index2'] is indices['index2'] assert kwargs['logger'] is cause.logger assert kwargs['dryrun'] is cause.dryrun assert kwargs['headers'] is cause.headers assert kwargs['sslpeer'] is cause.sslpeer assert kwargs['userinfo'] is cause.userinfo assert kwargs['warnings'] is cause.warnings assert kwargs['patch'] is cause.patch assert kwargs['memo'] is cause.memo assert kwargs['body'] is cause.body assert kwargs['spec'] is cause.body.spec assert kwargs['meta'] is cause.body.metadata assert kwargs['status'] is cause.body.status assert kwargs['labels'] is cause.body.metadata.labels assert kwargs['annotations'] is cause.body.metadata.annotations assert kwargs['uid'] == cause.body.metadata.uid assert kwargs['name'] == cause.body.metadata.name assert kwargs['namespace'] == cause.body.metadata.namespace