diff --git a/chart/templates/rbac/job-launcher-rolebinding.yaml b/chart/templates/rbac/job-launcher-rolebinding.yaml index e5cbca8c630b4..f918826663b12 100644 --- a/chart/templates/rbac/job-launcher-rolebinding.yaml +++ b/chart/templates/rbac/job-launcher-rolebinding.yaml @@ -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 @@ -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 }} diff --git a/chart/templates/rbac/pod-launcher-rolebinding.yaml b/chart/templates/rbac/pod-launcher-rolebinding.yaml index a9a3b510a4379..5e71c2511587a 100644 --- a/chart/templates/rbac/pod-launcher-rolebinding.yaml +++ b/chart/templates/rbac/pod-launcher-rolebinding.yaml @@ -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 @@ -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 diff --git a/chart/tests/helm_tests/airflow_aux/test_job_launcher_role.py b/chart/tests/helm_tests/airflow_aux/test_job_launcher_role.py index 74db8dad091d2..acbc181ba6695 100644 --- a/chart/tests/helm_tests/airflow_aux/test_job_launcher_role.py +++ b/chart/tests/helm_tests/airflow_aux/test_job_launcher_role.py @@ -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 diff --git a/chart/tests/helm_tests/airflow_aux/test_pod_launcher_role.py b/chart/tests/helm_tests/airflow_aux/test_pod_launcher_role.py index 3645d5850cf49..56bb333f23848 100644 --- a/chart/tests/helm_tests/airflow_aux/test_pod_launcher_role.py +++ b/chart/tests/helm_tests/airflow_aux/test_pod_launcher_role.py @@ -22,114 +22,193 @@ class TestPodLauncher: - """Tests pod launcher.""" + @pytest.mark.parametrize( + "executor", + ["LocalExecutor", "CeleryExecutor", "KubernetesExecutor", "CeleryExecutor,KubernetesExecutor"], + ) + def test_should_render(self, executor): + docs = render_chart( + values={"rbac": {"create": True}, "allowPodLaunching": True, "executor": executor}, + show_only=["templates/rbac/pod-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_pod_launcher_role(self, executor, rbac, allow, expected_accounts): + def test_should_not_render(self, rbac, allow, executor): docs = render_chart( + values={"rbac": {"create": rbac}, "allowPodLaunching": allow, "executor": executor}, + show_only=["templates/rbac/pod-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}, "allowPodLaunching": True, "multiNamespaceMode": False}, + show_only=["templates/rbac/pod-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-pod-launcher-role" + + metadata = jmespath.search("metadata", docs[0]) + assert metadata["namespace"] == "airflow" + assert metadata["name"] == "prod-pod-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}, "allowPodLaunching": True, "multiNamespaceMode": True}, + show_only=["templates/rbac/pod-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-pod-launcher-role" + + metadata = jmespath.search("metadata", docs[0]) + assert "namespace" not in metadata + assert metadata["name"] == "airflow-prod-pod-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}, - "allowPodLaunching": allow, + "rbac": {"create": True}, + "allowPodLaunching": True, "executor": executor, + "scheduler": {"enabled": True}, }, show_only=["templates/rbac/pod-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-pod-launcher-role", - "namespace-release-name-pod-launcher-rolebinding", - ), - ( - True, - "other-ns", - "other-ns-release-name-pod-launcher-role", - "other-ns-release-name-pod-launcher-rolebinding", - ), - (False, "namespace", "release-name-pod-launcher-role", "release-name-pod-launcher-rolebinding"), + ("CeleryExecutor", False), + ("CeleryExecutor", True), + ("LocalExecutor", False), + ("KubernetesExecutor", False), + ("LocalExecutor,CeleryExecutor", False), ], ) - def test_pod_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={"multiNamespaceMode": multiNamespaceMode}, + name="prod", + values={ + "rbac": {"create": True}, + "allowPodLaunching": True, + "executor": executor, + "scheduler": {"enabled": enabled}, + }, show_only=["templates/rbac/pod-launcher-rolebinding.yaml"], ) - actualRoleBinding = jmespath.search("metadata.name", docs[0]) - assert actualRoleBinding == expectedRoleBinding + assert jmespath.search("subjects[?name=='prod-airflow-scheduler']", docs[0]) == [] - actualRoleRef = jmespath.search("roleRef.name", docs[0]) - assert actualRoleRef == expectedRole + @pytest.mark.parametrize( + "executor", ["CeleryExecutor", "KubernetesExecutor", "LocalExecutor,CeleryExecutor"] + ) + def test_worker_role_binding_should_exists(self, executor): + docs = render_chart( + name="prod", + namespace="airflow", + values={"rbac": {"create": True}, "allowPodLaunching": True, "executor": executor}, + show_only=["templates/rbac/pod-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}, "allowPodLaunching": True, "executor": "LocalExecutor"}, + show_only=["templates/rbac/pod-launcher-rolebinding.yaml"], + ) - 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-worker']", docs[0]) == [] @pytest.mark.parametrize( - ("multiNamespaceMode", "namespace", "expectedRole"), - [ - (True, "namespace", "namespace-release-name-pod-launcher-role"), - (True, "other-ns", "other-ns-release-name-pod-launcher-role"), - (False, "namespace", "release-name-pod-launcher-role"), - ], + "executor", + ["LocalExecutor", "CeleryExecutor", "KubernetesExecutor", "CeleryExecutor,KubernetesExecutor"], + ) + def test_triggerer_role_binding_should_exists(self, executor): + docs = render_chart( + name="prod", + namespace="airflow", + values={ + "rbac": {"create": True}, + "allowPodLaunching": True, + "executor": executor, + "triggerer": {"enabled": True}, + }, + show_only=["templates/rbac/pod-launcher-rolebinding.yaml"], + ) + + assert jmespath.search("subjects[?name=='prod-airflow-triggerer'] | [0]", docs[0]) == { + "kind": "ServiceAccount", + "name": "prod-airflow-triggerer", + "namespace": "airflow", + } + + @pytest.mark.parametrize( + "executor", + ["LocalExecutor", "CeleryExecutor", "KubernetesExecutor", "CeleryExecutor,KubernetesExecutor"], ) - def test_pod_launcher_role_multi_namespace(self, multiNamespaceMode, namespace, expectedRole): + def test_triggerer_role_binding_should_not_exists(self, executor): docs = render_chart( - namespace=namespace, - values={"multiNamespaceMode": multiNamespaceMode}, - show_only=["templates/rbac/pod-launcher-role.yaml"], + name="prod", + values={ + "rbac": {"create": True}, + "allowPodLaunching": True, + "executor": executor, + "triggerer": {"enabled": False}, + }, + show_only=["templates/rbac/pod-launcher-rolebinding.yaml"], ) - actualRole = jmespath.search("metadata.name", docs[0]) - assert actualRole == expectedRole + assert jmespath.search("subjects[?name=='prod-airflow-triggerer']", docs[0]) == [] + + def test_no_role_bindings(self): + docs = render_chart( + name="prod", + values={ + "rbac": {"create": True}, + "allowPodLaunching": True, + "executor": "LocalExecutor", + "scheduler": {"enabled": False}, + "triggerer": {"enabled": False}, + }, + show_only=["templates/rbac/pod-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 diff --git a/chart/tests/helm_tests/security/test_scc_rolebinding.py b/chart/tests/helm_tests/security/test_scc_rolebinding.py index 60fe24ade976b..6c50b1cb04e97 100644 --- a/chart/tests/helm_tests/security/test_scc_rolebinding.py +++ b/chart/tests/helm_tests/security/test_scc_rolebinding.py @@ -24,16 +24,81 @@ class TestSCCActivation: """Tests SCCs.""" - def test_zero_subjects_when_all_disabled(self): + @pytest.mark.parametrize( + "executor", + ["LocalExecutor", "CeleryExecutor", "KubernetesExecutor", "CeleryExecutor,KubernetesExecutor"], + ) + def test_should_render(self, executor): + docs = render_chart( + values={"rbac": {"create": True, "createSCCRoleBinding": True}, "executor": executor}, + show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], + ) + + assert len(docs) == 1 + + @pytest.mark.parametrize(("create", "role_binding"), [(True, False), (False, True), (False, False)]) + @pytest.mark.parametrize( + "executor", + ["LocalExecutor", "CeleryExecutor", "KubernetesExecutor", "CeleryExecutor,KubernetesExecutor"], + ) + def test_should_not_render(self, create, role_binding, executor): + docs = render_chart( + values={"rbac": {"create": create, "createSCCRoleBinding": role_binding}, "executor": executor}, + show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], + ) + + assert len(docs) == 0 + + def test_multi_namespace_mode_disabled(self): + docs = render_chart( + name="prod", + namespace="airflow", + values={"rbac": {"create": True, "createSCCRoleBinding": True}, "multiNamespaceMode": False}, + show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], + ) + + assert jmespath.search("kind", docs[0]) == "RoleBinding" + + metadata = jmespath.search("metadata", docs[0]) + assert metadata["namespace"] == "airflow" + assert metadata["name"] == "prod-scc-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, "createSCCRoleBinding": True}, "multiNamespaceMode": True}, + show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], + ) + + assert jmespath.search("kind", docs[0]) == "ClusterRoleBinding" + + metadata = jmespath.search("metadata", docs[0]) + assert "namespace" not in metadata + assert metadata["name"] == "airflow-prod-scc-rolebinding" + assert metadata["labels"]["namespace"] == "airflow" + + def test_role_ref_default(self): + docs = render_chart( + values={"rbac": {"create": True, "createSCCRoleBinding": True}}, + show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], + ) + + assert jmespath.search("roleRef", docs[0]) == { + "apiGroup": "rbac.authorization.k8s.io", + "kind": "ClusterRole", + "name": "system:openshift:scc:anyuid", + } + + def test_no_role_bindings(self): docs = render_chart( values={ - "multiNamespaceMode": False, + "rbac": {"create": True, "createSCCRoleBinding": True}, "executor": "LocalExecutor", - "data": {"brokerUrlSecretName": "test"}, "cleanup": {"enabled": False}, "databaseCleanup": {"enabled": False}, "flower": {"enabled": False}, - "rbac": {"create": True, "createSCCRoleBinding": True}, "dagProcessor": {"enabled": False}, "apiServer": {"enabled": False}, "scheduler": {"enabled": False}, @@ -46,104 +111,142 @@ def test_zero_subjects_when_all_disabled(self): show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], ) - assert jmespath.search("kind", docs[0]) == "RoleBinding" - assert jmespath.search("roleRef.kind", docs[0]) == "ClusterRole" - assert jmespath.search("metadata.name", docs[0]) == "release-name-scc-rolebinding" - assert jmespath.search("roleRef.name", docs[0]) == "system:openshift:scc:anyuid" assert jmespath.search("subjects", docs[0]) is None @pytest.mark.parametrize( - ("rbac_enabled", "scc_enabled", "created"), - [ - (False, False, False), - (False, True, False), - (True, True, True), - (True, False, False), - ], + "executor", ["CeleryExecutor", "KubernetesExecutor", "LocalExecutor,CeleryExecutor"] ) - def test_create_scc(self, rbac_enabled, scc_enabled, created): + def test_worker_role_binding_should_exists(self, executor): + docs = render_chart( + name="prod", + namespace="airflow", + values={"rbac": {"create": True, "createSCCRoleBinding": True}, "executor": executor}, + show_only=["templates/rbac/security-context-constraint-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, "createSCCRoleBinding": True}, "executor": "LocalExecutor"}, + show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], + ) + + assert jmespath.search("subjects[?name=='prod-airflow-worker']", docs[0]) == [] + + @pytest.mark.parametrize("executor", ["CeleryExecutor", "LocalExecutor,CeleryExecutor"]) + def test_flower_role_binding_should_exists(self, executor): + docs = render_chart( + name="prod", + namespace="airflow", values={ - "multiNamespaceMode": False, - "cleanup": {"enabled": True}, - "databaseCleanup": {"enabled": True}, + "rbac": {"create": True, "createSCCRoleBinding": True}, + "executor": executor, "flower": {"enabled": True}, - "rbac": {"create": rbac_enabled, "createSCCRoleBinding": scc_enabled}, }, show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], ) - assert bool(docs) is created - if created: - assert jmespath.search("kind", docs[0]) == "RoleBinding" - assert jmespath.search("roleRef.kind", docs[0]) == "ClusterRole" - assert jmespath.search("metadata.name", docs[0]) == "release-name-scc-rolebinding" - assert jmespath.search("roleRef.name", docs[0]) == "system:openshift:scc:anyuid" - assert jmespath.search("subjects | [*].name", docs[0]) == [ - "release-name-airflow-worker", - "release-name-airflow-scheduler", - "release-name-airflow-api-server", - "release-name-airflow-statsd", - "release-name-airflow-flower", - "release-name-airflow-redis", - "release-name-airflow-triggerer", - "release-name-airflow-migrate-database-job", - "release-name-airflow-create-user-job", - "release-name-airflow-cleanup", - "release-name-airflow-database-cleanup", - "release-name-airflow-dag-processor", - ] + assert jmespath.search("subjects[?name=='prod-airflow-flower'] | [0]", docs[0]) == { + "kind": "ServiceAccount", + "name": "prod-airflow-flower", + "namespace": "airflow", + } @pytest.mark.parametrize( - ("namespace", "expected_name"), + ("executor", "enabled"), [ - ("default", "default-release-name-scc-rolebinding"), - ("other-ns", "other-ns-release-name-scc-rolebinding"), + ("LocalExecutor", True), + ("LocalExecutor", False), + ("KubernetesExecutor", True), + ("KubernetesExecutor", False), + ("CeleryExecutor", False), ], ) - def test_create_scc_multinamespace(self, namespace, expected_name): + def test_flower_role_binding_should_not_exists(self, executor, enabled): docs = render_chart( - namespace=namespace, + name="prod", values={ - "multiNamespaceMode": True, - "createUserJob": {"enabled": False}, - "cleanup": {"enabled": False}, - "databaseCleanup": {"enabled": False}, - "flower": {"enabled": False}, "rbac": {"create": True, "createSCCRoleBinding": True}, + "executor": executor, + "flower": {"enabled": enabled}, }, show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], ) - assert jmespath.search("kind", docs[0]) == "ClusterRoleBinding" - assert jmespath.search("roleRef.kind", docs[0]) == "ClusterRole" - assert expected_name == jmespath.search("metadata.name", docs[0]) - assert jmespath.search("roleRef.name", docs[0]) == "system:openshift:scc:anyuid" + assert jmespath.search("subjects[?name=='prod-airflow-flower']", docs[0]) == [] - def test_create_scc_worker_only(self): + @pytest.mark.parametrize( + "executor", + [ + "LocalExecutor", + "KubernetesExecutor", + "CeleryExecutor", + "KubernetesExecutor,LocalExecutor,CeleryExecutor", + ], + ) + def test_only_enable_components_role_binding_should_exists(self, executor): docs = render_chart( + name="prod", + namespace="airflow", values={ - "multiNamespaceMode": False, - "createUserJob": {"enabled": False}, - "cleanup": {"enabled": False}, - "databaseCleanup": {"enabled": False}, - "flower": {"enabled": False}, - "statsd": {"enabled": False}, "rbac": {"create": True, "createSCCRoleBinding": True}, + "executor": executor, + "scheduler": {"enabled": True}, + "apiServer": {"enabled": True}, + "statsd": {"enabled": True}, + "redis": {"enabled": True}, + "triggerer": {"enabled": True}, + "migrateDatabaseJob": {"enabled": True}, + "createUserJob": {"enabled": True}, + "cleanup": {"enabled": True}, + "databaseCleanup": {"enabled": True}, + "dagProcessor": {"enabled": True}, }, show_only=["templates/rbac/security-context-constraint-rolebinding.yaml"], ) - assert jmespath.search("kind", docs[0]) == "RoleBinding" - assert jmespath.search("roleRef.kind", docs[0]) == "ClusterRole" - assert jmespath.search("metadata.name", docs[0]) == "release-name-scc-rolebinding" - assert jmespath.search("roleRef.name", docs[0]) == "system:openshift:scc:anyuid" - assert jmespath.search("subjects | [*].name", docs[0]) == [ - "release-name-airflow-worker", - "release-name-airflow-scheduler", - "release-name-airflow-api-server", - "release-name-airflow-redis", - "release-name-airflow-triggerer", - "release-name-airflow-migrate-database-job", - "release-name-airflow-dag-processor", - ] + subjects = jmespath.search("subjects", docs[0]) + assert { + "kind": "ServiceAccount", + "name": "prod-airflow-scheduler", + "namespace": "airflow", + } in subjects + assert { + "kind": "ServiceAccount", + "name": "prod-airflow-api-server", + "namespace": "airflow", + } in subjects + assert {"kind": "ServiceAccount", "name": "prod-airflow-statsd", "namespace": "airflow"} in subjects + assert {"kind": "ServiceAccount", "name": "prod-airflow-redis", "namespace": "airflow"} in subjects + assert { + "kind": "ServiceAccount", + "name": "prod-airflow-triggerer", + "namespace": "airflow", + } in subjects + assert { + "kind": "ServiceAccount", + "name": "prod-airflow-migrate-database-job", + "namespace": "airflow", + } in subjects + assert { + "kind": "ServiceAccount", + "name": "prod-airflow-create-user-job", + "namespace": "airflow", + } in subjects + assert {"kind": "ServiceAccount", "name": "prod-airflow-cleanup", "namespace": "airflow"} in subjects + assert { + "kind": "ServiceAccount", + "name": "prod-airflow-database-cleanup", + "namespace": "airflow", + } in subjects + assert { + "kind": "ServiceAccount", + "name": "prod-airflow-dag-processor", + "namespace": "airflow", + } in subjects