Python: How can I make request like this by k8s python client, the below request is made by "kubectl edit", and it works!

Created on 9 Oct 2018  路  7Comments  路  Source: kubernetes-client/python

selection_007

"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

Most helpful comment

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:

All 7 comments

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!

selection_014

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_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.

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)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

djamaile picture djamaile  路  3Comments

codefetcher picture codefetcher  路  4Comments

Invictus17 picture Invictus17  路  5Comments

tdigangi picture tdigangi  路  4Comments

plee138 picture plee138  路  5Comments