kopf
kopf copied to clipboard
Watch for changes in array items.
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