3

I'm trying to patch a kube node using the Python kubernetes-client library.

Specifically, I'm trying to cordon the node. Using kubectl, I'm able to do it successfully:

kubectl patch node mynode -json --patch={"op":"replace", "path":"/spec/unschedulable", "value":true}`

But using the python kubernetes-client library fails:

from kubernetes import client, config

config.load_kube_config()
body='{"op":"replace", "path":"/spec/unschedulable", "value":true}'
# also have tried body='[{"op":"replace", "path":"/spec/unschedulable", "value":true}]'
v1=client.CoreV1Api()
ret=v1.patch_node(name="mynode", body=body)
print (ret)

The return contains the message:

"json: cannot unmarshal object into Go value of type jsonpatch.Patch"

Some research led me to this bug. It refers to using the kubernetes api directly, but the issue appears to be the same. Unfortunately, the solution - passing an array - doesn't help.

Unfortunately, the documentation doesn't help, here. The required type for body is shown as UNKNOWN_BASE_TYPE, which is not useful. I've looked at the code, but there's no clue there as to how I should be formatting the body - I'm at a loss.

SiHa
  • 7,830
  • 13
  • 34
  • 43

2 Answers2

4

So, it turns out that json.loads() is the answer, and upper casing the bool, so that loads() works. Also, although a non-array body does not raise an error, neither does it actually make the desired change, so an array is required:

from kubernetes import client, config
import json

config.load_kube_config()
v1=client.CoreV1Api()

body='[{"op": "add", "path": "/spec/unschedulable", "value": True}]'
print(json.loads(body)) #Debug
ret=v1.patch_node(name="mynode", body=json.loads(body))
print (ret)

It's worth pointing out that the resulting body has the bool capitalised, whereas for the kubectl command-line operation it must be lower-case.

Also, oddly, if I replace:
body=json.loads(body)
with
body="[{'op': 'add', 'path': '/spec/unschedulable', 'value': False}]"

Which is the output of the earlier print statement, it fails in the original manner.

SiHa
  • 7,830
  • 13
  • 34
  • 43
2

This can be also implemented that way

from kubernetes import client, config
config.load_incluster_config()
body = {
    "spec": {
        "unschedulable": True
    }
}
api_response = client.CoreV1Api().patch_node("NODE_NAME", body)
print(api_response)

This way is in case you load the config internally in the cluster. If you want to run from outside of the cluster, the config can be load like that

config_file = open(os.path.dirname(os.path.dirname(__file__)) + "config.yaml", 'r')    
config.load_kube_config(config_file)
Ofir Nagadi
  • 181
  • 1
  • 5