# Kubernetes Python Client in Minikube
Suppose the goal is to delegate some tasks from a pod to another pod using HTTP requests, then it's necessary to know to IP of each pod. [Kubernetes Python Client](https://github.com/kubernetes-client/python) can do the job.
---
###### tags: `Kubernetes` `Python`
---
## Pip Install
For testing purposes, it is convenient to use shell in the running container.
```
root@api-minikube-7f4b5d6dd6-56z8s:/app# which python
/app/venv/bin/python
root@api-minikube-7f4b5d6dd6-56z8s:/app# pip install kubernetes
```
## Try It Out
After installing successfully, open python shell in the container.
```
root@api-minikube-7f4b5d6dd6-56z8s:/app# python
Python 3.8.10 (default, May 12 2021, 15:56:47)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from kubernetes import client
>>> from kubernetes import config
```
[According to the example here](https://github.com/kubernetes-client/python#examples)
```
>>> config.load_kube_config()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/app/venv/lib/python3.8/site-packages/kubernetes/config/kube_config.py", line 813, in load_kube_config
loader = _get_kube_config_loader(
File "/app/venv/lib/python3.8/site-packages/kubernetes/config/kube_config.py", line 772, in _get_kube_config_loader
raise ConfigException(
kubernetes.config.config_exception.ConfigException: Invalid kube-config file. No configuration found.
```
So, the above command does not work in clusters. In clusters, the command as shown below should be used.
```
config.load_incluster_config()
```
Then, the next step would be listing all pods using `list_pod_for_all_namespaces` function. If it's desired to list only pods in a specific namespace, the function `list_namespaced_pod` should be used.
```
>>> v1 = client.CoreV1Api()
>>> ret = v1.list_pod_for_all_namespaces(watch=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api/core_v1_api.py", line 16864, in list_pod_for_all_namespaces
return self.list_pod_for_all_namespaces_with_http_info(**kwargs) # noqa: E501
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api/core_v1_api.py", line 16967, in list_pod_for_all_namespaces_with_http_info
return self.api_client.call_api(
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 348, in call_api
return self.__call_api(resource_path, method,
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 180, in __call_api
response_data = self.request(
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 373, in request
return self.rest_client.GET(url,
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/rest.py", line 239, in GET
return self.request("GET", url,
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/rest.py", line 233, in request
raise ApiException(http_resp=r)
kubernetes.client.exceptions.ApiException: (403)
Reason: Forbidden
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'X-Kubernetes-Pf-Flowschema-Uid': '7efca18f-3cc3-4a99-be09-59586a316041', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'c1eae4b0-1a62-4ba2-8ec6-677d6541bc5d', 'Date': 'Tue, 22 Jun 2021 04:47:02 GMT', 'Content-Length': '274'})
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"pods is forbidden: User \"system:serviceaccount:default:default\" cannot list resource \"pods\" in API group \"\" at the cluster scope","reason":"Forbidden","details":{"kind":"pods"},"code":403}
```
The most important part in this error message is `cannot list resource \"pods\" in API group`. Clearly, the issue relates to authorization.
To solve this issue, it's necessary to use [RBAC Authorization](https://hackmd.io/AoMPVOpBTSiBBI24ABtaFA)
The YAML file below is from the [here](https://github.com/kubernetes-client/python/issues/605#issuecomment-415217369)
```
# rbac_authorization.yml
kind:
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods-list
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods-list
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: Role
name: pods-list
```
Then, apply this YAML file using kubectl.
```
> kubectl apply -f rbac_authorization.yml
clusterrole.rbac.authorization.k8s.io/pods-list created
clusterrolebinding.rbac.authorization.k8s.io/pods-list created
```
Inspect the change using kubectl.
```
> kubectl describe roles pods-list
Name: pods-list
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [list]
```
As shown above, the information shown on the terminal is identical to the YAML file.
Go to the python shell in the container again.
```
>>> ret = v1.list_pod_for_all_namespaces(watch=False)
>>> pod_ips = [i.status.pod_ip for i in ret.items]
>>> pod_ips
['172.17.0.7', '172.17.0.6', '172.17.0.5', '172.17.0.8', '172.17.0.3', '172.17.0.4']
```
Now, it works.
If it is preferred to use `read_namespaced_pod_status` function, instead of `list_pod_for_all_namespaces` or `list_namespaced_pod`,. For example,
```
>>> import os
>>> POD_NS = os.environ['MY_POD_NAMESPACE']
>>> from kubernetes import client, config
>>> config.load_incluster_config()
>>>
>>> v1 = client.CoreV1Api()
>>> ret = v1.list_namespaced_pod(namespace=POD_NS)
>>> pod_nm = [i.metadata.name for i in ret.items]
>>> pod_stat = [v1.read_namespaced_pod_status(i, namespace=POD_NS) for i in pod_nm]
```
The error message would be similar as below.
```
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api/core_v1_api.py", line 23089, in read_namespaced_pod_status
return self.read_namespaced_pod_status_with_http_info(name, namespace, **kwargs) # noqa: E501
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api/core_v1_api.py", line 23176, in read_namespaced_pod_status_with_http_info
return self.api_client.call_api(
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 348, in call_api
return self.__call_api(resource_path, method,
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 180, in __call_api
response_data = self.request(
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 373, in request
return self.rest_client.GET(url,
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/rest.py", line 239, in GET
return self.request("GET", url,
File "/app/venv/lib/python3.8/site-packages/kubernetes/client/rest.py", line 233, in request
raise ApiException(http_resp=r)
kubernetes.client.exceptions.ApiException: (403)
Reason: Forbidden
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'X-Kubernetes-Pf-Flowschema-Uid': '7efca18f-3cc3-4a99-be09-59586a316041', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'c1eae4b0-1a62-4ba2-8ec6-677d6541bc5d', 'Date': 'Fri, 25 Jun 2021 10:27:02 GMT', 'Content-Length': '363'})
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"pods \"api-minikube-7b9d4659db-8pjq8\" is forbidden: User \"system:serviceaccount:default:default\" cannot get resource \"pods/status\" in API group \"\" in the namespace \"default\"","reason":"Forbidden","details":{"name":"api-minikube-7b9d4659db-8pjq8","kind":"pods"},"code":403}
```
In particular, `cannot get resource \"pods/status\" in API group`
Modify the above YAML file.
```
# rbac_authorization.yml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods-list
rules:
- apiGroups: [""]
resources: ["pods", "pods/status"]
verbs: ["list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods-list
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: Role
name: pods-list
apiGroup: rbac.authorization.k8s.io
```
The only difference is adding another resources called "pods/status".
Apply the YAML file again.
```
> kubectl apply -f rbac_authorization.yml
clusterrole.rbac.authorization.k8s.io/pods-list configured
clusterrolebinding.rbac.authorization.k8s.io/pods-list unchanged
```
It turns out the above modified YAML file does not work either.
To make it work, other verbs should be added.
```
# rbac_authorization.yml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods-list
rules:
- apiGroups: [""]
resources: ["pods", "pods/status"]
verbs: ["get", "watch", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods-list
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: Role
name: pods-list
apiGroup: rbac.authorization.k8s.io
```
Apply the YAML file again.
```
> kubectl apply -f rbac_authorization.yml
clusterrole.rbac.authorization.k8s.io/pods-list configured
clusterrolebinding.rbac.authorization.k8s.io/pods-list unchanged
```
Inspect the change using kubectl.
```
> kubectl describe roles pods-list
Name: pods-list
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods/status [] [] [get watch list]
pods [] [] [get watch list]
```
By adding verbs `get` and `watch`, it should work as expected.
```
>>> pod_stat = [v1.read_namespaced_pod_status(i, namespace=POD_NS) for i in pod_nm]
>>> [pod.status.phase for pod in pod_stat]
['Running', 'Running', 'Running', 'Running', 'Running', 'Running']
```
# Reference
- [**Official DOCS**](https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/AutoscalingV1Api.md)
- [Using RBAC Authorization](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
- https://github.com/kubernetes-client/python/issues/519
- https://github.com/kubernetes-client/python/issues/605
- https://github.com/kubernetes-client/python/blob/master/examples/in_cluster_config.py