This is an automated email from the ASF dual-hosted git repository.
dimberman pushed a commit to branch v1-10-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v1-10-test by this push:
new 589d907 Fix pod_mutation_hook for 1.10.13 (#10850)
589d907 is described below
commit 589d907039c80950d0c8d71b7ca0e41d29428cb6
Author: Daniel Imberman <[email protected]>
AuthorDate: Thu Sep 10 11:27:08 2020 -0700
Fix pod_mutation_hook for 1.10.13 (#10850)
* Fix breaking changes in Pod conversion for 1.10.13
* fix tests
* fix flake8
* fix test
* fix image secrets
* Update airflow/kubernetes/pod_launcher.py
Co-authored-by: Kaxil Naik <[email protected]>
Co-authored-by: Kaxil Naik <[email protected]>
---
airflow/bin/cli.py | 2 ++
airflow/contrib/kubernetes/pod.py | 20 ++++++++++++++--
airflow/kubernetes/pod_launcher.py | 3 ++-
tests/kubernetes/models/test_pod.py | 12 +++++++---
tests/kubernetes/test_pod_launcher.py | 2 ++
tests/test_local_settings/test_local_settings.py | 29 ++++++++++++------------
6 files changed, 48 insertions(+), 20 deletions(-)
diff --git a/airflow/bin/cli.py b/airflow/bin/cli.py
index 45f1c5a..cc8372a 100644
--- a/airflow/bin/cli.py
+++ b/airflow/bin/cli.py
@@ -1255,6 +1255,7 @@ def _serve_logs(env, skip_serve_logs=False):
def kubernetes_generate_dag_yaml(args):
from airflow.executors.kubernetes_executor import
AirflowKubernetesScheduler, KubeConfig
from airflow.kubernetes.pod_generator import PodGenerator
+ from airflow.kubernetes.pod_launcher import PodLauncher
from airflow.kubernetes.worker_configuration import WorkerConfiguration
from kubernetes.client.api_client import ApiClient
dag = get_dag(args)
@@ -1276,6 +1277,7 @@ def kubernetes_generate_dag_yaml(args):
worker_config=WorkerConfiguration(kube_config=kube_config).as_pod()
)
api_client = ApiClient()
+ pod = PodLauncher._mutate_pod_backcompat(pod)
date_string =
AirflowKubernetesScheduler._datetime_to_label_safe_datestring( # pylint:
disable=W0212
args.execution_date)
yaml_file_name = "{}_{}_{}.yml".format(args.dag_id, ti.task_id,
date_string)
diff --git a/airflow/contrib/kubernetes/pod.py
b/airflow/contrib/kubernetes/pod.py
index 9dc11cc..d1f30a8 100644
--- a/airflow/contrib/kubernetes/pod.py
+++ b/airflow/contrib/kubernetes/pod.py
@@ -118,7 +118,7 @@ class Pod(object):
self.node_selectors = node_selectors or {}
self.namespace = namespace
self.image_pull_policy = image_pull_policy
- self.image_pull_secrets = image_pull_secrets
+ self.image_pull_secrets = image_pull_secrets or ""
self.init_containers = init_containers
self.service_account_name = service_account_name
self.resources = resources or Resources()
@@ -142,21 +142,29 @@ class Pod(object):
labels=self.labels,
name=self.name,
namespace=self.namespace,
+ annotations=self.annotations,
)
+ if self.image_pull_secrets:
+ image_pull_secrets = [k8s.V1LocalObjectReference(i)
+ for i in self.image_pull_secrets.split(",")]
+ else:
+ image_pull_secrets = []
spec = k8s.V1PodSpec(
init_containers=self.init_containers,
containers=[
k8s.V1Container(
image=self.image,
command=self.cmds,
+ env_from=[],
name="base",
env=[k8s.V1EnvVar(name=key, value=val) for key, val in
self.envs.items()],
args=self.args,
image_pull_policy=self.image_pull_policy,
)
],
- image_pull_secrets=self.image_pull_secrets,
+ image_pull_secrets=image_pull_secrets,
service_account_name=self.service_account_name,
+ node_selector=self.node_selectors,
dns_policy=self.dnspolicy,
host_network=self.hostnetwork,
tolerations=self.tolerations,
@@ -168,6 +176,14 @@ class Pod(object):
spec=spec,
metadata=meta,
)
+ for configmap_name in self.configmaps:
+ env_var = k8s.V1EnvFromSource(
+ config_map_ref=k8s.V1ConfigMapEnvSource(
+ name=configmap_name,
+ )
+ )
+ pod.spec.containers[0].env_from.append(env_var)
+
for port in _extract_ports(self.ports):
pod = port.attach_to_pod(pod)
volumes = _extract_volumes(self.volumes)
diff --git a/airflow/kubernetes/pod_launcher.py
b/airflow/kubernetes/pod_launcher.py
index e8d4d22..704a77e 100644
--- a/airflow/kubernetes/pod_launcher.py
+++ b/airflow/kubernetes/pod_launcher.py
@@ -303,6 +303,7 @@ def _convert_to_airflow_pod(pod):
volumes = _extract_volumes(pod.spec.volumes)
api_client = ApiClient()
init_containers = pod.spec.init_containers
+ image_pull_secrets = pod.spec.image_pull_secrets or []
if pod.spec.init_containers is not None:
init_containers = [api_client.sanitize_for_serialization(i) for i in
pod.spec.init_containers]
dummy_pod = Pod(
@@ -321,7 +322,7 @@ def _convert_to_airflow_pod(pod):
image_pull_policy=base_container.image_pull_policy or 'IfNotPresent',
tolerations=pod.spec.tolerations,
init_containers=init_containers,
- image_pull_secrets=pod.spec.image_pull_secrets,
+ image_pull_secrets=",".join([i.name for i in image_pull_secrets]),
resources=base_container.resources,
service_account_name=pod.spec.service_account_name,
secrets=secrets,
diff --git a/tests/kubernetes/models/test_pod.py
b/tests/kubernetes/models/test_pod.py
index 8a89da0..f8df28a 100644
--- a/tests/kubernetes/models/test_pod.py
+++ b/tests/kubernetes/models/test_pod.py
@@ -120,7 +120,10 @@ class TestPod(unittest.TestCase):
result = k8s_client.sanitize_for_serialization(result)
expected = \
- {'metadata': {'labels': {}, 'name': 'bar', 'namespace': 'baz'},
+ {'metadata': {'annotations': {},
+ 'labels': {},
+ 'name': 'bar',
+ 'namespace': 'baz'},
'spec': {'affinity': {},
'containers': [{'args': [],
'command': ['airflow'],
@@ -128,6 +131,7 @@ class TestPod(unittest.TestCase):
{'name': 'AIRFLOW_SECRET',
'valueFrom': {'secretKeyRef':
{'key': 'airflow_config',
'name': 'secret_name'}}}],
+ 'envFrom': [],
'image': 'foo',
'imagePullPolicy': 'Never',
'name': 'base',
@@ -139,18 +143,20 @@ class TestPod(unittest.TestCase):
'readOnly': True,
'subPath': '/'},
{'mountPath':
'/opt/airflow',
- 'name': 'secretvol' +
str(static_uuid),
+ 'name': 'secretvol' +
str(static_uuid),
'readOnly': True}]}],
'hostNetwork': False,
+ 'imagePullSecrets': [],
'initContainers': {'name': 'test-container',
'volumeMounts': {'mountPath':
'/foo/bar',
'name':
'init-volume-secret'}},
+ 'nodeSelector': {},
'securityContext': {},
'tolerations': [],
'volumes': [{'name': 'foo'},
{'name': 'bar',
'secret': {'secretName': 'volume-secret'}},
- {'name':
'secretvolcf4a56d2-8101-4217-b027-2af6216feb48',
+ {'name': 'secretvol' + str(static_uuid),
'secret': {'secretName':
'init-volume-secret'}},
{'name': 'secretvol' + str(static_uuid),
'secret': {'secretName': 'volume-secret'}}
diff --git a/tests/kubernetes/test_pod_launcher.py
b/tests/kubernetes/test_pod_launcher.py
index f56615f..63169ae 100644
--- a/tests/kubernetes/test_pod_launcher.py
+++ b/tests/kubernetes/test_pod_launcher.py
@@ -228,6 +228,7 @@ class TestPodLauncherHelper(unittest.TestCase):
run_as_user=0,
fs_group=0,
),
+ image_pull_secrets=[k8s.V1LocalObjectReference("my-secret")],
volumes=[
k8s.V1Volume(
name="myvolume"
@@ -286,6 +287,7 @@ class TestPodLauncherHelper(unittest.TestCase):
sub_path=None,
read_only=True
)],
+ image_pull_secrets="my-secret",
secrets=[Secret("env", "AIRFLOW_SECRET", "ai", "secret_key")],
security_context={'fsGroup': 0, 'runAsUser': 0},
volumes=[Volume(name="myvolume", configs={'name': 'myvolume'}),
diff --git a/tests/test_local_settings/test_local_settings.py
b/tests/test_local_settings/test_local_settings.py
index 9fab355..e69bd05 100644
--- a/tests/test_local_settings/test_local_settings.py
+++ b/tests/test_local_settings/test_local_settings.py
@@ -318,9 +318,10 @@ class LocalSettingsTest(unittest.TestCase):
self.assertEqual(
sanitized_pod_post_mutation,
- {"apiVersion": "v1",
- "kind": "Pod",
- 'metadata': {'labels': {'test_label': 'test_value'},
+ {'apiVersion': 'v1',
+ 'kind': 'Pod',
+ 'metadata': {'annotations': {},
+ 'labels': {'test_label': 'test_value'},
'name': mock.ANY,
'namespace': 'airflow-tests'},
'spec': {'affinity': {'nodeAffinity':
{'requiredDuringSchedulingIgnoredDuringExecution': {
@@ -330,6 +331,7 @@ class LocalSettingsTest(unittest.TestCase):
'containers': [{'args': ['/bin/sh', '-c', 'touch
/tmp/healthy2'],
'command': ['foo'],
'env': [{'name': 'TEST_USER',
'value': 'ADMIN'}],
+ 'envFrom': [],
'image': 'my_image',
'imagePullPolicy': 'Never',
'name': 'base',
@@ -338,14 +340,13 @@ class LocalSettingsTest(unittest.TestCase):
'resources': {'limits':
{'nvidia.com/gpu': '200G'},
'requests': {'cpu':
'200Mi',
'memory':
'2G'}},
- 'volumeMounts': [
- {'mountPath': '/mnt',
- 'name': 'foo',
- 'readOnly': True,
- 'subPath': '/'},
- {'mountPath':
'/opt/airflow/secrets/',
- 'name': 'airflow-secrets-mount',
- 'readOnly': True}]}],
+ 'volumeMounts': [{'mountPath':
'/mnt',
+ 'name': 'foo',
+ 'readOnly': True,
+ 'subPath': '/'},
+ {'mountPath':
'/opt/airflow/secrets/',
+ 'name':
'airflow-secrets-mount',
+ 'readOnly':
True}]}],
'hostNetwork': False,
'imagePullSecrets': [],
'initContainers': [{'name': 'init-container',
@@ -353,6 +354,8 @@ class LocalSettingsTest(unittest.TestCase):
'runAsUser':
50000},
'volumeMounts': [{'mountPath':
'/tmp',
'name':
'init-secret'}]}],
+ 'nodeSelector': {},
+ 'securityContext': {'runAsUser': 1},
'tolerations': [{'effect': 'NoSchedule',
'key': 'static-pods',
'operator': 'Equal',
@@ -364,9 +367,7 @@ class LocalSettingsTest(unittest.TestCase):
'volumes': [{'name': 'airflow-secrets-mount',
'secret': {'secretName':
'airflow-test-secrets'}},
{'name': 'bar'},
- {'name': 'foo'},
- ],
- 'securityContext': {'runAsUser': 1}}}
+ {'name': 'foo'}]}}
)
def test_pod_mutation_v1_pod(self):