kopf icon indicating copy to clipboard operation
kopf copied to clipboard

Watch for changes in array items.

Open MarkusH opened this issue 4 years ago • 0 comments

Thank you for the great library. It's a pleasure to work with.

Problem

I have a custom resource with an array of objects somewhere in the spec. Say, like this:

spec:
  a:
    b:
    - foo: lorem
      nested:
        bar: ipsum
    - foo: dolor
      nested:
        bar: sit

I would like to be able to use @kopf.on.update to watch on individual changes of fields within array items and have these changes automatically in the diff argument of the handler.

The case at hand: I use kopf to build an operator that will create multiple StatefulSets where some specs for the StatefulSets are defined in the custom resource, such as the number of replicas:

spec:
  types:
  - name: type-a
    replicas: 2
  - name: type-b
    replicas: 4

The feature would allow me to neatly detect when the replicas for type-a are changed to e.g. 3.

Proposal

I see a few different implementation options. I'll demonstrate them here:

@kopf.on.update(...)
async def replicas_change(diff, **_):
    print(diff)
    # [("change", ("spec", "types", "0", "replicas"), 2, 3)]

Alternatively, one could want to watch for changes to the n-th array item in @kopf.on.field:

@kopf.on.field(..., field="spec.types.0.replicas")
async def type_b_change(diff, **_):
    print(diff)
    # [("change", (), 2, 3)]

Or watch for each array element and get its index.

@kopf.on.field(..., field="spec.types[]")
async def type_b_change(diff, **_):
    print(diff)
    # [("change", ("0"), {"name": "type-a", "replicas": 2}, {"name": "type-a", "replicas": 3})]

An interesting question in the last context would be how adding / removing items is going to be handled. E.g., what would the diff look like if one were to add a type-c as first item in the array and remove the type-b:

    [
        ("add", ("0"), None, {"name": "type-c", "replicas": 5}),
        ("remove", ("1"), {"name": "type-b", "replicas": 4}, None),
    ]
    # or
    [
        ("add", ("0"), None, {"name": "type-c", "replicas": 5}),
        ("remove", ("2"), {"name": "type-b", "replicas": 4}, None),
    ]
    # or
    [
        ("change", ("0"), {"name": "type-a", "replicas": 2}, {"name": "type-c", "replicas": 5}),
        ("change", ("2"), {"name": "type-b", "replicas": 4}, {"name": "type-a", "replicas": 2}),
    ]
    # or ...?

Checklist

  • [x] Many users can benefit from this feature, it is not a one-time case
  • [x] The proposal is related to the K8s operator framework, not to the K8s client libraries

MarkusH avatar Jun 11 '20 08:06 MarkusH