示例#1
0
    def __init__(
            self,
            *,
            name: str = 'kopf',
            field: dicts.FieldSpec = 'status.{name}.progress',
            touch_field: dicts.FieldSpec = 'status.{name}.dummy',
    ) -> None:
        super().__init__()
        self._name = name

        real_field = field.format(name=name) if isinstance(field, str) else field
        self._field = dicts.parse_field(real_field)

        real_field = touch_field.format(name=name) if isinstance(touch_field, str) else touch_field
        self._touch_field = dicts.parse_field(real_field)
示例#2
0
def test_catchall_handlers_with_field_ignored(cause_no_field, registry,
                                              handler_factory):
    cause = cause_no_field
    handler_factory(field=parse_field('some-field'))
    handlers = registry.resource_spawning_handlers[
        cause.resource].get_handlers(cause)
    assert not handlers
示例#3
0
    def register(
            self,
            fn: ResourceHandlerFn,
            *,
            id: Optional[str] = None,
            reason: Optional[causation.Reason] = None,
            event: Optional[str] = None,  # deprecated, use `reason`
            field: Optional[dicts.FieldSpec] = None,
            errors: Optional[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[bodies.Labels] = None,
            annotations: Optional[bodies.Annotations] = None,
    ) -> ResourceHandlerFn:
        if reason is None and event is not None:
            reason = causation.Reason(event)

        real_field = dicts.parse_field(field) or None  # to not store tuple() as a no-field case.
        real_id = generate_id(fn=fn, id=id, prefix=self.prefix, suffix=".".join(real_field or []))
        handler = ResourceHandler(
            id=real_id, fn=fn, reason=reason, field=real_field,
            errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown,
            initial=initial, deleted=deleted, requires_finalizer=requires_finalizer,
            labels=labels, annotations=annotations,
        )

        self.append(handler)
        return fn
示例#4
0
文件: on.py 项目: zer0n1/kopf
 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
示例#5
0
文件: on.py 项目: zhutony/kopf
 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
示例#6
0
文件: on.py 项目: zer0n1/kopf
 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
示例#7
0
文件: on.py 项目: zer0n1/kopf
 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 test_catchall_handlers_with_field_ignored(cause_no_diff, registry,
                                              handler_factory):
    cause = cause_no_diff
    handler_factory(reason=None, field=parse_field('some-field'))
    handlers = registry.resource_changing_handlers[
        cause.resource].get_handlers(cause)
    assert not handlers
示例#9
0
 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
示例#10
0
    def register(
            self,
            fn: ResourceHandlerFn,
            id: Optional[str] = None,
            reason: Optional[causation.Reason] = None,
            event: Optional[str] = None,  # deprecated, use `reason`
            field: Optional[dicts.FieldSpec] = None,
            timeout: Optional[float] = None,
            initial: Optional[bool] = None,
            requires_finalizer: bool = False,
            labels: Optional[bodies.Labels] = None,
            annotations: Optional[bodies.Annotations] = None,
    ) -> ResourceHandlerFn:
        if reason is None and event is not None:
            reason = causation.Reason(event)

        real_field = dicts.parse_field(field) or None  # to not store tuple() as a no-field case.
        real_id = generate_id(fn=fn, id=id, prefix=self.prefix, suffix=".".join(real_field or []))
        handler = ResourceHandler(
            id=real_id, fn=fn, reason=reason, field=real_field, timeout=timeout,
            initial=initial,
            labels=labels, annotations=annotations,
        )

        self.append(handler)

        if requires_finalizer:
            self._handlers_requiring_finalizer.append(handler)

        return fn  # to be usable as a decorator too.
示例#11
0
    def register(
        self,
        fn: callbacks.ResourceChangingFn,
        *,
        resource: references.Selector,
        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,
    ) -> callbacks.ResourceChangingFn:
        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 = generate_id(fn=fn, id=id, suffix=".".join(real_field or []))
        handler = handlers.ResourceChangingHandler(
            id=real_id,
            fn=fn,
            reason=reason,
            errors=errors,
            timeout=timeout,
            retries=retries,
            backoff=backoff,
            cooldown=cooldown,
            initial=initial,
            deleted=deleted,
            requires_finalizer=requires_finalizer,
            selector=resource,
            labels=labels,
            annotations=annotations,
            when=when,
            field=real_field,
            value=None,
            old=None,
            new=None,
            field_needs_change=None,
        )

        self.append(handler)
        return fn
示例#12
0
 def __init__(
         self,
         *,
         name: str = 'kopf',
         field: dicts.FieldSpec = 'status.{name}.last-handled-configuration',
 ) -> None:
     super().__init__()
     self._name = name
     real_field = field.format(name=self._name) if isinstance(field, str) else field
     self._field = dicts.parse_field(real_field)
示例#13
0
 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
示例#14
0
文件: on.py 项目: zer0n1/kopf
 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
示例#15
0
 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
示例#16
0
def handler(request, callback, selector):
    handler = ResourceWatchingHandler(
        selector=selector,
        annotations={'known': 'value'},
        labels={'known': 'value'},
        field=parse_field('spec.field'),
        value='value',
        when=None,
        fn=some_fn,
        id='a',
        errors=None,
        timeout=None,
        retries=None,
        backoff=None,  # irrelevant
    )
    if request.param in ['annotations', 'labels']:
        handler = dataclasses.replace(handler,
                                      **{request.param: {
                                          'known': callback
                                      }})
    else:
        handler = dataclasses.replace(handler, **{request.param: callback})
    return handler
示例#17
0
 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
示例#18
0
 def field(self, field: dicts.FieldSpec) -> None:
     real_field = field.format(name=self._name) if isinstance(field, str) else field
     self._field = dicts.parse_field(real_field)
示例#19
0
import datetime
import logging
import time
from typing import AsyncGenerator, Collection, Iterable, Optional, Tuple, Type, Union

from kopf.clients import patching
from kopf.engines import loggers
from kopf.structs import bodies, configuration, containers, dicts, \
                         diffs, patches, primitives, references

# How often to wake up from the long sleep, to show liveness in the logs.
WAITING_KEEPALIVE_INTERVAL = 10 * 60

# K8s-managed fields that are removed completely when patched to an empty list/dict.
KNOWN_INCONSISTENCIES = (
    dicts.parse_field('metadata.annotations'),
    dicts.parse_field('metadata.finalizers'),
    dicts.parse_field('metadata.labels'),
)


async def apply(
        *,
        settings: configuration.OperatorSettings,
        resource: references.Resource,
        body: bodies.Body,
        patch: patches.Patch,
        delays: Collection[float],
        logger: loggers.ObjectLogger,
        stream_pressure: Optional[asyncio.Event] = None,  # None for tests
) -> bool:
示例#20
0
def test_from_string_one_level():
    path = parse_field('field')
    assert isinstance(path, tuple)
    assert path == ('field', )
示例#21
0
def test_catchall_handlers_with_field_found(
        cause_with_diff, registry, handler_factory):
    cause = cause_with_diff
    handler_factory(reason=None, field=parse_field('known-field'))
    handlers = registry._resource_changing.get_handlers(cause)
    assert handlers
示例#22
0
def test_catchall_handlers_with_field_found(cause_with_field, registry,
                                            handler_factory):
    cause = cause_with_field
    handler_factory(field=parse_field('known-field'))
    handlers = registry._resource_spawning.get_handlers(cause)
    assert handlers
示例#23
0
def test_from_string_two_levels():
    path = parse_field('field.subfield')
    assert isinstance(path, tuple)
    assert path == ('field', 'subfield')
示例#24
0
def test_from_list():
    path = parse_field(['field', 'subfield'])
    assert isinstance(path, tuple)
    assert path == ('field', 'subfield')
示例#25
0
def test_from_tuple():
    path = parse_field(('field', 'subfield'))
    assert isinstance(path, tuple)
    assert path == ('field', 'subfield')
示例#26
0
def test_catchall_handlers_with_field_found(cause_with_field, registry,
                                            handler_factory):
    cause = cause_with_field
    handler_factory(field=parse_field('some-field'))
    handlers = registry.resource_watching_handlers.get_handlers(cause)
    assert handlers
示例#27
0
def test_from_others_fails(val):
    with pytest.raises(ValueError):
        parse_field(val)
示例#28
0
def test_from_none():
    path = parse_field(None)
    assert isinstance(path, tuple)
    assert len(path) == 0
示例#29
0
def test_catchall_handlers_with_field_ignored(cause_no_field, registry,
                                              handler_factory):
    cause = cause_no_field
    handler_factory(field=parse_field('known-field'))
    handlers = registry._resource_watching.get_handlers(cause)
    assert not handlers