-
-
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
Field filters for all resource handlers #573
Conversation
This pull request introduces 1 alert when merging 2137366 into 8023ea4 - view on LGTM.com new alerts:
|
This pull request introduces 1 alert when merging af33857 into 8023ea4 - view on LGTM.com new alerts:
|
b8862ec
to
cdde2ee
Compare
Documentation preview: https://kopf.readthedocs.io/en/field-filters/filters/ |
Matching is used for strict handler matching when selecting the handlers for invocation. Pre-matching is an optimisation measure — it is used in the early stage of processing to check if it is worth continuing to more heavy computations down the stack. For example, to check if a finalizer should be added/removed. Some computation-heavy and very variable criteria —essentially, the diffs-matching ones— are excluded from pre-matching, leaving it only to the stable body-matching criteria only.
Tested manually. The field-filters work as expected, it seems. Even for sub-handlers with this setup (impractical, but possible): import kopf
@kopf.on.create('zalando.org', 'v1', 'kopfexamples')
async def created_with_field(**kwargs):
print(f'CREATED')
for i in range(3):
@kopf.on.this(field='spec.field', value='value', id=f'a{i}')
def a_sub(new, i=i, **kwargs):
print(f'A-SUB {i} with field: {new}')
@kopf.on.this(field='spec.field', value=kopf.PRESENT, id=f'b{i}')
def b_sub(new, i=i, **kwargs):
print(f'B-SUB {i} with field: {new}')
@kopf.on.update('zalando.org', 'v1', 'kopfexamples')
async def update_with_field(**kwargs):
print(f'UPDATED')
for i in range(3):
@kopf.on.this(field='spec.field', old=i-1, new=i, id=f'c{i}')
def c_sub(new, i=i, **kwargs):
print(f'C-SUB {i} with field: {new}') And then doing: kubectl apply -f examples/obj.yaml
kubectl patch -f examples/obj.yaml --type merge -p '{"spec": {"field": -1}}'
kubectl patch -f examples/obj.yaml --type merge -p '{"spec": {"field": 0}}'
kubectl patch -f examples/obj.yaml --type merge -p '{"spec": {"field": 1}}'
kubectl patch -f examples/obj.yaml --type merge -p '{"spec": {"field": 2}}'
kubectl patch -f examples/obj.yaml --type merge -p '{"spec": {"field": 0}}' # no reaction |
Implement field & value filters for all resource-changing handlers:
@kopf.on.resume/create/update/delete
.It was a long-needed feature to replace field handlers (
@kopf.on.field
) with more clear, explicit, and less ambiguous syntax. It was drafted in Jan'2020, but didn't get into the main codebase due to some semantical complications. Over the past year, the complications were resolved, so it seems easy to implement this feature now.If
field=
is set on any handler, the handler is triggered only if the field is present in the object, andold
/new
/diff
kwargs are reduced to that field instead of the whole body; the usuallybody
& co kwargs still point to the full body, as expected.As with other filters (labels, annotations), either specific values are accepted and checked for equality, or
kopf.ABSENT
/kopf.PRESENT
markers are accepted, or callbacks that accept a positional value and all typical kwargs, and return a boolean for whether it matches or not.The default behaviour depends on what kind of a filter/handler it is:
For single-value filters (creation/resuming/deletion handlers), by default (i.e.
value=None
), the field must be present, and it is equivalent tovalue=kopf.PRESENT
:For the update & on-field handlers, additional criteria can be used:
old
&new
. By default, it is only triggered if the value is changed (including the case when it is changed from anything toNone
— i.e. the field is removed):Using both
value=
&old=/new=
is prohibited, as it is confusing. It is either-either. Essentially,new
is the same asvalue
.Some unusual tricks are now possible — as side-effects, not as the main goal of this change:
Trigger a handler only if the required field is NOT defined — the opposite of the default behaviour. The value of
new
will beNone
:@kopf.on.field
handler are now discouraged — but not yet deprecated. They will most likely remain for some long time for backward compatibility. A field handler like this:Is equivalent to this:
Note: but not for deletion & resuming, as nothing changes in those occasions, and on-field is only triggered when something is changed.
The field-value (but not old/new) filtering logic can also be applied to all other resource handlers:
Their semantics is the same as the labels/annotations/callback filtering: the handler is invoked and the daemon is running as long as the criterion is satisfied. Once the resource changes so that it does not satisfy the criterion, the handlers are not invoked, and the daemon is stopped.
Remaining TODOs:
Related: #571 #566