Пример #1
0
 def __init__(self, *, body: bodies.Body):
     super().__init__(
         logger,
         dict(
             k8s_skip=False,
             k8s_ref=dict(
                 apiVersion=body.get('apiVersion'),
                 kind=body.get('kind'),
                 name=body.get('metadata', {}).get('name'),
                 uid=body.get('metadata', {}).get('uid'),
                 namespace=body.get('metadata', {}).get('namespace'),
             ),
         ))
Пример #2
0
 def __init__(self, *, body: bodies.Body,
              settings: configuration.OperatorSettings) -> None:
     super().__init__(
         logger,
         dict(
             settings=settings,
             k8s_skip=False,
             k8s_ref=dict(
                 apiVersion=body.get('apiVersion'),
                 kind=body.get('kind'),
                 name=body.get('metadata', {}).get('name'),
                 uid=body.get('metadata', {}).get('uid'),
                 namespace=body.get('metadata', {}).get('namespace'),
             ),
         ))
Пример #3
0
def _matches_annotations(
        handler: ResourceHandler,
        body: bodies.Body,
) -> bool:
    return (not handler.annotations or
            _matches_metadata(pattern=handler.annotations,
                              content=body.get('metadata', {}).get('annotations', {})))
Пример #4
0
def get_retry_count(
    *,
    body: bodies.Body,
    handler: registries.ResourceHandler,
) -> int:
    progress = body.get('status', {}).get('kopf', {}).get('progress', {})
    return progress.get(handler.id, {}).get('retries', None) or 0
Пример #5
0
def is_started(
    *,
    body: bodies.Body,
    handler: registries.ResourceHandler,
) -> bool:
    progress = body.get('status', {}).get('kopf', {}).get('progress', {})
    return handler.id in progress
Пример #6
0
 def mark_key(self, key: str, *, body: bodies.Body) -> str:
     owners = body.meta.get('ownerReferences', [])
     kind = body.get('kind')
     if kind == 'ReplicaSet' and any(owner['kind'] == 'Deployment' for owner in owners):
         return f"{key}-ofDRS"  # no need to generalise for a single known case
     else:
         return key
Пример #7
0
def _matches_labels(
        handler: ResourceHandler,
        body: bodies.Body,
) -> bool:
    return (not handler.labels or
            _matches_metadata(pattern=handler.labels,
                              content=body.get('metadata', {}).get('labels', {})))
Пример #8
0
def get_awake_time(
    *,
    body: bodies.Body,
    handler: registries.ResourceHandler,
) -> Optional[datetime.datetime]:
    progress = body.get('status', {}).get('kopf', {}).get('progress', {})
    value = progress.get(handler.id, {}).get('delayed', None)
    return None if value is None else datetime.datetime.fromisoformat(value)
Пример #9
0
def is_finished(
    *,
    body: bodies.Body,
    handler: registries.ResourceHandler,
) -> bool:
    progress = body.get('status', {}).get('kopf', {}).get('progress', {})
    success = progress.get(handler.id, {}).get('success', None)
    failure = progress.get(handler.id, {}).get('failure', None)
    return bool(success or failure)
Пример #10
0
def append_finalizers(
    *,
    body: bodies.Body,
    patch: patches.Patch,
) -> None:
    if not has_finalizers(body=body):
        finalizers = body.get('metadata', {}).get('finalizers', [])
        patch.setdefault('metadata', {}).setdefault('finalizers',
                                                    list(finalizers))
        patch['metadata']['finalizers'].append(FINALIZER)
Пример #11
0
def block_deletion(
    *,
    body: bodies.Body,
    patch: patches.Patch,
) -> None:
    if not is_deletion_blocked(body=body):
        finalizers = body.get('metadata', {}).get('finalizers', [])
        patch.setdefault('metadata', {}).setdefault('finalizers',
                                                    list(finalizers))
        patch['metadata']['finalizers'].append(FINALIZER)
Пример #12
0
def get_start_time(
    *,
    body: bodies.Body,
    patch: patches.Patch,
    handler: registries.ResourceHandler,
) -> Optional[datetime.datetime]:
    progress = patch.get('status', {}).get('kopf', {}).get('progress', {})
    new_value = progress.get(handler.id, {}).get('started', None)
    progress = body.get('status', {}).get('kopf', {}).get('progress', {})
    old_value = progress.get(handler.id, {}).get('started', None)
    value = new_value or old_value
    return None if value is None else datetime.datetime.fromisoformat(value)
Пример #13
0
    def purge(self, patch: patches.Patch, body: bodies.Body) -> None:
        if 'progress' in body.get('status', {}).get('kopf', {}):
            patch_storage = patch.setdefault('status', {}).setdefault('kopf', {})
            patch_storage['progress'] = None
        elif 'progress' in patch.get('status', {}).get('kopf', {}):
            del patch['status']['kopf']['progress']

        # Avoid storing the empty status dicts (but do so if they have any content).
        if 'status' in patch and 'kopf' in patch['status'] and not patch['status']['kopf']:
            del patch['status']['kopf']
        if 'status' in patch and not patch['status']:
            del patch['status']
Пример #14
0
def allow_deletion(
    *,
    body: bodies.Body,
    patch: patches.Patch,
    finalizer: str,
) -> None:
    if is_deletion_blocked(body=body, finalizer=finalizer):
        finalizers = body.get('metadata', {}).get('finalizers', [])
        patch.setdefault('metadata', {}).setdefault('finalizers',
                                                    list(finalizers))
        if finalizer in patch['metadata']['finalizers']:
            patch['metadata']['finalizers'].remove(finalizer)
Пример #15
0
def remove_finalizers(
    *,
    body: bodies.Body,
    patch: patches.Patch,
) -> None:
    if has_finalizers(body=body):
        finalizers = body.get('metadata', {}).get('finalizers', [])
        patch.setdefault('metadata', {}).setdefault('finalizers',
                                                    list(finalizers))
        if LEGACY_FINALIZER in patch['metadata']['finalizers']:
            patch['metadata']['finalizers'].remove(LEGACY_FINALIZER)
        if FINALIZER in patch['metadata']['finalizers']:
            patch['metadata']['finalizers'].remove(FINALIZER)
Пример #16
0
def allow_deletion(
    *,
    body: bodies.Body,
    patch: patches.Patch,
) -> None:
    if is_deletion_blocked(body=body):
        finalizers = body.get('metadata', {}).get('finalizers', [])
        patch.setdefault('metadata', {}).setdefault('finalizers',
                                                    list(finalizers))
        if LEGACY_FINALIZER in patch['metadata']['finalizers']:
            patch['metadata']['finalizers'].remove(LEGACY_FINALIZER)
        if FINALIZER in patch['metadata']['finalizers']:
            patch['metadata']['finalizers'].remove(FINALIZER)
Пример #17
0
    def _build_key(
            self,
            body: bodies.Body,
    ) -> str:
        """
        Construct an immutable persistent key of a resource.

        Generally, a uid is sufficient, as it is unique within the cluster.
        But it can be e.g. plural/namespace/name triplet, or anything else,
        even of different types (as long as it satisfies the type checkers).

        But it must be consistent within a single process lifetime.
        """
        return body.get('metadata', {}).get('uid') or ''
Пример #18
0
 def from_body(
         cls,
         body: bodies.Body,
         *,
         handlers: Collection[handlers_.BaseHandler],
 ) -> "State":
     storage = body.get('status', {}).get('kopf', {})
     progress = storage.get('progress', {})
     content = {}
     content.update({
         handler.id: (HandlerState.from_scratch() if handler.id not in progress else
                      HandlerState.from_dict(progress[handler.id]))
         for handler in handlers
     })
     return cls(content)
Пример #19
0
    def make_key(self, body: bodies.Body) -> Key:
        """
        Make a key to address an object in internal containers.

        The key is not exposed to the users via indices,
        so its structure and type can be safely changed any time.

        However, the key must be as lightweight as possible:
        no dataclasses or namedtuples, only builtins.

        The name and namespace do not add value on top of the uid's uniqueness.
        They are here for debugging and for those rare objects
        that have no uid but are still exposed via the K8s API
        (highly unlikely to be indexed though).
        """
        meta = body.get('metadata', {})
        return (meta.get('namespace'), meta.get('name'), meta.get('uid'))
Пример #20
0
def has_finalizers(body: bodies.Body, ) -> bool:
    finalizers = body.get('metadata', {}).get('finalizers', [])
    return FINALIZER in finalizers or LEGACY_FINALIZER in finalizers
Пример #21
0
def is_deletion_blocked(
    body: bodies.Body,
    finalizer: str,
) -> bool:
    finalizers = body.get('metadata', {}).get('finalizers', [])
    return finalizer in finalizers
Пример #22
0
def is_deletion_blocked(body: bodies.Body, ) -> bool:
    finalizers = body.get('metadata', {}).get('finalizers', [])
    return FINALIZER in finalizers or LEGACY_FINALIZER in finalizers
Пример #23
0
def is_deletion_ongoing(body: bodies.Body, ) -> bool:
    return body.get('metadata', {}).get('deletionTimestamp', None) is not None
Пример #24
0
def has_essence_stored(body: bodies.Body, ) -> bool:
    annotations = body.get('metadata', {}).get('annotations', {})
    return LAST_SEEN_ANNOTATION in annotations