This is an automated email from the ASF dual-hosted git repository.
taragolis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new e90febceb5 Make sure impersonation tests use a temporary
`AIRFLOW_HOME` (#33422)
e90febceb5 is described below
commit e90febceb549f669e887de4219cc19ba48b73a4c
Author: Andrey Anshin <[email protected]>
AuthorDate: Thu Aug 17 03:22:51 2023 +0400
Make sure impersonation tests use a temporary `AIRFLOW_HOME` (#33422)
---
tests/core/test_impersonation_tests.py | 88 +++++++++++++++++++++++++++++-----
1 file changed, 75 insertions(+), 13 deletions(-)
diff --git a/tests/core/test_impersonation_tests.py
b/tests/core/test_impersonation_tests.py
index 3827f89896..b92d437f16 100644
--- a/tests/core/test_impersonation_tests.py
+++ b/tests/core/test_impersonation_tests.py
@@ -17,13 +17,17 @@
# under the License.
from __future__ import annotations
+import contextlib
import logging
import os
import subprocess
import sys
+import tempfile
+from pathlib import Path
import pytest
+from airflow.configuration import conf
from airflow.jobs.backfill_job_runner import BackfillJobRunner
from airflow.jobs.job import Job, run_job
from airflow.models import DagBag, DagRun, TaskInstance
@@ -45,6 +49,42 @@ TEST_USER = "airflow_test_user"
logger = logging.getLogger(__name__)
[email protected]
+def set_permissions(settings: dict[Path | str, int]):
+ """Helper for recursively set permissions only for specific path and
revert it back."""
+ orig_permissions = []
+ try:
+ print(" Change file/directory permissions ".center(72, "+"))
+ for path, mode in settings.items():
+ if isinstance(path, str):
+ path = Path(path)
+ if len(path.parts) <= 1:
+ raise SystemError(f"Unable to change permission for the root
directory: {path}.")
+
+ st_mode = os.stat(path).st_mode
+ new_st_mode = st_mode | mode
+ if new_st_mode > st_mode:
+ print(f"Path={path}, mode={oct(st_mode)},
new_mode={oct(new_st_mode)}")
+ orig_permissions.append((path, st_mode))
+ os.chmod(path, new_st_mode)
+
+ parent_path = path.parent
+ while len(parent_path.parts) > 1:
+ st_mode = os.stat(parent_path).st_mode
+ new_st_mode = st_mode | 0o755 # grant r/o access to the
parent directories
+ if new_st_mode > st_mode:
+ print(f"Path={parent_path}, mode={oct(st_mode)},
new_mode={oct(new_st_mode)}")
+ orig_permissions.append((parent_path, st_mode))
+ os.chmod(parent_path, new_st_mode)
+
+ parent_path = parent_path.parent
+ print("".center(72, "+"))
+ yield
+ finally:
+ for path, mode in orig_permissions:
+ os.chmod(path, mode)
+
+
@pytest.fixture
def check_original_docker_image():
if not os.path.isfile("/.dockerenv") or
os.environ.get("PYTHON_BASE_IMAGE") is None:
@@ -55,18 +95,7 @@ def check_original_docker_image():
"and only allow to run the test there. This is done by checking
/.dockerenv file "
"(always present inside container) and checking for
PYTHON_BASE_IMAGE variable."
)
-
-
[email protected]
-def set_permissions(check_original_docker_image):
- airflow_home = os.environ["AIRFLOW_HOME"]
- subprocess.check_call(
- 'find "%s" -exec sudo chmod og+w {} +; sudo chmod og+rx /root' %
airflow_home, shell=True
- )
yield
- subprocess.check_call(
- 'find "%s" -exec sudo chmod og-w {} +; sudo chmod og-rx /root' %
airflow_home, shell=True
- )
@pytest.fixture
@@ -84,15 +113,48 @@ def create_user(check_original_docker_image):
f"{command!r} without a password prompt (check sudoers
file)?\n"
f"{e.stdout.decode() if e.stdout else ''}"
)
- yield
+ yield TEST_USER
subprocess.check_call(["sudo", "userdel", "-r", TEST_USER])
[email protected]
+def create_airflow_home(create_user, tmp_path, monkeypatch):
+ sql_alchemy_conn = conf.get_mandatory_value("database", "sql_alchemy_conn")
+ username = create_user
+ airflow_home = tmp_path / "airflow-home"
+
+ if not airflow_home.exists():
+ airflow_home.mkdir(parents=True, exist_ok=True)
+
+ permissions = {
+ # By default, ``tmp_path`` save temporary files/directories in user
temporary directory
+ # something like: `/tmp/pytest-of-root` and other users might be
limited to access to it,
+ # so we need to grant at least r/o access to everyone.
+ airflow_home: 0o777,
+ # Grant full access to system-wide temporary directory (if for some
reason it not set)
+ tempfile.gettempdir(): 0o777,
+ }
+
+ if sql_alchemy_conn.lower().startswith("sqlite"):
+ sqlite_file = Path(sql_alchemy_conn.replace("sqlite:///", ""))
+ # Grant r/w access to sqlite file.
+ permissions[sqlite_file] = 0o766
+ # Grant r/w access to directory where sqlite file placed
+ # otherwise we can't create temporary files during write access.
+ permissions[sqlite_file.parent] = 0o777
+
+ monkeypatch.setenv("AIRFLOW_HOME", str(airflow_home))
+
+ with set_permissions(permissions):
+ subprocess.check_call(["sudo", "chown", f"{username}:root",
str(airflow_home), "-R"], close_fds=True)
+ yield airflow_home
+
+
class BaseImpersonationTest:
dagbag: DagBag
@pytest.fixture(autouse=True)
- def setup_impersonation_tests(self, set_permissions, create_user):
+ def setup_impersonation_tests(self, create_airflow_home):
"""Setup test cases for all impersonation tests."""
db.clear_db_runs()
db.clear_db_jobs()