kopf: Unexpected trigger and missing object during on.update() and on.field() handlers with callback filters

Question

I am using custom callback filters to try to limit when a handler executes. In some cases of new object creation, I am getting am empty (null) value for the old object.

It is my understanding, from reading the documentation, that on.update() and on.field() handlers should only execute when a change is made to a given resource. Also, if I read correctly, the objects old and new should be present for any update/field handler, and the callback filter should “receive the same keyword arguments as the respective handlers”. In the case of the on.field() below, the field handler not only executes on the creation of an resource, but also seems to execute before the on.create() does.

def is_ccp_config(name, **_):
    """filter on ConfigMap name"""
    if name == 'xxx':
        return True
    return False

@k8s.kopf.on.create(
    'configmap',
    when=is_ccp_config,
    annotations={'ccp/xxx':'true'},
    param='create'
)
@k8s.kopf.on.field(
    'configmap',
    when=is_ccp_config,
    field='metadata.annotations.ccp/xxx',
    new='true',
    param='update-annotations'
)

Also, I really want the on.field() handler to only execute when the value of the annotation changes, but have seen it execute randomly on edits of the other sections of the configMap (separate issue?). To get around that, I tried creating a custom filter callback for this as well, but that’s when I run into the null old issue.

def is_annotation_changed(old, new, **_):
    """helper for change handler filter"""
    old_val = None
    if ('annotations' in old['metadata'].keys() and
        'ccp/xxx' in old['metadata']['annotations'].keys()):
        old_val = old['metadata']['annotations']['ccp/xxx']
    new_val = None
    if ('annotations' in new['metadata'].keys() and
        'ccp/xxx' in new['metadata']['annotations'].keys()):
        new_val = new['metadata']['annotations']['ccp/xxx']
    return not (old_val == new_val)

@k8s.kopf.on.field(
    'configmap',
    when=k8s.kopf.all_([is_ccp_config, is_annotation_changed]),
    field='metadata.annotations.ccp/xxx',
    new='true',
    param='update-annotations'
)

So, in the above code, is it intended that on.field() should be firing when the object is created? My interpretation of the docs says no, but it does. Similarly I have another on.update() trigger that fires when I don’t expect it to, and the old object is also empty.

Checklist

Keywords

handlers filters on.update on.field

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Comments: 37 (37 by maintainers)

Most upvoted comments

FYI, other annotations that the operator does not interfere with appear to be intact.