snowflake-connector-python 4.4.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- snowflake/connector/__init__.py +118 -0
- snowflake/connector/_query_context_cache.py +276 -0
- snowflake/connector/_sql_util.py +48 -0
- snowflake/connector/_utils.py +353 -0
- snowflake/connector/aio/README.md +88 -0
- snowflake/connector/aio/__init__.py +163 -0
- snowflake/connector/aio/_azure_storage_client.py +227 -0
- snowflake/connector/aio/_bind_upload_agent.py +69 -0
- snowflake/connector/aio/_connection.py +1216 -0
- snowflake/connector/aio/_cursor.py +1402 -0
- snowflake/connector/aio/_description.py +5 -0
- snowflake/connector/aio/_direct_file_operation_utils.py +88 -0
- snowflake/connector/aio/_file_transfer_agent.py +316 -0
- snowflake/connector/aio/_gcs_storage_client.py +360 -0
- snowflake/connector/aio/_network.py +860 -0
- snowflake/connector/aio/_ocsp_asn1crypto.py +51 -0
- snowflake/connector/aio/_ocsp_snowflake.py +608 -0
- snowflake/connector/aio/_pandas_tools.py +561 -0
- snowflake/connector/aio/_result_batch.py +442 -0
- snowflake/connector/aio/_result_set.py +309 -0
- snowflake/connector/aio/_s3_storage_client.py +460 -0
- snowflake/connector/aio/_session_manager.py +588 -0
- snowflake/connector/aio/_storage_client.py +331 -0
- snowflake/connector/aio/_telemetry.py +97 -0
- snowflake/connector/aio/_time_util.py +57 -0
- snowflake/connector/aio/_wif_util.py +324 -0
- snowflake/connector/aio/auth/__init__.py +52 -0
- snowflake/connector/aio/auth/_auth.py +406 -0
- snowflake/connector/aio/auth/_by_plugin.py +131 -0
- snowflake/connector/aio/auth/_default.py +28 -0
- snowflake/connector/aio/auth/_idtoken.py +54 -0
- snowflake/connector/aio/auth/_keypair.py +60 -0
- snowflake/connector/aio/auth/_no_auth.py +31 -0
- snowflake/connector/aio/auth/_oauth.py +27 -0
- snowflake/connector/aio/auth/_oauth_code.py +117 -0
- snowflake/connector/aio/auth/_oauth_credentials.py +100 -0
- snowflake/connector/aio/auth/_okta.py +247 -0
- snowflake/connector/aio/auth/_pat.py +27 -0
- snowflake/connector/aio/auth/_usrpwdmfa.py +30 -0
- snowflake/connector/aio/auth/_webbrowser.py +405 -0
- snowflake/connector/aio/auth/_workload_identity.py +60 -0
- snowflake/connector/arrow_context.py +211 -0
- snowflake/connector/auth/__init__.py +53 -0
- snowflake/connector/auth/_auth.py +669 -0
- snowflake/connector/auth/_http_server.py +257 -0
- snowflake/connector/auth/_oauth_base.py +472 -0
- snowflake/connector/auth/by_plugin.py +219 -0
- snowflake/connector/auth/default.py +36 -0
- snowflake/connector/auth/idtoken.py +72 -0
- snowflake/connector/auth/keypair.py +225 -0
- snowflake/connector/auth/no_auth.py +39 -0
- snowflake/connector/auth/oauth.py +49 -0
- snowflake/connector/auth/oauth_code.py +490 -0
- snowflake/connector/auth/oauth_credentials.py +71 -0
- snowflake/connector/auth/okta.py +339 -0
- snowflake/connector/auth/pat.py +40 -0
- snowflake/connector/auth/usrpwdmfa.py +69 -0
- snowflake/connector/auth/webbrowser.py +514 -0
- snowflake/connector/auth/workload_identity.py +110 -0
- snowflake/connector/azure_storage_client.py +278 -0
- snowflake/connector/backoff_policies.py +141 -0
- snowflake/connector/bind_upload_agent.py +89 -0
- snowflake/connector/cache.py +696 -0
- snowflake/connector/compat.py +127 -0
- snowflake/connector/config_manager.py +553 -0
- snowflake/connector/connection.py +2671 -0
- snowflake/connector/connection_diagnostic.py +793 -0
- snowflake/connector/constants.py +460 -0
- snowflake/connector/converter.py +809 -0
- snowflake/connector/converter_issue23517.py +87 -0
- snowflake/connector/converter_null.py +14 -0
- snowflake/connector/converter_snowsql.py +205 -0
- snowflake/connector/crl.py +919 -0
- snowflake/connector/crl_cache.py +734 -0
- snowflake/connector/cursor.py +2099 -0
- snowflake/connector/dbapi.py +53 -0
- snowflake/connector/description.py +21 -0
- snowflake/connector/direct_file_operation_utils.py +88 -0
- snowflake/connector/encryption_util.py +220 -0
- snowflake/connector/errorcode.py +94 -0
- snowflake/connector/errors.py +666 -0
- snowflake/connector/externals_utils/__init__.py +0 -0
- snowflake/connector/externals_utils/externals_setup.py +30 -0
- snowflake/connector/feature.py +4 -0
- snowflake/connector/file_compression_type.py +118 -0
- snowflake/connector/file_lock.py +72 -0
- snowflake/connector/file_transfer_agent.py +1244 -0
- snowflake/connector/file_util.py +153 -0
- snowflake/connector/gcs_storage_client.py +476 -0
- snowflake/connector/gzip_decoder.py +85 -0
- snowflake/connector/interval_util.py +26 -0
- snowflake/connector/local_storage_client.py +90 -0
- snowflake/connector/log_configuration.py +62 -0
- snowflake/connector/logging_utils/__init__.py +0 -0
- snowflake/connector/logging_utils/filters.py +72 -0
- snowflake/connector/minicore/__init__.py +0 -0
- snowflake/connector/minicore/aix_ppc64/libsf_mini_core.a +0 -0
- snowflake/connector/minicore/aix_ppc64/libsf_mini_core_static.a +0 -0
- snowflake/connector/minicore/linux_aarch64_glibc/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_aarch64_musl/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_x86_64_glibc/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_x86_64_musl/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/macos_aarch64/libsf_mini_core.dylib +0 -0
- snowflake/connector/minicore/macos_x86_64/libsf_mini_core.dylib +0 -0
- snowflake/connector/minicore/windows_x86_64/sf_mini_core.dll +0 -0
- snowflake/connector/minicore/windows_x86_64/sf_mini_core_static.lib +0 -0
- snowflake/connector/nanoarrow_arrow_iterator.cp314-win_amd64.pyd +0 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +570 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1140 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +138 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +75 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +57 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +67 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +262 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
- snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
- snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
- snowflake/connector/network.py +1227 -0
- snowflake/connector/ocsp_asn1crypto.py +447 -0
- snowflake/connector/ocsp_snowflake.py +1939 -0
- snowflake/connector/options.py +179 -0
- snowflake/connector/os_details.py +88 -0
- snowflake/connector/pandas_tools.py +734 -0
- snowflake/connector/platform_detection.py +555 -0
- snowflake/connector/proxy.py +28 -0
- snowflake/connector/py.typed +0 -0
- snowflake/connector/result_batch.py +917 -0
- snowflake/connector/result_set.py +340 -0
- snowflake/connector/s3_storage_client.py +614 -0
- snowflake/connector/secret_detector.py +181 -0
- snowflake/connector/session_manager.py +650 -0
- snowflake/connector/sf_dirs.py +64 -0
- snowflake/connector/sfbinaryformat.py +35 -0
- snowflake/connector/sfdatetime.py +345 -0
- snowflake/connector/snow_logging.py +144 -0
- snowflake/connector/sqlstate.py +9 -0
- snowflake/connector/ssd_internal_keys.py +30 -0
- snowflake/connector/ssl_wrap_socket.py +281 -0
- snowflake/connector/storage_client.py +486 -0
- snowflake/connector/telemetry.py +254 -0
- snowflake/connector/telemetry_oob.py +544 -0
- snowflake/connector/test_util.py +30 -0
- snowflake/connector/time_util.py +159 -0
- snowflake/connector/token_cache.py +457 -0
- snowflake/connector/tool/__init__.py +0 -0
- snowflake/connector/tool/dump_certs.py +57 -0
- snowflake/connector/tool/dump_ocsp_response.py +139 -0
- snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
- snowflake/connector/tool/probe_connection.py +69 -0
- snowflake/connector/url_util.py +55 -0
- snowflake/connector/util_text.py +320 -0
- snowflake/connector/vendored/__init__.py +3 -0
- snowflake/connector/vendored/requests/LICENSE +175 -0
- snowflake/connector/vendored/requests/__init__.py +184 -0
- snowflake/connector/vendored/requests/__version__.py +14 -0
- snowflake/connector/vendored/requests/_internal_utils.py +50 -0
- snowflake/connector/vendored/requests/adapters.py +696 -0
- snowflake/connector/vendored/requests/api.py +157 -0
- snowflake/connector/vendored/requests/auth.py +314 -0
- snowflake/connector/vendored/requests/certs.py +17 -0
- snowflake/connector/vendored/requests/compat.py +106 -0
- snowflake/connector/vendored/requests/cookies.py +561 -0
- snowflake/connector/vendored/requests/exceptions.py +151 -0
- snowflake/connector/vendored/requests/help.py +134 -0
- snowflake/connector/vendored/requests/hooks.py +33 -0
- snowflake/connector/vendored/requests/models.py +1039 -0
- snowflake/connector/vendored/requests/packages.py +23 -0
- snowflake/connector/vendored/requests/sessions.py +831 -0
- snowflake/connector/vendored/requests/status_codes.py +128 -0
- snowflake/connector/vendored/requests/structures.py +99 -0
- snowflake/connector/vendored/requests/utils.py +1086 -0
- snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
- snowflake/connector/vendored/urllib3/__init__.py +211 -0
- snowflake/connector/vendored/urllib3/_base_connection.py +165 -0
- snowflake/connector/vendored/urllib3/_collections.py +487 -0
- snowflake/connector/vendored/urllib3/_request_methods.py +278 -0
- snowflake/connector/vendored/urllib3/_version.py +34 -0
- snowflake/connector/vendored/urllib3/connection.py +1108 -0
- snowflake/connector/vendored/urllib3/connectionpool.py +1178 -0
- snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/__init__.py +17 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/connection.py +260 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/emscripten_fetch_worker.js +110 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/fetch.py +726 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/request.py +22 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/response.py +277 -0
- snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +564 -0
- snowflake/connector/vendored/urllib3/contrib/socks.py +228 -0
- snowflake/connector/vendored/urllib3/exceptions.py +335 -0
- snowflake/connector/vendored/urllib3/fields.py +341 -0
- snowflake/connector/vendored/urllib3/filepost.py +89 -0
- snowflake/connector/vendored/urllib3/http2/__init__.py +53 -0
- snowflake/connector/vendored/urllib3/http2/connection.py +356 -0
- snowflake/connector/vendored/urllib3/http2/probe.py +87 -0
- snowflake/connector/vendored/urllib3/poolmanager.py +651 -0
- snowflake/connector/vendored/urllib3/py.typed +2 -0
- snowflake/connector/vendored/urllib3/response.py +1480 -0
- snowflake/connector/vendored/urllib3/util/__init__.py +42 -0
- snowflake/connector/vendored/urllib3/util/connection.py +137 -0
- snowflake/connector/vendored/urllib3/util/proxy.py +43 -0
- snowflake/connector/vendored/urllib3/util/request.py +263 -0
- snowflake/connector/vendored/urllib3/util/response.py +101 -0
- snowflake/connector/vendored/urllib3/util/retry.py +549 -0
- snowflake/connector/vendored/urllib3/util/ssl_.py +527 -0
- snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
- snowflake/connector/vendored/urllib3/util/ssltransport.py +271 -0
- snowflake/connector/vendored/urllib3/util/timeout.py +275 -0
- snowflake/connector/vendored/urllib3/util/url.py +469 -0
- snowflake/connector/vendored/urllib3/util/util.py +42 -0
- snowflake/connector/vendored/urllib3/util/wait.py +124 -0
- snowflake/connector/version.py +3 -0
- snowflake/connector/wif_util.py +434 -0
- snowflake_connector_python-4.4.0.dist-info/DELVEWHEEL +2 -0
- snowflake_connector_python-4.4.0.dist-info/METADATA +1591 -0
- snowflake_connector_python-4.4.0.dist-info/RECORD +302 -0
- snowflake_connector_python-4.4.0.dist-info/WHEEL +5 -0
- snowflake_connector_python-4.4.0.dist-info/entry_points.txt +4 -0
- snowflake_connector_python-4.4.0.dist-info/licenses/LICENSE.txt +202 -0
- snowflake_connector_python-4.4.0.dist-info/licenses/NOTICE +8 -0
- snowflake_connector_python-4.4.0.dist-info/top_level.txt +1 -0
- snowflake_connector_python.libs/msvcp140-0f885b509a685d2bbfa652fed26b5fb3.dll +0 -0
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
from concurrent.futures import CancelledError as FutureCancelledError
|
|
7
|
+
from concurrent.futures import TimeoutError as FutureTimeoutError
|
|
8
|
+
from concurrent.futures.thread import ThreadPoolExecutor
|
|
9
|
+
from contextlib import contextmanager
|
|
10
|
+
from enum import Enum
|
|
11
|
+
from functools import cache
|
|
12
|
+
|
|
13
|
+
from .constants import (
|
|
14
|
+
ENV_VAR_BOOL_POSITIVE_VALUES_LOWERCASED,
|
|
15
|
+
ENV_VAR_DISABLE_PLATFORM_DETECTION,
|
|
16
|
+
)
|
|
17
|
+
from .options import boto3, botocore, installed_boto
|
|
18
|
+
|
|
19
|
+
if installed_boto:
|
|
20
|
+
Config = botocore.config.Config
|
|
21
|
+
IMDSFetcher = botocore.utils.IMDSFetcher
|
|
22
|
+
|
|
23
|
+
from .session_manager import SessionManager, SessionManagerFactory
|
|
24
|
+
from .vendored.requests import RequestException, Timeout
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
# Loggers to suppress during platform detection to avoid noise in customer logs
|
|
29
|
+
_LOGGERS_TO_SUPPRESS = [
|
|
30
|
+
"snowflake.connector.vendored.urllib3.connectionpool",
|
|
31
|
+
"botocore.utils",
|
|
32
|
+
"botocore.httpsession",
|
|
33
|
+
"urllib3.connectionpool",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@contextmanager
|
|
38
|
+
def _suppress_platform_detection_logs():
|
|
39
|
+
"""
|
|
40
|
+
Context manager to temporarily suppress all logs from underlying HTTP libraries during platform detection.
|
|
41
|
+
|
|
42
|
+
This prevents noisy DEBUG logs and stack traces from urllib3 and botocore when detecting
|
|
43
|
+
cloud platforms, which can confuse customers (SNOW-2204396). Our own debug logs are not affected.
|
|
44
|
+
"""
|
|
45
|
+
original_levels = {}
|
|
46
|
+
try:
|
|
47
|
+
# Completely suppress all logs from noisy libraries
|
|
48
|
+
for logger_name in _LOGGERS_TO_SUPPRESS:
|
|
49
|
+
lib_logger = logging.getLogger(logger_name)
|
|
50
|
+
original_levels[logger_name] = lib_logger.level
|
|
51
|
+
lib_logger.setLevel(logging.CRITICAL + 1) # Above CRITICAL = no logs at all
|
|
52
|
+
yield
|
|
53
|
+
finally:
|
|
54
|
+
# Restore original log levels
|
|
55
|
+
for logger_name, level in original_levels.items():
|
|
56
|
+
logging.getLogger(logger_name).setLevel(level)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class _DetectionState(Enum):
|
|
60
|
+
"""Internal enum to represent the detection state of a platform."""
|
|
61
|
+
|
|
62
|
+
DETECTED = "detected"
|
|
63
|
+
NOT_DETECTED = "not_detected"
|
|
64
|
+
HTTP_TIMEOUT = "timeout"
|
|
65
|
+
WORKER_TIMEOUT = "worker_timeout"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Result returned when platform detection is disabled via environment variable
|
|
69
|
+
_PLATFORM_DETECTION_DISABLED_RESULT = ["disabled"]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def is_ec2_instance(platform_detection_timeout_seconds: float):
|
|
73
|
+
"""
|
|
74
|
+
Check if the current environment is running on an AWS EC2 instance.
|
|
75
|
+
|
|
76
|
+
If we query the AWS Instance Metadata Service (IMDS) for the instance identity document
|
|
77
|
+
and receive content back, then we assume we are running on an EC2 instance.
|
|
78
|
+
This function is compatible with IMDSv1 and IMDSv2 since we send the token in the request.
|
|
79
|
+
It will ignore the token if on IMDSv1 and use the token if on IMDSv2.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
platform_detection_timeout_seconds: Timeout value for the metadata service request.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
_DetectionState: DETECTED if running on EC2, NOT_DETECTED otherwise.
|
|
86
|
+
"""
|
|
87
|
+
if not installed_boto:
|
|
88
|
+
logger.debug("boto3 is not installed, skipping EC2 instance detection")
|
|
89
|
+
return _DetectionState.NOT_DETECTED
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
fetcher = IMDSFetcher(
|
|
93
|
+
timeout=platform_detection_timeout_seconds, num_attempts=1
|
|
94
|
+
)
|
|
95
|
+
document = fetcher._get_request(
|
|
96
|
+
"/latest/dynamic/instance-identity/document",
|
|
97
|
+
None,
|
|
98
|
+
fetcher._fetch_metadata_token(),
|
|
99
|
+
)
|
|
100
|
+
return (
|
|
101
|
+
_DetectionState.DETECTED
|
|
102
|
+
if document.content
|
|
103
|
+
else _DetectionState.NOT_DETECTED
|
|
104
|
+
)
|
|
105
|
+
except Exception:
|
|
106
|
+
return _DetectionState.NOT_DETECTED
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def is_aws_lambda():
|
|
110
|
+
"""
|
|
111
|
+
Check if the current environment is running in AWS Lambda.
|
|
112
|
+
|
|
113
|
+
If we check for the LAMBDA_TASK_ROOT environment variable and it exists,
|
|
114
|
+
then we assume we are running in AWS Lambda.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
_DetectionState: DETECTED if LAMBDA_TASK_ROOT env var exists, NOT_DETECTED otherwise.
|
|
118
|
+
"""
|
|
119
|
+
return (
|
|
120
|
+
_DetectionState.DETECTED
|
|
121
|
+
if "LAMBDA_TASK_ROOT" in os.environ
|
|
122
|
+
else _DetectionState.NOT_DETECTED
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def is_valid_arn_for_wif(arn: str) -> bool:
|
|
127
|
+
"""
|
|
128
|
+
Validate if an AWS ARN is suitable for use with Snowflake's Workload Identity Federation (WIF).
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
arn: The AWS ARN string to validate.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
bool: True if ARN is valid for WIF, False otherwise.
|
|
135
|
+
"""
|
|
136
|
+
patterns = [
|
|
137
|
+
r"^arn:[^:]+:iam::[^:]+:user/.+$",
|
|
138
|
+
r"^arn:[^:]+:sts::[^:]+:assumed-role/.+$",
|
|
139
|
+
]
|
|
140
|
+
return any(re.match(p, arn) for p in patterns)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def has_aws_identity(platform_detection_timeout_seconds: float):
|
|
144
|
+
"""
|
|
145
|
+
Check if the current environment has a valid AWS identity for authentication.
|
|
146
|
+
|
|
147
|
+
If we retrieve an ARN from the caller identity and it is a valid WIF ARN,
|
|
148
|
+
then we assume we have a valid AWS identity for authentication.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
platform_detection_timeout_seconds: Timeout value for AWS API calls.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
_DetectionState: DETECTED if valid AWS identity exists, NOT_DETECTED otherwise.
|
|
155
|
+
"""
|
|
156
|
+
if not installed_boto:
|
|
157
|
+
logger.debug("boto3 is not installed, skipping AWS identity detection")
|
|
158
|
+
return _DetectionState.NOT_DETECTED
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
config = Config(
|
|
162
|
+
connect_timeout=platform_detection_timeout_seconds,
|
|
163
|
+
read_timeout=platform_detection_timeout_seconds,
|
|
164
|
+
retries={"total_max_attempts": 1},
|
|
165
|
+
)
|
|
166
|
+
caller_identity = boto3.client("sts", config=config).get_caller_identity()
|
|
167
|
+
if not caller_identity or "Arn" not in caller_identity:
|
|
168
|
+
return _DetectionState.NOT_DETECTED
|
|
169
|
+
return (
|
|
170
|
+
_DetectionState.DETECTED
|
|
171
|
+
if is_valid_arn_for_wif(caller_identity["Arn"])
|
|
172
|
+
else _DetectionState.NOT_DETECTED
|
|
173
|
+
)
|
|
174
|
+
except Exception:
|
|
175
|
+
return _DetectionState.NOT_DETECTED
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def is_azure_vm(
|
|
179
|
+
platform_detection_timeout_seconds: float, session_manager: SessionManager
|
|
180
|
+
):
|
|
181
|
+
"""
|
|
182
|
+
Check if the current environment is running on an Azure Virtual Machine.
|
|
183
|
+
|
|
184
|
+
If we query the Azure Instance Metadata Service and receive an HTTP 200 response,
|
|
185
|
+
then we assume we are running on an Azure VM.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
platform_detection_timeout_seconds: Timeout value for the metadata service request.
|
|
189
|
+
session_manager: SessionManager instance for making HTTP requests.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
_DetectionState: DETECTED if on Azure VM, HTTP_TIMEOUT if request times out,
|
|
193
|
+
NOT_DETECTED otherwise.
|
|
194
|
+
"""
|
|
195
|
+
try:
|
|
196
|
+
token_resp = session_manager.get(
|
|
197
|
+
"http://169.254.169.254/metadata/instance?api-version=2021-02-01",
|
|
198
|
+
headers={"Metadata": "true"},
|
|
199
|
+
timeout=platform_detection_timeout_seconds,
|
|
200
|
+
)
|
|
201
|
+
return (
|
|
202
|
+
_DetectionState.DETECTED
|
|
203
|
+
if token_resp.status_code == 200
|
|
204
|
+
else _DetectionState.NOT_DETECTED
|
|
205
|
+
)
|
|
206
|
+
except Timeout:
|
|
207
|
+
return _DetectionState.HTTP_TIMEOUT
|
|
208
|
+
except RequestException:
|
|
209
|
+
return _DetectionState.NOT_DETECTED
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def is_azure_function():
|
|
213
|
+
"""
|
|
214
|
+
Check if the current environment is running in Azure Functions.
|
|
215
|
+
|
|
216
|
+
If we check for Azure Functions environment variables (FUNCTIONS_WORKER_RUNTIME,
|
|
217
|
+
FUNCTIONS_EXTENSION_VERSION, AzureWebJobsStorage) and they all exist,
|
|
218
|
+
then we assume we are running in Azure Functions.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
_DetectionState: DETECTED if all Azure Functions env vars are present,
|
|
222
|
+
NOT_DETECTED otherwise.
|
|
223
|
+
"""
|
|
224
|
+
service_vars = [
|
|
225
|
+
"FUNCTIONS_WORKER_RUNTIME",
|
|
226
|
+
"FUNCTIONS_EXTENSION_VERSION",
|
|
227
|
+
"AzureWebJobsStorage",
|
|
228
|
+
]
|
|
229
|
+
return (
|
|
230
|
+
_DetectionState.DETECTED
|
|
231
|
+
if all(var in os.environ for var in service_vars)
|
|
232
|
+
else _DetectionState.NOT_DETECTED
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def is_managed_identity_available_on_azure_vm(
|
|
237
|
+
platform_detection_timeout_seconds,
|
|
238
|
+
session_manager: SessionManager,
|
|
239
|
+
resource="https://management.azure.com",
|
|
240
|
+
):
|
|
241
|
+
"""
|
|
242
|
+
Check if Azure Managed Identity is available and accessible on an Azure VM.
|
|
243
|
+
|
|
244
|
+
If we attempt to mint an access token from the Azure Instance Metadata Service
|
|
245
|
+
managed identity endpoint and receive an HTTP 200 response,
|
|
246
|
+
then we assume managed identity is available.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
platform_detection_timeout_seconds: Timeout value for the metadata service request.
|
|
250
|
+
session_manager: SessionManager instance for making HTTP requests.
|
|
251
|
+
resource: The Azure resource URI to request a token for.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
_DetectionState: DETECTED if managed identity is available, HTTP_TIMEOUT if request
|
|
255
|
+
times out, NOT_DETECTED otherwise.
|
|
256
|
+
"""
|
|
257
|
+
endpoint = f"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource={resource}"
|
|
258
|
+
headers = {"Metadata": "true"}
|
|
259
|
+
try:
|
|
260
|
+
response = session_manager.get(
|
|
261
|
+
endpoint, headers=headers, timeout=platform_detection_timeout_seconds
|
|
262
|
+
)
|
|
263
|
+
return (
|
|
264
|
+
_DetectionState.DETECTED
|
|
265
|
+
if response.status_code == 200
|
|
266
|
+
else _DetectionState.NOT_DETECTED
|
|
267
|
+
)
|
|
268
|
+
except Timeout:
|
|
269
|
+
return _DetectionState.HTTP_TIMEOUT
|
|
270
|
+
except RequestException:
|
|
271
|
+
return _DetectionState.NOT_DETECTED
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def is_managed_identity_available_on_azure_function():
|
|
275
|
+
return bool(os.environ.get("IDENTITY_HEADER"))
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def has_azure_managed_identity(
|
|
279
|
+
platform_detection_timeout_seconds: float, session_manager: SessionManager
|
|
280
|
+
):
|
|
281
|
+
"""
|
|
282
|
+
Determine if Azure Managed Identity is available in the current environment.
|
|
283
|
+
|
|
284
|
+
If we are on Azure Functions and the IDENTITY_HEADER environment variable exists,
|
|
285
|
+
then we assume managed identity is available.
|
|
286
|
+
If we are on an Azure VM and can mint an access token from the managed identity endpoint,
|
|
287
|
+
then we assume managed identity is available.
|
|
288
|
+
Handles Azure Functions first since the checks are faster
|
|
289
|
+
Handles Azure VM checks second since they involve network calls.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
platform_detection_timeout_seconds: Timeout value for managed identity checks.
|
|
293
|
+
session_manager: SessionManager instance for making HTTP requests.
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
_DetectionState: DETECTED if managed identity is available, HTTP_TIMEOUT if
|
|
297
|
+
detection timed out, NOT_DETECTED otherwise.
|
|
298
|
+
"""
|
|
299
|
+
# short circuit early to save on latency and avoid minting an unnecessary token
|
|
300
|
+
if is_azure_function() == _DetectionState.DETECTED:
|
|
301
|
+
return (
|
|
302
|
+
_DetectionState.DETECTED
|
|
303
|
+
if is_managed_identity_available_on_azure_function()
|
|
304
|
+
else _DetectionState.NOT_DETECTED
|
|
305
|
+
)
|
|
306
|
+
return is_managed_identity_available_on_azure_vm(
|
|
307
|
+
platform_detection_timeout_seconds, session_manager
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def is_gce_vm(
|
|
312
|
+
platform_detection_timeout_seconds: float, session_manager: SessionManager
|
|
313
|
+
):
|
|
314
|
+
"""
|
|
315
|
+
Check if the current environment is running on Google Compute Engine (GCE).
|
|
316
|
+
|
|
317
|
+
If we query the Google metadata server and receive a response with the
|
|
318
|
+
"Metadata-Flavor: Google" header, then we assume we are running on GCE.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
platform_detection_timeout_seconds: Timeout value for the metadata service request.
|
|
322
|
+
session_manager: SessionManager instance for making HTTP requests.
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
_DetectionState: DETECTED if on GCE, HTTP_TIMEOUT if request times out,
|
|
326
|
+
NOT_DETECTED otherwise.
|
|
327
|
+
"""
|
|
328
|
+
try:
|
|
329
|
+
response = session_manager.get(
|
|
330
|
+
"http://metadata.google.internal",
|
|
331
|
+
timeout=platform_detection_timeout_seconds,
|
|
332
|
+
)
|
|
333
|
+
return (
|
|
334
|
+
_DetectionState.DETECTED
|
|
335
|
+
if response.headers and response.headers.get("Metadata-Flavor") == "Google"
|
|
336
|
+
else _DetectionState.NOT_DETECTED
|
|
337
|
+
)
|
|
338
|
+
except Timeout:
|
|
339
|
+
return _DetectionState.HTTP_TIMEOUT
|
|
340
|
+
except RequestException:
|
|
341
|
+
return _DetectionState.NOT_DETECTED
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def is_gcp_cloud_run_service():
|
|
345
|
+
"""
|
|
346
|
+
Check if the current environment is running in Google Cloud Run service.
|
|
347
|
+
|
|
348
|
+
If we check for Cloud Run service environment variables (K_SERVICE, K_REVISION,
|
|
349
|
+
K_CONFIGURATION) and they all exist, then we assume we are running in Cloud Run service.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
_DetectionState: DETECTED if all Cloud Run service env vars are present,
|
|
353
|
+
NOT_DETECTED otherwise.
|
|
354
|
+
"""
|
|
355
|
+
service_vars = ["K_SERVICE", "K_REVISION", "K_CONFIGURATION"]
|
|
356
|
+
return (
|
|
357
|
+
_DetectionState.DETECTED
|
|
358
|
+
if all(var in os.environ for var in service_vars)
|
|
359
|
+
else _DetectionState.NOT_DETECTED
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def is_gcp_cloud_run_job():
|
|
364
|
+
"""
|
|
365
|
+
Check if the current environment is running in Google Cloud Run job.
|
|
366
|
+
|
|
367
|
+
If we check for Cloud Run job environment variables (CLOUD_RUN_JOB, CLOUD_RUN_EXECUTION)
|
|
368
|
+
and they both exist, then we assume we are running in a Cloud Run job.
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
_DetectionState: DETECTED if all Cloud Run job env vars are present,
|
|
372
|
+
NOT_DETECTED otherwise.
|
|
373
|
+
"""
|
|
374
|
+
job_vars = ["CLOUD_RUN_JOB", "CLOUD_RUN_EXECUTION"]
|
|
375
|
+
return (
|
|
376
|
+
_DetectionState.DETECTED
|
|
377
|
+
if all(var in os.environ for var in job_vars)
|
|
378
|
+
else _DetectionState.NOT_DETECTED
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def has_gcp_identity(
|
|
383
|
+
platform_detection_timeout_seconds: float, session_manager: SessionManager
|
|
384
|
+
):
|
|
385
|
+
"""
|
|
386
|
+
Check if the current environment has a valid Google Cloud Platform identity.
|
|
387
|
+
|
|
388
|
+
If we query the GCP metadata service for the default service account email
|
|
389
|
+
and receive a non-empty response, then we assume we have a valid GCP identity.
|
|
390
|
+
|
|
391
|
+
Args:
|
|
392
|
+
platform_detection_timeout_seconds: Timeout value for the metadata service request.
|
|
393
|
+
session_manager: SessionManager instance for making HTTP requests.
|
|
394
|
+
Returns:
|
|
395
|
+
_DetectionState: DETECTED if valid GCP identity exists, HTTP_TIMEOUT if request
|
|
396
|
+
times out, NOT_DETECTED otherwise.
|
|
397
|
+
"""
|
|
398
|
+
try:
|
|
399
|
+
response = session_manager.get(
|
|
400
|
+
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email",
|
|
401
|
+
headers={"Metadata-Flavor": "Google"},
|
|
402
|
+
timeout=platform_detection_timeout_seconds,
|
|
403
|
+
)
|
|
404
|
+
return (
|
|
405
|
+
_DetectionState.DETECTED
|
|
406
|
+
if response.status_code == 200
|
|
407
|
+
else _DetectionState.NOT_DETECTED
|
|
408
|
+
)
|
|
409
|
+
except Timeout:
|
|
410
|
+
return _DetectionState.HTTP_TIMEOUT
|
|
411
|
+
except RequestException:
|
|
412
|
+
return _DetectionState.NOT_DETECTED
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def is_github_action():
|
|
416
|
+
"""
|
|
417
|
+
Check if the current environment is running in GitHub Actions.
|
|
418
|
+
|
|
419
|
+
If we check for the GITHUB_ACTIONS environment variable and it exists,
|
|
420
|
+
then we assume we are running in GitHub Actions.
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
_DetectionState: DETECTED if GITHUB_ACTIONS env var exists, NOT_DETECTED otherwise.
|
|
424
|
+
"""
|
|
425
|
+
return (
|
|
426
|
+
_DetectionState.DETECTED
|
|
427
|
+
if "GITHUB_ACTIONS" in os.environ
|
|
428
|
+
else _DetectionState.NOT_DETECTED
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
@cache
|
|
433
|
+
def detect_platforms(
|
|
434
|
+
platform_detection_timeout_seconds: float | None,
|
|
435
|
+
session_manager: SessionManager | None = None,
|
|
436
|
+
) -> list[str]:
|
|
437
|
+
"""
|
|
438
|
+
Detect all potential platforms that the current environment may be running on.
|
|
439
|
+
Swallows all exceptions and returns an empty list if any exception occurs to not affect main driver functionality.
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
platform_detection_timeout_seconds: Timeout value for platform detection requests. Defaults to 0.2 seconds
|
|
443
|
+
if None is provided.
|
|
444
|
+
session_manager: SessionManager instance for making HTTP requests. If None, a new instance will be created.
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
list[str]: List of detected platform names. Platforms that timed out (either HTTP timeout
|
|
448
|
+
or thread timeout) will have "_timeout" suffix appended to their name.
|
|
449
|
+
Returns _PLATFORM_DETECTION_DISABLED_RESULT if the ENV_VAR_DISABLE_PLATFORM_DETECTION
|
|
450
|
+
environment variable is set to a value in ENV_VAR_BOOL_POSITIVE_VALUES_LOWERCASED
|
|
451
|
+
(case-insensitive). Returns empty list if any exception occurs during detection.
|
|
452
|
+
"""
|
|
453
|
+
try:
|
|
454
|
+
# Check if platform detection is disabled via environment variable
|
|
455
|
+
if (
|
|
456
|
+
os.environ.get(ENV_VAR_DISABLE_PLATFORM_DETECTION, "").lower()
|
|
457
|
+
in ENV_VAR_BOOL_POSITIVE_VALUES_LOWERCASED
|
|
458
|
+
):
|
|
459
|
+
logger.debug(
|
|
460
|
+
"Platform detection disabled via %s environment variable",
|
|
461
|
+
ENV_VAR_DISABLE_PLATFORM_DETECTION,
|
|
462
|
+
)
|
|
463
|
+
return _PLATFORM_DETECTION_DISABLED_RESULT
|
|
464
|
+
|
|
465
|
+
if platform_detection_timeout_seconds is None:
|
|
466
|
+
platform_detection_timeout_seconds = 0.2
|
|
467
|
+
|
|
468
|
+
if session_manager is None:
|
|
469
|
+
# This should never happen - we expect session manager to be passed from the outer scope
|
|
470
|
+
logger.debug(
|
|
471
|
+
"No session manager provided. HTTP settings may not be preserved. Using default."
|
|
472
|
+
)
|
|
473
|
+
session_manager = SessionManagerFactory.get_manager(
|
|
474
|
+
use_pooling=False, max_retries=0
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
# HTTP timeout should be slightly shorter than thread timeout to allow HTTP-level
|
|
478
|
+
# timeouts to occur before thread executor times out. This helps distinguish between
|
|
479
|
+
# HTTP_TIMEOUT (network issue) and WORKER_TIMEOUT (thread stuck/hung).
|
|
480
|
+
http_timeout_epsilon = 0.05 # 5% shorter
|
|
481
|
+
http_timeout = platform_detection_timeout_seconds * (1 - http_timeout_epsilon)
|
|
482
|
+
threads_timeout = platform_detection_timeout_seconds
|
|
483
|
+
|
|
484
|
+
# Suppress noisy logs from underlying HTTP libraries during platform detection
|
|
485
|
+
with _suppress_platform_detection_logs():
|
|
486
|
+
# Run environment-only checks synchronously (no network calls, no threading overhead)
|
|
487
|
+
platforms = {
|
|
488
|
+
"is_aws_lambda": is_aws_lambda(),
|
|
489
|
+
"is_azure_function": is_azure_function(),
|
|
490
|
+
"is_gce_cloud_run_service": is_gcp_cloud_run_service(),
|
|
491
|
+
"is_gce_cloud_run_job": is_gcp_cloud_run_job(),
|
|
492
|
+
"is_github_action": is_github_action(),
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
# Run network-calling functions in parallel
|
|
496
|
+
if platform_detection_timeout_seconds != 0.0:
|
|
497
|
+
with ThreadPoolExecutor(max_workers=6) as executor:
|
|
498
|
+
futures = {
|
|
499
|
+
"is_ec2_instance": executor.submit(
|
|
500
|
+
is_ec2_instance, http_timeout
|
|
501
|
+
),
|
|
502
|
+
"has_aws_identity": executor.submit(
|
|
503
|
+
has_aws_identity, http_timeout
|
|
504
|
+
),
|
|
505
|
+
"is_azure_vm": executor.submit(
|
|
506
|
+
is_azure_vm,
|
|
507
|
+
http_timeout,
|
|
508
|
+
session_manager,
|
|
509
|
+
),
|
|
510
|
+
"has_azure_managed_identity": executor.submit(
|
|
511
|
+
has_azure_managed_identity,
|
|
512
|
+
http_timeout,
|
|
513
|
+
session_manager,
|
|
514
|
+
),
|
|
515
|
+
"is_gce_vm": executor.submit(
|
|
516
|
+
is_gce_vm,
|
|
517
|
+
http_timeout,
|
|
518
|
+
session_manager,
|
|
519
|
+
),
|
|
520
|
+
"has_gcp_identity": executor.submit(
|
|
521
|
+
has_gcp_identity,
|
|
522
|
+
http_timeout,
|
|
523
|
+
session_manager,
|
|
524
|
+
),
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
# Enforce timeout at executor level - all parallel detections must complete
|
|
528
|
+
# within threads_timeout
|
|
529
|
+
for key, future in futures.items():
|
|
530
|
+
try:
|
|
531
|
+
platforms[key] = future.result(timeout=threads_timeout)
|
|
532
|
+
except (FutureTimeoutError, FutureCancelledError):
|
|
533
|
+
# Thread/future timed out at executor level
|
|
534
|
+
platforms[key] = _DetectionState.WORKER_TIMEOUT
|
|
535
|
+
except Exception:
|
|
536
|
+
# Any other error from the thread
|
|
537
|
+
platforms[key] = _DetectionState.NOT_DETECTED
|
|
538
|
+
|
|
539
|
+
detected_platforms = []
|
|
540
|
+
for platform_name, detection_state in platforms.items():
|
|
541
|
+
if detection_state == _DetectionState.DETECTED:
|
|
542
|
+
detected_platforms.append(platform_name)
|
|
543
|
+
elif detection_state in (
|
|
544
|
+
_DetectionState.HTTP_TIMEOUT,
|
|
545
|
+
_DetectionState.WORKER_TIMEOUT,
|
|
546
|
+
):
|
|
547
|
+
detected_platforms.append(f"{platform_name}_timeout")
|
|
548
|
+
|
|
549
|
+
logger.debug(
|
|
550
|
+
"Platform detection completed. Detected platforms: %s",
|
|
551
|
+
detected_platforms,
|
|
552
|
+
)
|
|
553
|
+
return detected_platforms
|
|
554
|
+
except Exception:
|
|
555
|
+
return []
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_proxy_url(
|
|
6
|
+
proxy_host: str | None,
|
|
7
|
+
proxy_port: str | None,
|
|
8
|
+
proxy_user: str | None = None,
|
|
9
|
+
proxy_password: str | None = None,
|
|
10
|
+
) -> str | None:
|
|
11
|
+
http_prefix = "http://"
|
|
12
|
+
https_prefix = "https://"
|
|
13
|
+
|
|
14
|
+
if proxy_host and proxy_port:
|
|
15
|
+
if proxy_host.startswith(http_prefix):
|
|
16
|
+
host = proxy_host[len(http_prefix) :]
|
|
17
|
+
elif proxy_host.startswith(https_prefix):
|
|
18
|
+
host = proxy_host[len(https_prefix) :]
|
|
19
|
+
else:
|
|
20
|
+
host = proxy_host
|
|
21
|
+
auth = (
|
|
22
|
+
f"{proxy_user or ''}:{proxy_password or ''}@"
|
|
23
|
+
if proxy_user or proxy_password
|
|
24
|
+
else ""
|
|
25
|
+
)
|
|
26
|
+
return f"{http_prefix}{auth}{host}:{proxy_port}"
|
|
27
|
+
|
|
28
|
+
return None
|
|
File without changes
|