def create_name(): """ Dynamically created name for the pod. Name should be unique so it does not collide with parallel runs. :return: """ return PodGenerator.make_unique_pod_id("data-volume-init")
def test_pod_name_confirm_to_max_length(self, _, pod_id): name = PodGenerator.make_unique_pod_id(pod_id) assert len(name) <= 253 parts = name.split(".") if len(pod_id) <= 63: assert len(parts[0]) == len(pod_id) else: assert len(parts[0]) <= 63 assert len(parts[1]) <= 63
def test_pod_name_is_valid(self, pod_id, expected_starts_with): name = PodGenerator.make_unique_pod_id(pod_id) regex = r"^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" assert (len(name) <= 253 and all(ch.lower() == ch for ch in name) and re.match( regex, name)), "pod_id is invalid - fails allowed regex check" assert name.rsplit(".")[0] == expected_starts_with
def test_create_pod_id(self): for dag_id, task_id in self._cases(): pod_name = PodGenerator.make_unique_pod_id( create_pod_id(dag_id, task_id)) assert self._is_valid_pod_id(pod_name)
def create_pod_request_obj(self) -> k8s.V1Pod: """ Creates a V1Pod based on user parameters. Note that a `pod` or `pod_template_file` will supersede all other values. """ self.log.debug("Creating pod for KubernetesPodOperator task %s", self.task_id) if self.pod_template_file: self.log.debug("Pod template file found, will parse for base pod") pod_template = pod_generator.PodGenerator.deserialize_model_file( self.pod_template_file) if self.full_pod_spec: pod_template = PodGenerator.reconcile_pods( pod_template, self.full_pod_spec) elif self.full_pod_spec: pod_template = self.full_pod_spec else: pod_template = k8s.V1Pod(metadata=k8s.V1ObjectMeta(name="name")) pod = k8s.V1Pod( api_version="v1", kind="Pod", metadata=k8s.V1ObjectMeta( namespace=self.namespace, labels=self.labels, name=self.name, annotations=self.annotations, ), spec=k8s.V1PodSpec( node_selector=self.node_selector, affinity=self.affinity, tolerations=self.tolerations, init_containers=self.init_containers, containers=[ k8s.V1Container( image=self.image, name="base", command=self.cmds, ports=self.ports, image_pull_policy=self.image_pull_policy, resources=self.k8s_resources, volume_mounts=self.volume_mounts, args=self.arguments, env=self.env_vars, env_from=self.env_from, ) ], image_pull_secrets=self.image_pull_secrets, service_account_name=self.service_account_name, host_network=self.hostnetwork, security_context=self.security_context, dns_policy=self.dnspolicy, scheduler_name=self.schedulername, restart_policy='Never', priority_class_name=self.priority_class_name, volumes=self.volumes, ), ) pod = PodGenerator.reconcile_pods(pod_template, pod) if self.random_name_suffix: pod.metadata.name = PodGenerator.make_unique_pod_id( pod.metadata.name) for secret in self.secrets: self.log.debug("Adding secret to task %s", self.task_id) pod = secret.attach_to_pod(pod) if self.do_xcom_push: self.log.debug("Adding xcom sidecar to task %s", self.task_id) pod = xcom_sidecar.add_xcom_sidecar(pod) return pod
def build_pod_request_obj(self, context=None): """ Returns V1Pod object based on pod template file, full pod spec, and other operator parameters. The V1Pod attributes are derived (in order of precedence) from operator params, full pod spec, pod template file. """ self.log.debug("Creating pod for KubernetesPodOperator task %s", self.task_id) if self.pod_template_file: self.log.debug("Pod template file found, will parse for base pod") pod_template = pod_generator.PodGenerator.deserialize_model_file( self.pod_template_file) if self.full_pod_spec: pod_template = PodGenerator.reconcile_pods( pod_template, self.full_pod_spec) elif self.full_pod_spec: pod_template = self.full_pod_spec else: pod_template = k8s.V1Pod(metadata=k8s.V1ObjectMeta(name="name")) pod = k8s.V1Pod( api_version="v1", kind="Pod", metadata=k8s.V1ObjectMeta( namespace=self.namespace, labels=self.labels, name=self.name, annotations=self.annotations, ), spec=k8s.V1PodSpec( node_selector=self.node_selector, affinity=self.affinity, tolerations=self.tolerations, init_containers=self.init_containers, containers=[ k8s.V1Container( image=self.image, name=self.BASE_CONTAINER_NAME, command=self.cmds, ports=self.ports, image_pull_policy=self.image_pull_policy, resources=self.k8s_resources, volume_mounts=self.volume_mounts, args=self.arguments, env=self.env_vars, env_from=self.env_from, ) ], image_pull_secrets=self.image_pull_secrets, service_account_name=self.service_account_name, host_network=self.hostnetwork, security_context=self.security_context, dns_policy=self.dnspolicy, scheduler_name=self.schedulername, restart_policy='Never', priority_class_name=self.priority_class_name, volumes=self.volumes, ), ) pod = PodGenerator.reconcile_pods(pod_template, pod) if self.random_name_suffix: pod.metadata.name = PodGenerator.make_unique_pod_id( pod.metadata.name) for secret in self.secrets: self.log.debug("Adding secret to task %s", self.task_id) pod = secret.attach_to_pod(pod) if self.do_xcom_push: self.log.debug("Adding xcom sidecar to task %s", self.task_id) pod = xcom_sidecar.add_xcom_sidecar(pod) labels = self._get_ti_pod_labels(context) self.log.info("Creating pod %s with labels: %s", pod.metadata.name, labels) # Merge Pod Identifying labels with labels passed to operator pod.metadata.labels.update(labels) # Add Airflow Version to the label # And a label to identify that pod is launched by KubernetesPodOperator pod.metadata.labels.update({ 'airflow_version': airflow_version.replace('+', '-'), 'kubernetes_pod_operator': 'True', }) pod_mutation_hook(pod) return pod
def test_create_pod_id(self): for dag_id, task_id in self._cases(): pod_name = PodGenerator.make_unique_pod_id( AirflowKubernetesScheduler._create_pod_id(dag_id, task_id)) self.assertTrue(self._is_valid_pod_id(pod_name))