This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch v2-9-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 487117802d63a9e7a8149ce192d8260ff37b9c07
Author: Jarek Potiuk <ja...@potiuk.com>
AuthorDate: Thu Apr 4 13:51:22 2024 +0200

    Make UV_HTTP_TIMEOUT default value bigger in WSL2 environment (#38742)
    
    * Make UV_HTTP_TIMEOUT default value bigger in WSL2 environment
    
    When uv docker build is run in WSL2 the default timeout does not
    cope well with downloading big packages and times-out with the
    default UV timeout. This PR performs detection of whether you
    are in a WSL environment and changes the timeout in case you are
    in WSL2. It also raises error when WSL1 is detected (not supported
    by Breeze at all). In case the WSL1 detection is wrong we also
    have an escape hatch by manually specifying `--uv-http-timeout`.
    
    * Update dev/breeze/src/airflow_breeze/utils/platforms.py
    
    Co-authored-by: Andrey Anshin <andrey.ans...@taragol.is>
    
    ---------
    
    Co-authored-by: Andrey Anshin <andrey.ans...@taragol.is>
    (cherry picked from commit fb7f82ccd5fa5adc8f1d44cfb3f411a24683db92)
---
 dev/breeze/src/airflow_breeze/global_constants.py  |  1 +
 .../src/airflow_breeze/params/build_ci_params.py   |  5 +-
 .../src/airflow_breeze/params/build_prod_params.py |  5 +-
 dev/breeze/src/airflow_breeze/utils/platforms.py   | 63 ++++++++++++++++++++++
 dev/breeze/src/airflow_breeze/utils/uv_utils.py    | 43 +++++++++++++++
 5 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/dev/breeze/src/airflow_breeze/global_constants.py 
b/dev/breeze/src/airflow_breeze/global_constants.py
index 0de45d8e10..fbf2abc5c1 100644
--- a/dev/breeze/src/airflow_breeze/global_constants.py
+++ b/dev/breeze/src/airflow_breeze/global_constants.py
@@ -122,6 +122,7 @@ ALLOWED_INSTALL_MYSQL_CLIENT_TYPES = ["mariadb", "mysql"]
 PIP_VERSION = "24.0"
 
 DEFAULT_UV_HTTP_TIMEOUT = 300
+DEFAULT_WSL2_HTTP_TIMEOUT = 900
 
 # packages that  providers docs
 REGULAR_DOC_PACKAGES = [
diff --git a/dev/breeze/src/airflow_breeze/params/build_ci_params.py 
b/dev/breeze/src/airflow_breeze/params/build_ci_params.py
index 2c02e81f25..05179df07b 100644
--- a/dev/breeze/src/airflow_breeze/params/build_ci_params.py
+++ b/dev/breeze/src/airflow_breeze/params/build_ci_params.py
@@ -67,7 +67,10 @@ class BuildCiParams(CommonBuildParams):
         self._req_arg("AIRFLOW_IMAGE_REPOSITORY", 
self.airflow_image_repository)
         self._req_arg("AIRFLOW_PRE_CACHED_PIP_PACKAGES", 
self.airflow_pre_cached_pip_packages)
         self._req_arg("AIRFLOW_USE_UV", self.use_uv)
-        self._opt_arg("UV_HTTP_TIMEOUT", self.uv_http_timeout)
+        if self.use_uv:
+            from airflow_breeze.utils.uv_utils import get_uv_timeout
+
+            self._opt_arg("UV_HTTP_TIMEOUT", get_uv_timeout(self))
         self._req_arg("AIRFLOW_VERSION", self.airflow_version)
         self._req_arg("BUILD_ID", self.build_id)
         self._req_arg("CONSTRAINTS_GITHUB_REPOSITORY", 
self.constraints_github_repository)
diff --git a/dev/breeze/src/airflow_breeze/params/build_prod_params.py 
b/dev/breeze/src/airflow_breeze/params/build_prod_params.py
index c752b15bff..d3a3dbfdbc 100644
--- a/dev/breeze/src/airflow_breeze/params/build_prod_params.py
+++ b/dev/breeze/src/airflow_breeze/params/build_prod_params.py
@@ -208,7 +208,10 @@ class BuildProdParams(CommonBuildParams):
         self._req_arg("AIRFLOW_IMAGE_REPOSITORY", 
self.airflow_image_repository)
         self._req_arg("AIRFLOW_PRE_CACHED_PIP_PACKAGES", 
self.airflow_pre_cached_pip_packages)
         self._opt_arg("AIRFLOW_USE_UV", self.use_uv)
-        self._opt_arg("UV_HTTP_TIMEOUT", self.uv_http_timeout)
+        if self.use_uv:
+            from airflow_breeze.utils.uv_utils import get_uv_timeout
+
+            self._req_arg("UV_HTTP_TIMEOUT", get_uv_timeout(self))
         self._req_arg("AIRFLOW_VERSION", self.airflow_version)
         self._req_arg("BUILD_ID", self.build_id)
         self._req_arg("CONSTRAINTS_GITHUB_REPOSITORY", 
self.constraints_github_repository)
diff --git a/dev/breeze/src/airflow_breeze/utils/platforms.py 
b/dev/breeze/src/airflow_breeze/utils/platforms.py
index c79e486525..f32ccd20a6 100644
--- a/dev/breeze/src/airflow_breeze/utils/platforms.py
+++ b/dev/breeze/src/airflow_breeze/utils/platforms.py
@@ -16,6 +16,10 @@
 # under the License.
 from __future__ import annotations
 
+import platform
+import sys
+from pathlib import Path
+
 
 def get_real_platform(single_platform: str) -> str:
     """
@@ -23,3 +27,62 @@ def get_real_platform(single_platform: str) -> str:
     are using: amd64 and arm64.
     """
     return single_platform.replace("x86_64", "amd64").replace("aarch64", 
"arm64").replace("/", "-")
+
+
+def _exists_no_permission_error(p: str) -> bool:
+    try:
+        return Path(p).exists()
+    except PermissionError:
+        return False
+
+
+def message_on_wsl1_detected(release_name: str | None, kernel_version: 
tuple[int, ...] | None):
+    from airflow_breeze.utils.console import get_console
+
+    get_console().print("[error]You are running WSL1 - Breeze requires WSL2! 
Quitting.\n")
+    get_console().print("[warning]It can also be that our detection mechanism 
is wrong:[/]\n\n")
+    if release_name:
+        get_console().print(f"[info]We based our WSL1 detection on the release 
name: `{release_name}`\n")
+    elif kernel_version:
+        get_console().print(f"[info]We based our WSL1 detection on the kernel 
version: `{kernel_version}`\n")
+    get_console().print(
+        "[info]If you are running WSL2, please report this issue to the 
maintainers\n"
+        "of Airflow, so we can improve the detection mechanism.\n"
+        "You can also try to run the command with `--uv-http-timeout 900` or "
+        "`--no-use-uv` flag to skip the WSL1 check.\n"
+    )
+
+
+def is_wsl2() -> bool:
+    """
+    Check if the current platform is WSL2. This method will exit with error 
printing appropriate
+    message if WSL1 is detected as WSL1 is not supported.
+
+    :return: True if the current platform is WSL2, False otherwise (unless 
it's WSL1 then it exits).
+    """
+    if not sys.platform.startswith("linux"):
+        return False
+    release_name = platform.uname().release
+    has_wsl_interop = 
_exists_no_permission_error("/proc/sys/fs/binfmt_misc/WSLInterop")
+    microsoft_in_release = "microsoft" in release_name.lower()
+    wsl_conf = _exists_no_permission_error("/etc/wsl.conf")
+    if not has_wsl_interop and not microsoft_in_release and not wsl_conf:
+        return False
+    if microsoft_in_release:
+        # Release name WSL1 detection
+        if "Microsoft" in release_name:
+            message_on_wsl1_detected(release_name=release_name, 
kernel_version=None)
+            sys.exit(1)
+        return True
+
+    # Kernel WSL1 detection
+    kernel_version: tuple[int, ...] = (0, 0)
+    if len(parts := release_name.split(".", 2)[:2]) == 2:
+        try:
+            kernel_version = tuple(map(int, parts))
+        except (TypeError, ValueError):
+            pass
+    if kernel_version < (4, 19):
+        message_on_wsl1_detected(release_name=None, 
kernel_version=kernel_version)
+        sys.exit(1)
+    return True
diff --git a/dev/breeze/src/airflow_breeze/utils/uv_utils.py 
b/dev/breeze/src/airflow_breeze/utils/uv_utils.py
new file mode 100644
index 0000000000..796c086e3b
--- /dev/null
+++ b/dev/breeze/src/airflow_breeze/utils/uv_utils.py
@@ -0,0 +1,43 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from airflow_breeze.global_constants import DEFAULT_UV_HTTP_TIMEOUT, 
DEFAULT_WSL2_HTTP_TIMEOUT
+
+if TYPE_CHECKING:
+    from airflow_breeze.params.common_build_params import CommonBuildParams
+from airflow_breeze.utils.platforms import is_wsl2
+
+
+def get_uv_timeout(build_params: CommonBuildParams) -> int:
+    """
+    Get the timeout for the uvicorn server. We do not want to change the 
default value to not slow down
+    the --help and command line in general and also it might be useful to give 
escape hatch in case our
+    WSL1 detection is wrong (it will fail default --use-uv build, but you will 
be able to skip the check by
+    manually specifying --uv-http-timeout or --no-use-uv). So we only check 
for wsl2 when default value is
+    used and when uv is enabled.
+    """
+
+    if build_params.uv_http_timeout != DEFAULT_UV_HTTP_TIMEOUT:
+        # a bit of hack: if you specify 300 in command line it will also be 
overridden in case of WSL2
+        # but this is a corner case
+        return build_params.uv_http_timeout
+    if is_wsl2():
+        return DEFAULT_WSL2_HTTP_TIMEOUT
+    return build_params.uv_http_timeout

Reply via email to