diff --git a/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py b/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py index 36d420692be97..dc0bf13d0cfb4 100644 --- a/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py +++ b/dev/breeze/src/airflow_breeze/utils/docker_command_utils.py @@ -230,7 +230,7 @@ def check_docker_version(quiet: bool = False): sys.exit(1) -def check_container_engine(quiet: bool = False): +def check_container_engine_is_docker(quiet: bool = False) -> bool: """Checks if the container engine is Docker or podman.""" response = run_command( ["docker", "version"], @@ -254,10 +254,12 @@ def check_container_engine(quiet: bool = False): ) if podman_engine_enabled: get_console().print( - "[error]Podman is not yet supported as a container engine in breeze.[/]\n" - "[warning]Please switch to Docker.[/]" + "[warning]Podman container engine detected.[/]\n" + "[warning]Podman container engine has not become fully supported in breeze yet.[/]" ) - sys.exit(1) + return False + get_console().print("[success]Docker container engine detected.[/]") + return True def check_remote_ghcr_io_commands(): @@ -538,10 +540,15 @@ def check_executable_entrypoint_permissions(quiet: bool = False): @lru_cache def perform_environment_checks(quiet: bool = False): check_docker_is_running() - check_container_engine(quiet) - check_docker_version(quiet) - check_docker_compose_version(quiet) - check_executable_entrypoint_permissions(quiet) + container_engine_is_docker = check_container_engine_is_docker(quiet) + if not container_engine_is_docker: + get_console().print("[error]Unsupported container engine detected.[/]") + get_console().print("[error]Install and enable Docker to continue.[/]") + sys.exit(1) + else: + check_docker_version(quiet) + check_docker_compose_version(quiet) + check_executable_entrypoint_permissions(quiet) if not quiet: get_console().print(f"[success]Host python version is {sys.version}[/]") diff --git a/dev/breeze/src/airflow_breeze/utils/run_utils.py b/dev/breeze/src/airflow_breeze/utils/run_utils.py index 8c34f1e8a16f5..cfd9e9e179cf0 100644 --- a/dev/breeze/src/airflow_breeze/utils/run_utils.py +++ b/dev/breeze/src/airflow_breeze/utils/run_utils.py @@ -368,7 +368,20 @@ def check_if_buildx_plugin_installed() -> bool: text=True, check=False, ) - if docker_buildx_version_result.returncode == 0: + if "buildah" in docker_buildx_version_result.stdout.lower(): + get_console().print( + "[warning]Detected buildah installation.[/]\n" + "[warning]The Dockerfiles are only compatible with BuildKit.[/]\n" + "[warning]Please see the syntax declaration at the top of the Dockerfiles for BuildKit version\n" + ) + return False + if ( + docker_buildx_version_result.returncode == 0 + and "buildx" in docker_buildx_version_result.stdout.lower() + ): + get_console().print( + "[success]Docker BuildKit is installed and will be used for the image build.[/]\n" + ) return True return False diff --git a/dev/breeze/tests/test_run_utils.py b/dev/breeze/tests/test_run_utils.py index 5b77e84c282bc..cd278834245a2 100644 --- a/dev/breeze/tests/test_run_utils.py +++ b/dev/breeze/tests/test_run_utils.py @@ -17,10 +17,12 @@ from __future__ import annotations import stat +from unittest import mock from airflow_breeze.utils.run_utils import ( change_directory_permission, change_file_permission, + check_if_buildx_plugin_installed, ) @@ -42,3 +44,56 @@ def test_change_directory_permission(tmp_path): assert not (mode & stat.S_IWOTH) assert mode & stat.S_IXGRP assert mode & stat.S_IXOTH + + +@mock.patch("airflow_breeze.utils.run_utils.run_command") +@mock.patch("airflow_breeze.utils.run_utils.get_console") +def test_check_buildah_is_installed(mock_get_console, mock_run_command): + mock_run_command.return_value.returncode = 0 + mock_run_command.return_value.stdout = "buildah 1.33.7" + assert check_if_buildx_plugin_installed() is False + mock_run_command.assert_called_with( + ["docker", "buildx", "version"], + no_output_dump_on_exception=True, + capture_output=True, + text=True, + check=False, + ) + mock_get_console.return_value.print.assert_called_with( + "[warning]Detected buildah installation.[/]\n" + "[warning]The Dockerfiles are only compatible with BuildKit.[/]\n" + "[warning]Please see the syntax declaration at the top of the Dockerfiles for BuildKit version\n" + ) + + +@mock.patch("airflow_breeze.utils.run_utils.run_command") +@mock.patch("airflow_breeze.utils.run_utils.get_console") +def test_check_buildkit_is_installed(mock_get_console, mock_run_command): + mock_run_command.return_value.returncode = 0 + mock_run_command.return_value.stdout = "github.com/docker/buildx v0.29.1-desktop.1" + assert check_if_buildx_plugin_installed() is True + mock_run_command.assert_called_with( + ["docker", "buildx", "version"], + no_output_dump_on_exception=True, + capture_output=True, + text=True, + check=False, + ) + mock_get_console.return_value.print.assert_called_with( + "[success]Docker BuildKit is installed and will be used for the image build.[/]\n" + ) + + +@mock.patch("airflow_breeze.utils.run_utils.run_command") +@mock.patch("airflow_breeze.utils.run_utils.get_console") +def test_check_buildx_not_detected(mock_get_console, mock_run_command): + mock_run_command.return_value.returncode = 1 + assert check_if_buildx_plugin_installed() is False + mock_run_command.assert_called_with( + ["docker", "buildx", "version"], + no_output_dump_on_exception=True, + capture_output=True, + text=True, + check=False, + ) + mock_get_console.return_value.print.assert_not_called()