Repository: kubernetes-client/python

Issue:
Version 32.0.0 gke-gcloud-auth-plugin configuration break
**What happened (please include outputs or screenshots)**:

Attempting to run a simple test program to merely load configuration breaks with a json.dumps TypeError error when using a configuration file similar to those generated by executing the `gcloud container clusters get-credentials <cluster> --region <region> --project <gcp_project>` command with the `gke-gcloud-auth-plugin` authentication helper installed:
```
$ cat test.py
from kubernetes import client, config
config.load_kube_config()
$ KUBECONFIG=config python test.py
ERROR:root:Object of type ConfigNode is not JSON serializable
```

**What you expected to happen**:

Empty output (provided a valid non-example configuration is provided and one has the gcloud auth plugin installed).

**How to reproduce it (as minimally and precisely as possible)**:

Create a test Kubernetes configuration file as follows as a file called `config`:
```
apiVersion: v1
kind: Config
preferences: {}
contexts:
- context:
    cluster: test-cluster
    user: test-user
  name: test
clusters:
- cluster:
    certificate-authority-data: bm90X2FfcmVhbF9jZXJ0Cg==
    server: https://w.x.y.z
  name: test-cluster
users:
- name: test-user
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      command: gke-gcloud-auth-plugin
      installHint: Install gke-gcloud-auth-plugin for use with kubectl by following
        https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl#install_plugin
      provideClusterInfo: true
current-context: test
```

Create a `test.py` script as follows:
```
from kubernetes import client, config
config.load_kube_config()
```

Ensure kubernetes 32.0.0 is installed (31.0.0 works for me):
```
pip install kubernetes==32.0.0
```

Execute the script, specifying the `KUBECONFIG` environment variable to override the default location to your test file:
```
KUBECONFIG=config python test.py
```

You should receive the following error message from the default logger due to the error being caught and logged without a stacktrace:
```
ERROR:root:Object of type ConfigNode is not JSON serializable
```

**Anything else we need to know?**:

This is likely due to the call here passing in a `kubernetes_exec_info` structure containing a ConfigNode instance rather than serializable Python native types:
https://github.com/kubernetes-client/python/blob/v32.0.0/kubernetes/base/config/exec_provider.py#L76

I haven't looked extensively into what could have changed between versions, but version 31.0.0 appears to work; FWIW here's the requirements.txt for a more-involved test project where version 31.0.0 appears to function with the test file; swapping kubernetes==32.0.0 in breaks it:
```
toml==0.10.2
typer==0.15.1
google-cloud-logging==3.11.3
kubernetes==31.0.0
```

I'm also using pyenv with a virtualenv whereas the `gke-gcloud-auth-plugin` binary likely uses the system python installation; this shouldn't matter as it's invoked in a subprocess, just as relative versus absolute path in the kube config for it likewise doesn't make a difference. You shouldn't need to even install it to reproduce, as it fails prior to the subprocess call AFAICT; that said, I haven't tried it on a totally 100% clean system without it installed.

**Environment**:
- Kubernetes version (`kubectl version`):
```
Client Version: v1.31.2
Kustomize Version: v5.4.2
Server Version: v1.31.4-gke.1256000
```

- OS:
Mac OSX 12.6.1

- Python version (`python --version`)
```
Python 3.9.20
```

- Python client version (`pip list | grep kubernetes`)
```
kubernetes                     32.0.0
```


Discussion:
I am seeing the same issue after upgrading to `kubernetes==32.0.0`. Downgrading to `kubernetes==31.0.0` fixes the issue
Confirming both the problem described by the OP, as well as the solution of freezing version to kubernetes==31.0.0
Can also confirm that version 32.0.0 breaks local auth. 

```2025-01-27 18:21:27 - cluster.py - __init__ - INFO - Loading kubeconfig.
ERROR:root:exec: failed to decode process output: Expecting value: line 1 column 1 (char 0)
```

Downgrading to 31.0.0 fixes this. 
Same here 32.0.0 breaks local auth but works in cluster auth

`ERROR:root:exec: failed to decode process output: Expecting value: line 1 column 1 (char 0)`

31.0.0 works as well
It appears that the issue is related to this line in the 
`ExecProvider` class in `/kubernetes/config/exec_provider.py`:
```
       if self.cluster:
            kubernetes_exec_info['spec']['cluster'] = self.cluster
        self.env['KUBERNETES_EXEC_INFO'] = json.dumps(kubernetes_exec_info)
```

`self.cluster` appears to be type `ConfigNode` which does not have a `toJSON` serializer.

Alternatively, `ConfigNode` could inherit from `dict`, which seems to work.
In OCI-OKE also giving the same error when we use kubernetes-32.0.0.

```
import kubernetes
from kubernetes import client, config
print(f"module version: {kubernetes.__version__}")
config.load_kube_config(config_file="exported_kube.config")
```

>**module version: 32.0.0**
>**ERROR:root:exec: failed to decode process output: Expecting value: line 1 column 1 (char 0)**

This is also broken for Digital Ocean and kubeconfig generated by `doctl`. Reverting back to 31.0.0 works.



Patch:
diff --git a/kubernetes/base/config/exec_provider.py b/kubernetes/base/config/exec_provider.py
index 317a566955..03dc0386ef 100644
--- a/kubernetes/base/config/exec_provider.py
+++ b/kubernetes/base/config/exec_provider.py
@@ -71,7 +71,7 @@ def run(self, previous_response=None):
         if previous_response:
             kubernetes_exec_info['spec']['response'] = previous_response
         if self.cluster:
-            kubernetes_exec_info['spec']['cluster'] = self.cluster
+            kubernetes_exec_info['spec']['cluster'] = self.cluster.value
 
         self.env['KUBERNETES_EXEC_INFO'] = json.dumps(kubernetes_exec_info)
         process = subprocess.Popen(


Test patch:
diff --git a/kubernetes/base/config/exec_provider_test.py b/kubernetes/base/config/exec_provider_test.py
index 9ff62d12e2..fc4944b229 100644
--- a/kubernetes/base/config/exec_provider_test.py
+++ b/kubernetes/base/config/exec_provider_test.py
@@ -175,7 +175,7 @@ def test_with_cluster_info(self, mock):
         instance = mock.return_value
         instance.wait.return_value = 0
         instance.communicate.return_value = (self.output_ok, '')
-        ep = ExecProvider(self.input_with_cluster, None, {'server': 'name.company.com'})
+        ep = ExecProvider(self.input_with_cluster, None, ConfigNode("cluster", {'server': 'name.company.com'}))
         result = ep.run()
         self.assertTrue(isinstance(result, dict))
         self.assertTrue('token' in result)