What happened (please include outputs or screenshots):
from code below, the print(v1deployment) shows:
'env_from': [{'config_map_ref': 'global-config','prefix': None,'secret_ref': None}],
but the last line ( print(updated) or print(created)) shows the response from the server/k8sApi is:
'env_from': None
What you expected to happen:
env_from/envFrom should have been created.
How to reproduce it (as minimally and precisely as possible):
python code (sorry for the length)
import kubernetes.client as kclient
import kubernetes.config as kconfig
# init k8s api config
kconfig.load_kube_config()
# declare variables
namespace_name = '125-dev'
deployment_name = 'test'
match_labels = {'app': deployment_name}
metadata = {'name': deployment_name, 'labels': match_labels}
pod_name = deployment_name
pod_image = 'busybox'
envFrom = [{'configMapRef': {'name': 'global-config'}}]
# build v1deployment object
labels = kclient.V1ObjectMeta(labels=match_labels)
# # add envFrom object to v1container object
v1configmapenvsource = [kclient.V1EnvFromSource(i.get('configMapRef').get('name')) for i in envFrom]
v1container = kclient.V1Container(name=pod_name, image=pod_image, env_from=v1configmapenvsource)
# # create deployment object
v1deploymentspec = kclient.V1DeploymentSpec(
selector=kclient.V1LabelSelector(match_labels=labels.labels),
template=kclient.V1PodTemplateSpec(
spec=kclient.V1PodSpec(**kclient.V1PodSpec(containers=[v1container]).to_dict()), metadata=labels
)
)
v1deployment = kclient.V1Deployment(metadata=kclient.V1ObjectMeta(**metadata), spec=v1deploymentspec)
print(v1deployment)
# check if deployment exists
deployment_exists = False
apps_v1 = kclient.AppsV1Api()
deployments = apps_v1.list_namespaced_deployment(namespace=namespace_name)
for i in deployments.items:
if i.metadata.name == deployment_name:
deployment_exists = True
# if deployment exists: patch, if not: create
if deployment_exists:
print(f"Deployment {metadata.get('name')} found. Patching now.")
updated = apps_v1.patch_namespaced_deployment(name=v1deployment.metadata.name,
namespace=namespace_name,
body=v1deployment, field_manager='Octopus')
print(updated)
else:
print(f"Deployment {metadata.get('name')} not found. Creating now.")
created = apps_v1.create_namespaced_deployment(namespace=namespace_name,
body=v1deployment, field_manager='Octopus')
# dry_run='All')
print(created)
Anything else we need to know?:
Environment:
kubectl version):Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.0", GitCommit:"70132b0f130acc0bed193d9ba59dd186f0e634cf", GitTreeState:"clean", BuildDate:"2019-12-07T21:20:10Z", GoVersion:"go1.13.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.6", GitCommit:"7015f71e75f670eb9e7ebd4b5749639d42e20079", GitTreeState:"clean", BuildDate:"2019-11-13T11:11:50Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
python --version): Python 3.7.4pip list | grep kubernetes): kubernetes 10.0.1Simpler; this creates a Pod with environment variables from a ConfigMap.
import kubernetes.config as config
from kubernetes.client import V1Pod, V1ObjectMeta, V1PodSpec, V1Container, V1ConfigMapEnvSource, CoreV1Api, V1EnvVar, V1EnvFromSource
config.load_kube_config()
v1 = CoreV1Api()
r = v1.create_namespaced_pod(
'default',
body=V1Pod(
metadata=V1ObjectMeta(name='issue1095'),
spec=V1PodSpec(
containers=[
V1Container(
name='issue1095',
image='busybox',
env=[
V1EnvVar(name="static-key", value="static-value")
],
env_from=[
V1EnvFromSource(
config_map_ref=V1ConfigMapEnvSource(name="configmap-name")
)
]
)
]
)
)
)
print("Created", r)
assert r.spec.containers[0].env_from[0].config_map_ref.name == 'configmap-name'
import subprocess
r = subprocess.check_output(['kubectl', 'get', 'pods', 'issue1095', '-o', 'yaml']).decode()
assert 'configmap-name' in r
$ kubectl describe pod issue1095 | grep -B 3 -A 2 ConfigMap
Ready: False
Restart Count: 0
Environment Variables from:
configmap-name ConfigMap Optional: false
Environment:
static-key: static-value
kubernetes==8.0.1You're never actually creating a V1ConfigMapEnvSource object.
So I changed this line:
# v1configmapenvsource = [kclient.V1EnvFromSource(i.get('configMapRef').get('name')) for i in envFrom]
to this:
v1configmapenvsource = [
kclient.V1EnvFromSource(config_map_ref=kclient.V1ConfigMapEnvSource(name=i.get('configMapRef').get('name'))) for i
in envFrom
]
and got the same result (envFrom: None in the response). I'll try your code sample and see if anything changes.
I'm using a Deployment, so I'll wrap the pod you have in the Deployment object.
Same result with your code sample updated for a Deployment. I'll try just a Pod by itself.
So @alanjcastonguay your code sample worked when creating a pod by itself. the envFrom came back properly from the Api.
I just realized... I'm not sure why, but I was creating a v1PodSpec object to pass in **args to a v1PodSpec object...
I changed this:
v1deploymentspec = kclient.V1DeploymentSpec(
selector=kclient.V1LabelSelector(match_labels=labels.labels),
template=kclient.V1PodTemplateSpec(
spec=kclient.V1PodSpec(**kclient.V1PodSpec(containers=[v1container]).to_dict()), metadata=labels
)
)
to this:
v1deploymentspec = kclient.V1DeploymentSpec(
selector=kclient.V1LabelSelector(match_labels=labels.labels),
template=kclient.V1PodTemplateSpec(
spec=kclient.V1PodSpec(containers=[v1container]), metadata=labels
)
)
and it worked!
Confirmed in my normal code. Apparently creating a V1PodSpec, converting it to a dict, and then using that for **args to create a V1PodSpec breaks the envFrom object (because I assume it gets added as a dict instead of a V1ConfigMapEnvSource object.)
Again, I have no idea why I thought that was a good idea. 馃槵
@alanjcastonguay is it out of the scope of kubernetes-client/python to recursively resolve the embedded objects? I'm a little miffed that I can't just pass it a dict of dicts and have it resolve properly. In the end, I assume it's just passing JSON to the Api anyway, right?
Dunno what the dict-style would be doing. But everything else in the library assumes classes that know how to (de)serialize themselves.
/assign
/close
@alanjcastonguay: You can't close an active issue/PR unless you authored it or you are a collaborator.
In response to this:
/close
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.