Exemple #1
0
 def decorator(  # lgtm[py/similar-function]
         fn: callbacks.DaemonFn,
 ) -> callbacks.DaemonFn:
     _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.DaemonHandler(
         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._spawning.append(handler)
     return fn
Exemple #2
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)
Exemple #3
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)
Exemple #4
0
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.ChangingFn, ) -> callbacks.ChangingFn:
     _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.ChangingHandler(
         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=causes.Reason.DELETE,
     )
     real_registry._changing.append(handler)
     return fn
Exemple #5
0
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.WebhookFn, ) -> callbacks.WebhookFn:
     _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.WebhookHandler(
         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=causes.WebhookType.MUTATING,
         operation=operation,
         persistent=persistent,
         side_effects=side_effects,
         ignore_failures=ignore_failures,
     )
     real_registry._webhooks.append(handler)
     return fn
Exemple #6
0
 def decorator(  # lgtm[py/similar-function]
         fn: callbacks.IndexingFn,
 ) -> callbacks.IndexingFn:
     _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.IndexingHandler(
         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,
     )
     real_registry._indexing.append(handler)
     return fn
Exemple #7
0
 def decorator(  # lgtm[py/similar-function]
     fn: callbacks.ChangingFn, ) -> callbacks.ChangingFn:
     parent_handler = execution.handler_var.get()
     if not isinstance(parent_handler, handlers.ChangingHandler):
         raise TypeError(
             "Sub-handlers are only supported for resource-changing handlers."
         )
     _warn_incompatible_parent_with_oldnew(parent_handler, old, new)
     _warn_conflicting_values(field, value, old, new)
     _verify_filters(labels, annotations)
     real_registry = subhandling.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.ChangingHandler(
         fn=fn,
         id=real_id,
         param=param,
         errors=errors,
         timeout=timeout,
         retries=retries,
         backoff=backoff,
         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 handler(request, callback, selector):
    handler = WatchingHandler(
        selector=selector,
        annotations={'known': 'value'},
        labels={'known': 'value'},
        field=parse_field('spec.field'),
        value='value',
        when=None,
        fn=some_fn,
        id='a',
        param=None,
        errors=None,
        timeout=None,
        retries=None,
        backoff=None,
    )
    if request.param in ['annotations', 'labels']:
        handler = dataclasses.replace(handler,
                                      **{request.param: {
                                          'known': callback
                                      }})
    else:
        handler = dataclasses.replace(handler, **{request.param: callback})
    return handler
def test_from_none():
    path = parse_field(None)
    assert isinstance(path, tuple)
    assert len(path) == 0
def test_from_others_fails(val):
    with pytest.raises(ValueError):
        parse_field(val)
def test_from_tuple():
    path = parse_field(('field', 'subfield'))
    assert isinstance(path, tuple)
    assert path == ('field', 'subfield')
def test_from_list():
    path = parse_field(['field', 'subfield'])
    assert isinstance(path, tuple)
    assert path == ('field', 'subfield')
def test_from_string_two_levels():
    path = parse_field('field.subfield')
    assert isinstance(path, tuple)
    assert path == ('field', 'subfield')
def test_from_string_one_level():
    path = parse_field('field')
    assert isinstance(path, tuple)
    assert path == ('field', )
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._spawning.get_handlers(cause)
    assert handlers
Exemple #16
0
import datetime
from typing import Collection, Optional

from kopf._cogs.aiokits import aiotime
from kopf._cogs.clients import patching
from kopf._cogs.configs import configuration
from kopf._cogs.helpers import typedefs
from kopf._cogs.structs import bodies, dicts, diffs, patches, references
from kopf._core.actions import loggers

# 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:
Exemple #17
0
def test_catchall_handlers_with_field_ignored(
        cause_no_diff, registry, handler_factory):
    cause = cause_no_diff
    handler_factory(reason=None, field=parse_field('known-field'))
    handlers = registry._changing.get_handlers(cause)
    assert not handlers
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._watching.get_handlers(cause)
    assert not handlers
Exemple #19
0
 def touch_field(self, field: dicts.FieldSpec) -> None:
     real_field = field.format(
         name=self._name) if isinstance(field, str) else field
     self._touch_field = dicts.parse_field(real_field)