-
-
Notifications
You must be signed in to change notification settings - Fork 166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optionally remove Status handler_id prefix. #579
Changes from all commits
373f983
21b6c60
78f4c84
c24a472
2a57e9c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ Kopf: Kubernetes Operators Framework | |
results | ||
errors | ||
scopes | ||
status | ||
|
||
.. toctree:: | ||
:maxdepth: 2 | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,59 @@ | ||||||
======= | ||||||
Updating Status | ||||||
======= | ||||||
|
||||||
Kopf will take the return value of all state-changing handlers (even | ||||||
sub-handlers) and add them to the ``Status`` of the corresponding Kuberenetes | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
resource. By default, this is stored under the handler id which by default is | ||||||
the function name. | ||||||
|
||||||
.. note:: | ||||||
|
||||||
The ``CustomResourceDefinition`` requires that the fields that will be set in | ||||||
status have a corresponding schema. | ||||||
|
||||||
You could also use ``x-kubernetes-preserve-unknown-fields: true``:: | ||||||
|
||||||
schema: | ||||||
openAPIV3Schema: | ||||||
type: object | ||||||
properties: | ||||||
status: | ||||||
type: object | ||||||
x-kubernetes-preserve-unknown-fields: true | ||||||
spec: | ||||||
... | ||||||
|
||||||
Given the following handler definition:: | ||||||
|
||||||
import kopf | ||||||
|
||||||
@kopf.on.create('zalando.org', 'v1', 'kopfexamples') | ||||||
def my_handler(spec, **_): | ||||||
return {'field': 'value} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please wrap all code blocks here (before and after this comment) to their specific language highlights? This is one of the following instead of
I'm highly uncertain if there is any kind of automatic language detection in SphinxDocs. |
||||||
|
||||||
The resulting object will have the following data:: | ||||||
|
||||||
spec: | ||||||
... | ||||||
status: | ||||||
my_handler: | ||||||
field: value | ||||||
|
||||||
In order to remove the handler ID from the result, you may set the optional | ||||||
``status_prefix=False`` when defining the handler. | ||||||
|
||||||
So with the handler definition:: | ||||||
|
||||||
import kopf | ||||||
|
||||||
@kopf.on.create('zalando.org', 'v1', 'kopfexamples', status_prefix=False) | ||||||
def my_handler(spec, **_): | ||||||
return {'field': 'value} | ||||||
|
||||||
The resulting object will have the following data:: | ||||||
|
||||||
spec: | ||||||
... | ||||||
status: | ||||||
field: value | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important: What will happen with |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,6 +145,7 @@ def resume( # lgtm[py/similar-function] | |
labels: Optional[filters.MetaFilter] = None, | ||
annotations: Optional[filters.MetaFilter] = None, | ||
when: Optional[callbacks.WhenFilterFn] = None, | ||
status_prefix: bool = True, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important: Generally, as a rule of thumb, all handler options are designed so that the default value is Can you please negate the option and its meaning? (I am not sure what would be the better wording to describe this: flat status? direct status? raw status? result_to_status? something else?) |
||
) -> ResourceChangingDecorator: | ||
""" ``@kopf.on.resume()`` handler for the object resuming on operator (re)start. """ | ||
def decorator( # lgtm[py/similar-function] | ||
|
@@ -161,6 +162,7 @@ def decorator( # lgtm[py/similar-function] | |
labels=labels, annotations=annotations, when=when, | ||
initial=True, deleted=deleted, requires_finalizer=None, | ||
reason=None, | ||
status_prefix=status_prefix, | ||
) | ||
real_registry.resource_changing_handlers[real_resource].append(handler) | ||
return fn | ||
|
@@ -180,6 +182,7 @@ def create( # lgtm[py/similar-function] | |
labels: Optional[filters.MetaFilter] = None, | ||
annotations: Optional[filters.MetaFilter] = None, | ||
when: Optional[callbacks.WhenFilterFn] = None, | ||
status_prefix: bool = True, | ||
) -> ResourceChangingDecorator: | ||
""" ``@kopf.on.create()`` handler for the object creation. """ | ||
def decorator( # lgtm[py/similar-function] | ||
|
@@ -196,6 +199,7 @@ def decorator( # lgtm[py/similar-function] | |
labels=labels, annotations=annotations, when=when, | ||
initial=None, deleted=None, requires_finalizer=None, | ||
reason=handlers.Reason.CREATE, | ||
status_prefix=status_prefix, | ||
) | ||
real_registry.resource_changing_handlers[real_resource].append(handler) | ||
return fn | ||
|
@@ -215,6 +219,7 @@ def update( # lgtm[py/similar-function] | |
labels: Optional[filters.MetaFilter] = None, | ||
annotations: Optional[filters.MetaFilter] = None, | ||
when: Optional[callbacks.WhenFilterFn] = None, | ||
status_prefix: bool = True, | ||
) -> ResourceChangingDecorator: | ||
""" ``@kopf.on.update()`` handler for the object update or change. """ | ||
def decorator( # lgtm[py/similar-function] | ||
|
@@ -231,6 +236,7 @@ def decorator( # lgtm[py/similar-function] | |
labels=labels, annotations=annotations, when=when, | ||
initial=None, deleted=None, requires_finalizer=None, | ||
reason=handlers.Reason.UPDATE, | ||
status_prefix=status_prefix, | ||
) | ||
real_registry.resource_changing_handlers[real_resource].append(handler) | ||
return fn | ||
|
@@ -251,6 +257,7 @@ def delete( # lgtm[py/similar-function] | |
labels: Optional[filters.MetaFilter] = None, | ||
annotations: Optional[filters.MetaFilter] = None, | ||
when: Optional[callbacks.WhenFilterFn] = None, | ||
status_prefix: bool = True, | ||
) -> ResourceChangingDecorator: | ||
""" ``@kopf.on.delete()`` handler for the object deletion. """ | ||
def decorator( # lgtm[py/similar-function] | ||
|
@@ -267,6 +274,7 @@ def decorator( # lgtm[py/similar-function] | |
labels=labels, annotations=annotations, when=when, | ||
initial=None, deleted=None, requires_finalizer=bool(not optional), | ||
reason=handlers.Reason.DELETE, | ||
status_prefix=status_prefix, | ||
) | ||
real_registry.resource_changing_handlers[real_resource].append(handler) | ||
return fn | ||
|
@@ -287,6 +295,7 @@ def field( # lgtm[py/similar-function] | |
labels: Optional[filters.MetaFilter] = None, | ||
annotations: Optional[filters.MetaFilter] = None, | ||
when: Optional[callbacks.WhenFilterFn] = None, | ||
status_prefix: bool = True, | ||
) -> ResourceChangingDecorator: | ||
""" ``@kopf.on.field()`` handler for the individual field changes. """ | ||
def decorator( # lgtm[py/similar-function] | ||
|
@@ -304,6 +313,7 @@ def decorator( # lgtm[py/similar-function] | |
labels=labels, annotations=annotations, when=when, | ||
initial=None, deleted=None, requires_finalizer=None, | ||
reason=None, | ||
status_prefix=status_prefix, | ||
) | ||
real_registry.resource_changing_handlers[real_resource].append(handler) | ||
return fn | ||
|
@@ -318,6 +328,7 @@ def event( # lgtm[py/similar-function] | |
labels: Optional[filters.MetaFilter] = None, | ||
annotations: Optional[filters.MetaFilter] = None, | ||
when: Optional[callbacks.WhenFilterFn] = None, | ||
status_prefix: bool = True, | ||
) -> ResourceWatchingDecorator: | ||
""" ``@kopf.on.event()`` handler for the silent spies on the events. """ | ||
def decorator( # lgtm[py/similar-function] | ||
|
@@ -396,6 +407,7 @@ def timer( # lgtm[py/similar-function] | |
sharp: Optional[bool] = None, | ||
idle: Optional[float] = None, | ||
interval: Optional[float] = None, | ||
status_prefix: bool = True, | ||
) -> ResourceTimerDecorator: | ||
""" ``@kopf.timer()`` handler for the regular events. """ | ||
def decorator( # lgtm[py/similar-function] | ||
|
@@ -432,6 +444,7 @@ def this( # lgtm[py/similar-function] | |
labels: Optional[filters.MetaFilter] = None, | ||
annotations: Optional[filters.MetaFilter] = None, | ||
when: Optional[callbacks.WhenFilterFn] = None, | ||
status_prefix: Optional[bool] = None, | ||
) -> ResourceChangingDecorator: | ||
""" | ||
``@kopf.on.this()`` decorator for the dynamically generated sub-handlers. | ||
|
@@ -471,12 +484,14 @@ def decorator( # lgtm[py/similar-function] | |
real_registry = registry if registry is not None else handling.subregistry_var.get() | ||
real_id = registries.generate_id(fn=fn, id=id, | ||
prefix=parent_handler.id if parent_handler else None) | ||
handler_status_prefix = status_prefix if status_prefix is not None else parent_handler.status_prefix if parent_handler else True | ||
handler = handlers.ResourceChangingHandler( | ||
fn=fn, id=real_id, field=None, | ||
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, | ||
status_prefix=handler_status_prefix, | ||
) | ||
real_registry.append(handler) | ||
return fn | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ class HandlerOutcome: | |
possibly after few executions, and consisting of simple data types | ||
(for YAML/JSON serialisation) rather than the actual in-memory objects. | ||
""" | ||
handler: handlers_.BaseHandler | ||
final: bool | ||
delay: Optional[float] = None | ||
result: Optional[callbacks.Result] = None | ||
|
@@ -304,9 +305,16 @@ def deliver_results( | |
pass | ||
elif isinstance(outcome.result, collections.abc.Mapping): | ||
# TODO: merge recursively (patch-merge), do not overwrite the keys if they are present. | ||
patch.setdefault('status', {}).setdefault(handler_id, {}).update(outcome.result) | ||
if hasattr(outcome.handler, 'status_prefix') and not outcome.handler.status_prefix: | ||
base = patch.setdefault('status', {}) | ||
else: | ||
base = patch.setdefault('status', {}).setdefault(handler_id, {}) | ||
base.update(outcome.result) | ||
else: | ||
patch.setdefault('status', {})[handler_id] = copy.deepcopy(outcome.result) | ||
if hasattr(outcome.handler, 'status_prefix') and not outcome.handler.status_prefix: | ||
patch.setdefault('status', {})[copy.deepcopy(outcome.result)] = {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important: I'm quite not sure what does this line mean. Can you please clarify the intentions? It looks like the result is used as the key, not as the value. |
||
else: | ||
patch.setdefault('status', {})[handler_id] = copy.deepcopy(outcome.result) | ||
|
||
|
||
@overload | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.