apply method didn't work with provided namespace
ahrechanychenko opened this issue · 8 comments
(Pdb) from kubernetes import config
(Pdb) from openshift.dynamic import DynamicClient
(Pdb) k8s_client = config.new_client_from_config()
(Pdb) dyn_client = DynamicClient(k8s_client)
(Pdb) data = yaml.safe_load(open("test.yaml"))
(Pdb) data
{'kind': 'Service', 'spec': {'ports': [{'targetPort': 8080, 'protocol': 'TCP', 'port': 8080, 'name': 'web3'}]}, 'apiVersion': 'v1', 'metadata': {'name': 'svc-test'}}
(Pdb) resp = dyn_client.apply(service, body=data, namespace="test")
PDB set_trace (IO-capturing turned off)
*** ValueError: Namespace is required for v1.Service
(Pdb) data['metadata']['namespace']="test"
(Pdb) data
{'kind': 'Service', 'spec': {'ports': [{'targetPort': 8080, 'protocol': 'TCP', 'port': 8080, 'name': 'web3'}]}, 'apiVersion': 'v1', 'metadata': {'namespace': 'test', 'name': 'svc-test'}}
(Pdb) resp = dyn_client.apply(service, body=data)
(Pdb) resp
ResourceInstance[Service]:
apiVersion: v1
kind: Service
metadata:
creationTimestamp: '2019-05-23T11:56:08Z'
name: svc-test
namespace: test
resourceVersion: '3133190'
selfLink: /api/v1/namespaces/test/services/svc-test
uid: c066a908-7d51-11e9-a348-5254002c416c
spec:
clusterIP: 172.30.186.221
ports:
- name: web3
port: 8080
protocol: TCP
targetPort: 8080
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
Cannot reproduce on latest master branch. I had to modify yours slightly to actually ensure that service
got defined.
Can you do print openshift.__version__
?
from kubernetes import config
from openshift.dynamic import DynamicClient
import yaml
k8s_client = config.new_client_from_config()
dyn_client = DynamicClient(k8s_client)
data = yaml.safe_load(open("service.yaml"))
service = dyn_client.resources.get(api_version='v1', kind='Service')
resp = dyn_client.apply(service, body=data, namespace="test")
$ kubectl get svc -n test -o yaml
apiVersion: v1
items:
- apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: '{"kind":"Service","spec":{"ports":[{"targetPort":8080,"protocol":"TCP","port":8080,"name":"web3"}]},"apiVersion":"v1","metadata":{"namespace":"test","name":"svc-test"}}'
creationTimestamp: 2019-05-23T13:17:42Z
name: svc-test
namespace: test
resourceVersion: "121618"
selfLink: /api/v1/namespaces/test/services/svc-test
uid: 2553598b-7d5d-11e9-b584-025000000001
spec:
clusterIP: 10.106.90.9
ports:
- name: web3
port: 8080
protocol: TCP
targetPort: 8080
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
kind: List
metadata:
resourceVersion: ""
selfLink: ""
0.10.0dev1
from pip I get next
print openshift.version
0.8.8
AttributeError: 'DynamicClient' object has no attribute 'apply'
and are you on the latest commit from the master branch?
if so, can you rerun my test and see if you get the same results (my service.yml should be the same as your test.yml) - if you don't, can you see what in your code differs from mine (or just paste the code exactly - I'm not really sure how yours ever worked without service
being defined or without import yaml
)
(openshift) [root@titan46 ~]# cat test.py
from kubernetes import config
from openshift.dynamic import DynamicClient
import yaml
k8s_client = config.new_client_from_config()
dyn_client = DynamicClient(k8s_client)
service = dyn_client.resources.get(api_version='v1', kind="Service")
data = yaml.safe_load(open("test.yaml"))
resp = dyn_client.apply(service, body=data, namespace="test")
(openshift) [root@titan46 ~]# python test.py
Traceback (most recent call last):
File "test.py", line 10, in
resp = dyn_client.apply(service, body=data, namespace="test")
File "/root/openshift/lib/python2.7/site-packages/openshift/dynamic/client.py", line 187, in apply
return apply(resource, body)
File "/root/openshift/lib/python2.7/site-packages/openshift/dynamic/apply.py", line 19, in apply
return resource.create(body=dict_merge(definition, desired_annotation), namespace=definition['metadata'].get('namespace'))
File "/root/openshift/lib/python2.7/site-packages/openshift/dynamic/client.py", line 77, in inner
resp = func(self, resource, *args, **kwargs)
File "/root/openshift/lib/python2.7/site-packages/openshift/dynamic/client.py", line 142, in create
namespace = self.ensure_namespace(resource, namespace, body)
File "/root/openshift/lib/python2.7/site-packages/openshift/dynamic/client.py", line 125, in ensure_namespace
raise ValueError("Namespace is required for {}.{}".format(resource.group_version, resource.kind))
ValueError: Namespace is required for v1.Service
(openshift) [root@titan46 openshift-restclient-python]# git log -n 1
commit 4376f93
Author: Fabian von Feilitzsch fabian@fabianism.us
Date: Wed May 22 16:13:10 2019 -0400
always use merge-patch+json in apply (#294)
I honestly have no idea - as I say, I can't reproduce.
Things I would try:
- add
print body
before theraise ValueError
in client.py - add
print data
just after theyaml.load
in your script
That should show that either data
is wrong (an input problem) or it gets mangled before ensure_namespace
.
(test) []# cat test.py
from openshift.dynamic import DynamicClient
import yaml
k8s_client = config.new_client_from_config()
dyn_client = DynamicClient(k8s_client)
service = dyn_client.resources.get(api_version='v1', kind="Service")
data = yaml.safe_load(open("test.yaml"))
print("content of data")
print(data)
resp = dyn_client.apply(service, body=data, namespace="test")'''
###updated func
(test) [root@titan46 ~]# grep "def apply(self, resource, body=None, name=None, namespace=None):" /tmp/test/lib/python2.7/site-packages/openshift/dynamic/client.py -A14
def apply(self, resource, body=None, name=None, namespace=None):
print("print body before serialization")
print(body)
body = self.serialize_body(body)
print("after serialization")
print(body)
name = name or body.get('metadata', {}).get('name')
if not name:
raise ValueError("name is required to apply {}.{}".format(resource.group_version, resource.kind))
if resource.namespaced:
namespace = self.ensure_namespace(resource, namespace, body)
print("namespace from apply_func")
print(namespace)
return apply(resource, body)
(test) [~]# python test.py
content of data
{'kind': 'Service', 'spec': {'ports': [{'targetPort': 8080, 'protocol': 'TCP', 'port': 8080, 'name': 'web3'}]}, 'apiVersion': 'v1', 'metadata': {'name': 'svc-test'}}
print body before serialization
{'kind': 'Service', 'spec': {'ports': [{'targetPort': 8080, 'protocol': 'TCP', 'port': 8080, 'name': 'web3'}]}, 'apiVersion': 'v1', 'metadata': {'name': 'svc-test'}}
after serialization
{'kind': 'Service', 'spec': {'ports': [{'targetPort': 8080, 'protocol': 'TCP', 'port': 8080, 'name': 'web3'}]}, 'apiVersion': 'v1', 'metadata': {'name': 'svc-test'}}
namespace from apply_func
test
Traceback (most recent call last):
File "test.py", line 12, in
resp = dyn_client.apply(service, body=data, namespace="test")
File "/tmp/test/lib/python2.7/site-packages/openshift/dynamic/client.py", line 193, in apply
return apply(resource, body)
File "/tmp/test/lib/python2.7/site-packages/openshift/dynamic/apply.py", line 19, in apply
return resource.create(body=dict_merge(definition, desired_annotation), namespace=definition['metadata'].get('namespace'))
File "/tmp/test/lib/python2.7/site-packages/openshift/dynamic/client.py", line 77, in inner
resp = func(self, resource, *args, **kwargs)
File "/tmp/test/lib/python2.7/site-packages/openshift/dynamic/client.py", line 142, in create
namespace = self.ensure_namespace(resource, namespace, body)
File "/tmp/test/lib/python2.7/site-packages/openshift/dynamic/client.py", line 125, in ensure_namespace
raise ValueError("Namespace is required for {}.{}".format(resource.group_version, resource.kind))
ValueError: Namespace is required for v1.Service
argh, yes, it's obvious now. I had namespace in my test.yaml, no wonder I couldn't reproduce (this is why a full test case with all the data is helpful)
also, please can you enclose your code snippets in triple backticks, it makes them much more readable.
#300 should fix this issue