Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions chart/templates/rbac/job-launcher-rolebinding.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
## Airflow Job Launcher Role Binding
####################################
{{- if and .Values.rbac.create .Values.allowJobLaunching }}
{{- $schedulerLaunchExecutors := list "LocalExecutor" "KubernetesExecutor" }}
{{- $workerLaunchExecutors := list "CeleryExecutor" "KubernetesExecutor" }}
{{- $executors := split "," .Values.executor }}
apiVersion: rbac.authorization.k8s.io/v1
{{- if .Values.multiNamespaceMode }}
kind: ClusterRoleBinding
Expand Down Expand Up @@ -58,22 +55,14 @@ roleRef:
name: {{ include "airflow.fullname" . }}-job-launcher-role
{{- end }}
subjects:
{{- range $executor := $executors }}
{{- $executorClass := last (splitList "." ($executor | trim)) }}
{{- if has $executorClass $schedulerLaunchExecutors }}
{{- if and .Values.scheduler.enabled (or (contains "LocalExecutor" .Values.executor) (contains "KubernetesExecutor" .Values.executor)) }}
- kind: ServiceAccount
name: {{ include "scheduler.serviceAccountName" $ }}
namespace: "{{ $.Release.Namespace }}"
{{- break }}
{{- end }}
{{- end }}
{{- range $executor := $executors }}
{{- $executorClass := last (splitList "." ($executor | trim)) }}
{{- if has $executorClass $workerLaunchExecutors }}
{{- if or (contains "CeleryExecutor" .Values.executor) (contains "KubernetesExecutor" .Values.executor) }}
- kind: ServiceAccount
name: {{ include "worker.serviceAccountName" $ }}
namespace: "{{ $.Release.Namespace }}"
{{- break }}
{{- end }}
{{- end }}
{{- end }}
15 changes: 2 additions & 13 deletions chart/templates/rbac/pod-launcher-rolebinding.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
## Airflow Pod Launcher Role Binding
####################################
{{- if and .Values.rbac.create .Values.allowPodLaunching }}
{{- $schedulerLaunchExecutors := list "LocalExecutor" "KubernetesExecutor" }}
{{- $workerLaunchExecutors := list "CeleryExecutor" "KubernetesExecutor" }}
{{- $executors := split "," .Values.executor }}
apiVersion: rbac.authorization.k8s.io/v1
{{- if .Values.multiNamespaceMode }}
kind: ClusterRoleBinding
Expand Down Expand Up @@ -58,23 +55,15 @@ roleRef:
name: {{ include "airflow.fullname" . }}-pod-launcher-role
{{- end }}
subjects:
{{- range $executor := $executors }}
{{- $executorClass := last (splitList "." ($executor | trim)) }}
{{- if has $executorClass $schedulerLaunchExecutors }}
{{- if and .Values.scheduler.enabled (or (contains "LocalExecutor" .Values.executor) (contains "KubernetesExecutor" .Values.executor)) }}
- kind: ServiceAccount
name: {{ include "scheduler.serviceAccountName" $ }}
namespace: "{{ $.Release.Namespace }}"
{{- break }}
{{- end }}
{{- end }}
{{- range $executor := $executors }}
{{- $executorClass := last (splitList "." ($executor | trim)) }}
{{- if has $executorClass $workerLaunchExecutors }}
{{- if or (contains "CeleryExecutor" .Values.executor) (contains "KubernetesExecutor" .Values.executor) }}
- kind: ServiceAccount
name: {{ include "worker.serviceAccountName" $ }}
namespace: "{{ $.Release.Namespace }}"
{{- break }}
{{- end }}
{{- end }}
{{- if .Values.triggerer.enabled }}
- kind: ServiceAccount
Expand Down
208 changes: 122 additions & 86 deletions chart/tests/helm_tests/airflow_aux/test_job_launcher_role.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,114 +22,150 @@


class TestJobLauncher:
"""Tests job launcher RBAC."""
@pytest.mark.parametrize(
"executor",
["LocalExecutor", "CeleryExecutor", "KubernetesExecutor", "CeleryExecutor,KubernetesExecutor"],
)
def test_should_render(self, executor):
docs = render_chart(
values={"rbac": {"create": True}, "allowJobLaunching": True, "executor": executor},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)

assert len(docs) == 1

@pytest.mark.parametrize(("rbac", "allow"), [(True, False), (False, True), (False, False)])
@pytest.mark.parametrize(
("executor", "rbac", "allow", "expected_accounts"),
[
("KubernetesExecutor", True, True, ["scheduler", "worker"]),
(
"airflow.providers.cncf.kubernetes.executors.kubernetes_executor.KubernetesExecutor",
True,
True,
["scheduler", "worker"],
),
("CeleryExecutor", True, True, ["worker"]),
(
"airflow.providers.celery.executors.celery_executor.CeleryExecutor",
True,
True,
["worker"],
),
("LocalExecutor", True, True, ["scheduler"]),
("airflow.executors.local_executor.LocalExecutor", True, True, ["scheduler"]),
("LocalExecutor", False, False, []),
("CeleryExecutor,KubernetesExecutor", True, True, ["scheduler", "worker"]),
(
"CeleryExecutor,airflow.providers.cncf.kubernetes.executors.kubernetes_executor.KubernetesExecutor",
True,
True,
["scheduler", "worker"],
),
],
"executor",
["LocalExecutor", "CeleryExecutor", "KubernetesExecutor", "CeleryExecutor,KubernetesExecutor"],
)
def test_job_launcher_rolebinding(self, executor, rbac, allow, expected_accounts):
def test_should_not_render(self, rbac, allow, executor):
docs = render_chart(
values={"rbac": {"create": rbac}, "allowJobLaunching": allow, "executor": executor},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)

assert len(docs) == 0

def test_multi_namespace_mode_disabled(self):
docs = render_chart(
name="prod",
namespace="airflow",
values={"rbac": {"create": True}, "allowJobLaunching": True, "multiNamespaceMode": False},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)

assert jmespath.search("kind", docs[0]) == "RoleBinding"

role_ref = jmespath.search("roleRef", docs[0])
assert role_ref["kind"] == "Role"
assert role_ref["name"] == "prod-job-launcher-role"

metadata = jmespath.search("metadata", docs[0])
assert metadata["namespace"] == "airflow"
assert metadata["name"] == "prod-job-launcher-rolebinding"
assert "namespace" not in metadata["labels"]

def test_multi_namespace_mode_enabled(self):
docs = render_chart(
name="prod",
namespace="airflow",
values={"rbac": {"create": True}, "allowJobLaunching": True, "multiNamespaceMode": True},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)

assert jmespath.search("kind", docs[0]) == "ClusterRoleBinding"

role_ref = jmespath.search("roleRef", docs[0])
assert role_ref["kind"] == "ClusterRole"
assert role_ref["name"] == "airflow-prod-job-launcher-role"

metadata = jmespath.search("metadata", docs[0])
assert "namespace" not in metadata
assert metadata["name"] == "airflow-prod-job-launcher-rolebinding"
assert metadata["labels"]["namespace"] == "airflow"

@pytest.mark.parametrize(
"executor", ["LocalExecutor", "KubernetesExecutor", "KubernetesExecutor,LocalExecutor,CeleryExecutor"]
)
def test_scheduler_role_binding_should_exists(self, executor):
docs = render_chart(
name="prod",
namespace="airflow",
values={
"rbac": {"create": rbac},
"allowJobLaunching": allow,
"rbac": {"create": True},
"allowJobLaunching": True,
"executor": executor,
"scheduler": {"enabled": True},
},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)
if expected_accounts:
for idx, suffix in enumerate(expected_accounts):
assert f"release-name-airflow-{suffix}" == jmespath.search(f"subjects[{idx}].name", docs[0])
else:
assert docs == []

assert jmespath.search("subjects[?name=='prod-airflow-scheduler'] | [0]", docs[0]) == {
"kind": "ServiceAccount",
"name": "prod-airflow-scheduler",
"namespace": "airflow",
}

@pytest.mark.parametrize(
("multiNamespaceMode", "namespace", "expectedRole", "expectedRoleBinding"),
("executor", "enabled"),
[
(
True,
"namespace",
"namespace-release-name-job-launcher-role",
"namespace-release-name-job-launcher-rolebinding",
),
(
True,
"other-ns",
"other-ns-release-name-job-launcher-role",
"other-ns-release-name-job-launcher-rolebinding",
),
(False, "namespace", "release-name-job-launcher-role", "release-name-job-launcher-rolebinding"),
("CeleryExecutor", False),
("CeleryExecutor", True),
("KubernetesExecutor", False),
("LocalExecutor,CeleryExecutor", False),
],
)
def test_job_launcher_rolebinding_multi_namespace(
self, multiNamespaceMode, namespace, expectedRole, expectedRoleBinding
):
def test_scheduler_role_binding_should_not_exists(self, executor, enabled):
docs = render_chart(
namespace=namespace,
values={"allowJobLaunching": True, "multiNamespaceMode": multiNamespaceMode},
name="prod",
values={
"rbac": {"create": True},
"allowJobLaunching": True,
"executor": executor,
"scheduler": {"enabled": enabled},
},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)

actualRoleBinding = jmespath.search("metadata.name", docs[0])
assert actualRoleBinding == expectedRoleBinding

actualRoleRef = jmespath.search("roleRef.name", docs[0])
assert actualRoleRef == expectedRole

actualKind = jmespath.search("kind", docs[0])
actualRoleRefKind = jmespath.search("roleRef.kind", docs[0])
if multiNamespaceMode:
assert actualKind == "ClusterRoleBinding"
assert actualRoleRefKind == "ClusterRole"
else:
assert actualKind == "RoleBinding"
assert actualRoleRefKind == "Role"
assert jmespath.search("subjects[?name=='prod-airflow-scheduler']", docs[0]) == []

@pytest.mark.parametrize(
("multiNamespaceMode", "namespace", "expectedRole"),
[
(True, "namespace", "namespace-release-name-job-launcher-role"),
(True, "other-ns", "other-ns-release-name-job-launcher-role"),
(False, "namespace", "release-name-job-launcher-role"),
],
"executor", ["CeleryExecutor", "KubernetesExecutor", "LocalExecutor,CeleryExecutor"]
)
def test_job_launcher_role_multi_namespace(self, multiNamespaceMode, namespace, expectedRole):
def test_worker_role_binding_should_exists(self, executor):
docs = render_chart(
namespace=namespace,
values={"allowJobLaunching": True, "multiNamespaceMode": multiNamespaceMode},
show_only=["templates/rbac/job-launcher-role.yaml"],
name="prod",
namespace="airflow",
values={"rbac": {"create": True}, "allowJobLaunching": True, "executor": executor},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)

assert jmespath.search("subjects[?name=='prod-airflow-worker'] | [0]", docs[0]) == {
"kind": "ServiceAccount",
"name": "prod-airflow-worker",
"namespace": "airflow",
}

def test_worker_role_binding_should_not_exists(self):
docs = render_chart(
name="prod",
values={"rbac": {"create": True}, "allowJobLaunching": True, "executor": "LocalExecutor"},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)

actualRole = jmespath.search("metadata.name", docs[0])
assert actualRole == expectedRole
assert jmespath.search("subjects[?name=='prod-airflow-worker']", docs[0]) == []

def test_no_role_bindings(self):
docs = render_chart(
name="prod",
values={
"rbac": {"create": True},
"allowJobLaunching": True,
"executor": "LocalExecutor",
"scheduler": {"enabled": False},
},
show_only=["templates/rbac/job-launcher-rolebinding.yaml"],
)

actualKind = jmespath.search("kind", docs[0])
if multiNamespaceMode:
assert actualKind == "ClusterRole"
else:
assert actualKind == "Role"
assert jmespath.search("subjects[?name=='prod-airflow-scheduler']", docs[0]) is None
Loading
Loading