How to use the kopf.reactor.causation.Reason function in kopf

To help you get started, we’ve selected a few kopf examples, based on popular ways it is used in public projects.

Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.

github zalando-incubator / kopf / tests / handling / test_cause_logging.py View on Github external
async def test_all_logs_are_prefixed(registry, resource, handlers,
                                     logstream, cause_type, cause_mock):
    event_type = None if cause_type == Reason.RESUME else 'irrelevant'
    cause_mock.reason = cause_type

    await resource_handler(
        lifecycle=kopf.lifecycles.all_at_once,
        registry=registry,
        resource=resource,
        memories=ResourceMemories(),
        event={'type': event_type, 'object': cause_mock.body},
        replenished=asyncio.Event(),
        event_queue=asyncio.Queue(),
    )

    lines = logstream.getvalue().splitlines()
    assert lines  # no messages means that we cannot test it
    assert all(line.startswith('prefix [ns1/name1] ') for line in lines)
github zalando-incubator / kopf / tests / invocations / test_callbacks.py View on Github external
async def test_special_kwargs_added(fn, resource):
    body = {'metadata': {'uid': 'uid', 'name': 'name', 'namespace': 'ns'},
            'spec': {'field': 'value'},
            'status': {'info': 'payload'}}

    # Values can be any.
    cause = ResourceChangingCause(
        logger=logging.getLogger('kopf.test.fake.logger'),
        resource=resource,
        patch=Patch(),
        initial=False,
        reason=Reason.NOOP,
        memo=object(),
        body=body,
        diff=object(),
        old=object(),
        new=object(),
    )

    fn = MagicMock(fn)
    await invoke(fn, cause=cause)

    assert fn.called
    assert fn.call_count == 1

    assert len(fn.call_args[1]) >= 2
    assert fn.call_args[1]['cause'] is cause
    assert fn.call_args[1]['event'] is cause.reason  # deprecated
github zalando-incubator / kopf / tests / handling / test_retrying_limits.py View on Github external
async def test_retries_limited_handler_fails(
        registry, handlers, extrahandlers, resource, cause_mock, cause_type,
        caplog, assert_logs, k8s_mocked):
    caplog.set_level(logging.DEBUG)
    name1 = f'{cause_type}_fn'

    event_type = None if cause_type == Reason.RESUME else 'irrelevant'
    cause_mock.reason = cause_type
    cause_mock.body.update({
        'status': {'kopf': {'progress': {
            'create_fn': {'retries': 100},
            'update_fn': {'retries': 100},
            'delete_fn': {'retries': 100},
            'resume_fn': {'retries': 100},
        }}}
    })

    await resource_handler(
        lifecycle=kopf.lifecycles.one_by_one,
        registry=registry,
        resource=resource,
        memories=ResourceMemories(),
        event={'type': event_type, 'object': cause_mock.body},
github zalando-incubator / kopf / tests / handling / test_multistep.py View on Github external
async def test_1st_step_stores_progress_by_patching(
        registry, handlers, extrahandlers,
        resource, cause_mock, cause_type, k8s_mocked):
    name1 = f'{cause_type}_fn'
    name2 = f'{cause_type}_fn2'

    event_type = None if cause_type == Reason.RESUME else 'irrelevant'
    cause_mock.reason = cause_type

    await resource_handler(
        lifecycle=kopf.lifecycles.asap,
        registry=registry,
        resource=resource,
        memories=ResourceMemories(),
        event={'type': event_type, 'object': cause_mock.body},
        replenished=asyncio.Event(),
        event_queue=asyncio.Queue(),
    )

    assert handlers.create_mock.call_count == (1 if cause_type == Reason.CREATE else 0)
    assert handlers.update_mock.call_count == (1 if cause_type == Reason.UPDATE else 0)
    assert handlers.delete_mock.call_count == (1 if cause_type == Reason.DELETE else 0)
    assert handlers.resume_mock.call_count == (1 if cause_type == Reason.RESUME else 0)
github zalando-incubator / kopf / tests / causation / test_detection.py View on Github external
def test_for_gone(kwargs, event, finalizers, deletion_ts, requires_finalizer):
    event = {'type': event, 'object': {'metadata': {}}}
    event['object']['metadata'].update(finalizers)
    event['object']['metadata'].update(deletion_ts)
    cause = detect_resource_changing_cause(
        event=event,
        requires_finalizer=requires_finalizer,
        **kwargs)
    assert cause.reason == Reason.GONE
    check_kwargs(cause, kwargs)
github zalando-incubator / kopf / tests / handling / test_multistep.py View on Github external
cause_mock.reason = cause_type

    await resource_handler(
        lifecycle=kopf.lifecycles.asap,
        registry=registry,
        resource=resource,
        memories=ResourceMemories(),
        event={'type': event_type, 'object': cause_mock.body},
        replenished=asyncio.Event(),
        event_queue=asyncio.Queue(),
    )

    assert handlers.create_mock.call_count == (1 if cause_type == Reason.CREATE else 0)
    assert handlers.update_mock.call_count == (1 if cause_type == Reason.UPDATE else 0)
    assert handlers.delete_mock.call_count == (1 if cause_type == Reason.DELETE else 0)
    assert handlers.resume_mock.call_count == (1 if cause_type == Reason.RESUME else 0)

    assert not k8s_mocked.sleep_or_wait.called
    assert k8s_mocked.patch_obj.called

    patch = k8s_mocked.patch_obj.call_args_list[0][1]['patch']
    assert patch['status']['kopf']['progress'] is not None

    assert patch['status']['kopf']['progress'][name1]['retries'] == 1
    assert patch['status']['kopf']['progress'][name1]['success'] is True

    assert patch['status']['kopf']['progress'][name2]['retries'] == 0
    assert patch['status']['kopf']['progress'][name2]['success'] is False

    assert patch['status']['kopf']['progress'][name1]['started']
    assert patch['status']['kopf']['progress'][name2]['started']
github zalando-incubator / kopf / kopf / reactor / causation.py View on Github external
# The object was really deleted from the cluster. But we do not care anymore.
    if event['type'] == 'DELETED':
        return ResourceChangingCause(reason=Reason.GONE, **kwargs)

    # The finalizer has been just removed. We are fully done.
    if finalizers.is_deleted(body) and not finalizers.has_finalizers(body):
        return ResourceChangingCause(reason=Reason.FREE, **kwargs)

    if finalizers.is_deleted(body):
        return ResourceChangingCause(reason=Reason.DELETE, **kwargs)

    # For a fresh new object, first block it from accidental deletions without our permission.
    # The actual handler will be called on the next call.
    # Only return this cause if the resource requires finalizers to be added.
    if requires_finalizer and not finalizers.has_finalizers(body):
        return ResourceChangingCause(reason=Reason.ACQUIRE, **kwargs)

    # Check whether or not the resource has finalizers, but doesn't require them. If this is
    # the case, then a resource may not be able to be deleted completely as finalizers may
    # not be removed by the operator under normal operation. We remove the finalizers first,
    # and any handler that should be called will be done on the next call.
    if not requires_finalizer and finalizers.has_finalizers(body):
        return ResourceChangingCause(reason=Reason.RELEASE, **kwargs)

    # For an object seen for the first time (i.e. just-created), call the creation handlers,
    # then mark the state as if it was seen when the creation has finished.
    # Creation never mixes with resuming, even if an object is detected on startup (first listing).
    if not lastseen.has_essence_stored(body):
        kwargs['initial'] = False
        return ResourceChangingCause(reason=Reason.CREATE, **kwargs)

    # Cases with no essence changes are usually ignored (NOOP). But for the not-yet-resumed objects,
github zalando-incubator / kopf / kopf / reactor / causation.py View on Github external
# These sets are checked in few places, so we keep them centralised:
# the user-facing causes (for handlers) and internally facing (for the reactor).
HANDLER_REASONS = (
    Reason.CREATE,
    Reason.UPDATE,
    Reason.DELETE,
    Reason.RESUME,
)
REACTOR_REASONS = (
    Reason.NOOP,
    Reason.FREE,
    Reason.GONE,
    Reason.ACQUIRE,
    Reason.RELEASE,
)
ALL_REASONS = HANDLER_REASONS + REACTOR_REASONS

# The human-readable names of these causes. Will be capitalised when needed.
TITLES = {
    Reason.CREATE: 'creation',
    Reason.UPDATE: 'update',
    Reason.DELETE: 'deletion',
    Reason.RESUME: 'resuming',
}


@dataclasses.dataclass
class BaseCause:
    logger: Union[logging.Logger, logging.LoggerAdapter]
github zalando-incubator / kopf / kopf / reactor / causation.py View on Github external
# Put them back to the pass-through kwargs (to avoid code duplication).
    body = event['object']
    kwargs.update(body=body, initial=initial)
    if diff is not None:
        kwargs.update(diff=diff)

    # The object was really deleted from the cluster. But we do not care anymore.
    if event['type'] == 'DELETED':
        return ResourceChangingCause(reason=Reason.GONE, **kwargs)

    # The finalizer has been just removed. We are fully done.
    if finalizers.is_deleted(body) and not finalizers.has_finalizers(body):
        return ResourceChangingCause(reason=Reason.FREE, **kwargs)

    if finalizers.is_deleted(body):
        return ResourceChangingCause(reason=Reason.DELETE, **kwargs)

    # For a fresh new object, first block it from accidental deletions without our permission.
    # The actual handler will be called on the next call.
    # Only return this cause if the resource requires finalizers to be added.
    if requires_finalizer and not finalizers.has_finalizers(body):
        return ResourceChangingCause(reason=Reason.ACQUIRE, **kwargs)

    # Check whether or not the resource has finalizers, but doesn't require them. If this is
    # the case, then a resource may not be able to be deleted completely as finalizers may
    # not be removed by the operator under normal operation. We remove the finalizers first,
    # and any handler that should be called will be done on the next call.
    if not requires_finalizer and finalizers.has_finalizers(body):
        return ResourceChangingCause(reason=Reason.RELEASE, **kwargs)

    # For an object seen for the first time (i.e. just-created), call the creation handlers,
    # then mark the state as if it was seen when the creation has finished.
github zalando-incubator / kopf / kopf / reactor / causation.py View on Github external
RELEASE = 'release'

    def __str__(self) -> str:
        return str(self.value)


# These sets are checked in few places, so we keep them centralised:
# the user-facing causes (for handlers) and internally facing (for the reactor).
HANDLER_REASONS = (
    Reason.CREATE,
    Reason.UPDATE,
    Reason.DELETE,
    Reason.RESUME,
)
REACTOR_REASONS = (
    Reason.NOOP,
    Reason.FREE,
    Reason.GONE,
    Reason.ACQUIRE,
    Reason.RELEASE,
)
ALL_REASONS = HANDLER_REASONS + REACTOR_REASONS

# The human-readable names of these causes. Will be capitalised when needed.
TITLES = {
    Reason.CREATE: 'creation',
    Reason.UPDATE: 'update',
    Reason.DELETE: 'deletion',
    Reason.RESUME: 'resuming',
}