
"spec":{"$setElementOrder/ports":[{"port":3315}],"ports":[{"nodePort":30005,"port":3315,"protocol":"TCP","targetPort":3321},{"$patch":"delete","port":3310}]}}
PATCH https://61.164.142.194:6443/api/v1/namespaces/default/services/mysql
Have you tried patch_namespaced_service?
Have you tried patch_namespaced_service?
Yes, I have tried, but I do not know what should I set to patch_namespaced_service's body parameter.
I can set service's "target_port" a new value and it works.
but I set service's "port", it do not works!

It's intended behavior. patch_namespaced_service sends strategic-merge-patch (also please refer to this doc) by default, service.spec.ports uses "merge" patchStrategy and "port" as patchMergeKey. Therefore:
service.spec.ports[0].target_port = 3321 sends a patch that contains {"port":3315, "targetPort":3321}-- apiserver sees patchMergeKey is the same as existing ports[0], so ports[0].target_port gets updated. service.spec.ports[0].port = 3309 sends a patch that contains {"port":3309, "targetPort":XXXX(_previous value_)}-- apiserver sees patchMergeKey is different from existing ports[0], so it tries appending ports[1] to the list, but fails validation. You could try enable debugging log but passing debug=True to configuration, to see the HTTP response from apiserver. The request is likely to fail the validation in apiserver:
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Service \"my-service\" is invalid: spec.ports[1].name: Duplicate value: \"tests\"","reason":"Invalid","details":{"name":"my-service","kind":"Service","causes":[{"reason":"FieldValueDuplicate","message":"Duplicate value: \"tests\"","field":"spec.ports[1].name"}]},"code":422}
kubectl edit performs client-side apply (three-way diff) and calculates the needed patch body (the python client library currently doesn't have this functionality):
{"nodePort":30005,"port":3315,"protocol":"TCP","targetPort":3321} appends a ports[1] with same fields except port{"$patch":"delete","port":3310}]} deletes the existing ports[0]The result appears to be spec.ports[0].port getting updated.
It's intended behavior.
patch_namespaced_servicesends strategic-merge-patch (also please refer to this doc) by default,service.spec.portsuses "merge" patchStrategy and "port" as patchMergeKey. Therefore:
service.spec.ports[0].target_port = 3321sends a patch that contains {"port":3315, "targetPort":3321}-- apiserver sees patchMergeKey is the same as existing ports[0], so ports[0].target_port gets updated.service.spec.ports[0].port = 3309sends a patch that contains {"port":3309, "targetPort":XXXX(_previous value_)}-- apiserver sees patchMergeKey is different from existing ports[0], so it tries appending ports[1] to the list, but fails validation.You could try enable debugging log but passing
debug=Trueto configuration, to see the HTTP response from apiserver. The request is likely to fail the validation in apiserver:HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Service \"my-service\" is invalid: spec.ports[1].name: Duplicate value: \"tests\"","reason":"Invalid","details":{"name":"my-service","kind":"Service","causes":[{"reason":"FieldValueDuplicate","message":"Duplicate value: \"tests\"","field":"spec.ports[1].name"}]},"code":422}
kubectl editperforms client-side apply (three-way diff) and calculates the needed patch body (the python client library currently doesn't have this functionality):
{"nodePort":30005,"port":3315,"protocol":"TCP","targetPort":3321}appends a ports[1] with same fields except port{"$patch":"delete","port":3310}]}deletes the existing ports[0]The result appears to be spec.ports[0].port getting updated.
OK, I see your point, thanks very much!
So I wonder how can I make a request by python client to delete the port[0] of service?
Any update on this as how to make a request by python client to delete the port[0] or any spec in service ?
You can use _json-patch_ which is supported by k8s and this library:
api_instance = client.CoreV1Api()
body = [{"op": "replace", "path": "/spec/ports/0/port", "value": 8080}]
api_response = api_instance.patch_namespaced_service("my-service", "my-namespace", body)
More information:
Hey thanks for the response @tomplus
I also found the RFC for this here https://tools.ietf.org/html/rfc6902
And through that found a way to delete specs via json-patch.
patch = [{'op': 'remove', 'path': '/spec/ports/1'}]
client.patch_namespaced_service(name=self._component_info.get('name'),
namespace=self._component_info.get('namespace'),
body=patch)
Most helpful comment
You can use _json-patch_ which is supported by k8s and this library:
More information: