kopf
kopf copied to clipboard
if child is deletd its not recreated automatically
Expected Behavior
I have created simple operator using kopf and its has children service created which is a clusterip service using adopt. if this service is deleted it should be recreated automatically
Actual Behavior
Child service of operator is not recreated automatically
Steps to Reproduce the Problem
- create operator using this tutorial: https://medium.com/swlh/building-a-kubernetes-operator-in-python-with-zalandos-kopf-37c311d8edff
- delete adopted service
- operator stays but child service gets deleted, either we shouldn't allow to delete or recreate it
Is there way to adopt child in such a way that we can recreate automatically or is there vent handler available
Specifications
- Platform:
- Kubernetes version: (use
kubectl version
) 1.14 - Python version: (use
python --version
) 3.7 - Python packages installed: (use
pip freeze --all
)
You can use Kubernetes finalizers for that.
@kopf.on.create(...)
def create_fn(**_):
svc = {'apiVersion': 'v1', 'metadata': {'name' : name}, 'spec': { 'selector': {'app': 'db'}, 'type': 'NodePort'}}
svc['metadata']['finalizers'] = ['your-domain.com/myoperator-svc-protector']
kopf.adopt(svc, owner=body)
obj = api.create_namespaced_service(namespace, svc)
If at least one finalizer exists on the object, k8s will not delete it, but only mark for deletion (by setting metadata.deletionTimestamp
).
The operator must release its child object from duties somehow, when it decides it is suitable — by removing its own finalizer (but keeping the others if necessary):
@kopf.on.delete(...)
def delete_fn(name, namespace, **_):
obj = api.read_namespaced_service(name, namespace)
finalizers = list(obj.metadata.finalizers)
if finalizers and 'your-domain.com/myoperator-svc-protector' in finalizers:
finalizers.remove('your-domain.com/myoperator-svc-protector')
kopf.adopt(svc, owner=body)
obj = api.patch_namespaced_service(name, namespace, {
'metadata': {'finalizers': finalizers}
})
This operation will read the child Service to get its current list of finalizers, remove its own finalizer, and put the modified list of the finalizers back to the object.
PS: Keep in mind, this patching can be broken with kubernetes==10.0.0
due to kubernetes-client/python#866.
Another way is to indeed add an additional handler — e.g. the spy-handlers.
Please use kopf>=0.19
for this. The apiVersion: v1
objects are supported only in 0.19rc2 & 0.19+.
@kopf.on.create(...)
def create_fn(**_):
svc = {'apiVersion': 'v1', 'metadata': {'name' : name}, 'spec': { 'selector': {'app': 'db'}, 'type': 'NodePort'}}
kopf.adopt(svc, owner=body)
kopf.label(svc, {'my-app': True})
obj = api.create_namespaced_service(namespace, svc)
@kopf.on.event('', 'v1', 'services')
def service_event(meta, name, namespace, event, **_):
# filter out irrelevant services
if not meta.get('labels', {}).get('my-app'):
return
# Now, it is surely our service.
# NB: the old service is already absent at this event, so there will be no HTTP 409 conflict.
if event['type'] == 'DELETED':
_recreate_service(name, namespace)
This will produce extra log messages for all existing services in the namespace/cluster, which looks not nice, but does not create problems. This could be solved soon with decorator-level filtering instead of calling the handler for a single if
statement (see issues).