Skip to content

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

Closed

Description

@SailorCrane

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

Activity

  1. tomplus commented on Oct 9, 2018

    @tomplus
    Member

    Have you tried patch_namespaced_service?

  2. SailorCrane commented on Oct 10, 2018

    @SailorCrane
    Author

    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

  3. roycaihw commented on Oct 12, 2018

    @roycaihw
    Member

    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.

  4. SailorCrane commented on Oct 24, 2018

    @SailorCrane
    Author

    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?

  5. sanster23 commented on Feb 28, 2019

    @sanster23

    Any update on this as how to make a request by python client to delete the port[0] or any spec in service ?

  6. tomplus commented on Feb 28, 2019

    @tomplus
    Member

    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:

  7. sanster23 commented on Mar 1, 2019

    @sanster23

    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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions