Python: envFrom Does Not Get Created

Created on 2 Mar 2020  路  12Comments  路  Source: kubernetes-client/python

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:

  • Kubernetes version (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"}
  • OS (e.g., MacOS 10.13.6): Ubuntu 18.04
  • Python version (python --version): Python 3.7.4
  • Python client version (pip list | grep kubernetes): kubernetes 10.0.1
kinbug

All 12 comments

Simpler; 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 version: kubectl v1.16.2, server v1.15.5
  • OS: MacOS 10.15.2 (19C57)
  • Python version: 3.7.3
  • Python client version: kubernetes==8.0.1

You'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.

Was this page helpful?
0 / 5 - 0 ratings