flyte 0.2.0b1__py3-none-any.whl → 2.0.0b46__py3-none-any.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.
- flyte/__init__.py +83 -30
- flyte/_bin/connect.py +61 -0
- flyte/_bin/debug.py +38 -0
- flyte/_bin/runtime.py +87 -19
- flyte/_bin/serve.py +351 -0
- flyte/_build.py +3 -2
- flyte/_cache/cache.py +6 -5
- flyte/_cache/local_cache.py +216 -0
- flyte/_code_bundle/_ignore.py +31 -5
- flyte/_code_bundle/_packaging.py +42 -11
- flyte/_code_bundle/_utils.py +57 -34
- flyte/_code_bundle/bundle.py +130 -27
- flyte/_constants.py +1 -0
- flyte/_context.py +21 -5
- flyte/_custom_context.py +73 -0
- flyte/_debug/constants.py +37 -0
- flyte/_debug/utils.py +17 -0
- flyte/_debug/vscode.py +315 -0
- flyte/_deploy.py +396 -75
- flyte/_deployer.py +109 -0
- flyte/_environment.py +94 -11
- flyte/_excepthook.py +37 -0
- flyte/_group.py +2 -1
- flyte/_hash.py +1 -16
- flyte/_image.py +544 -231
- flyte/_initialize.py +456 -316
- flyte/_interface.py +40 -5
- flyte/_internal/controllers/__init__.py +22 -8
- flyte/_internal/controllers/_local_controller.py +159 -35
- flyte/_internal/controllers/_trace.py +18 -10
- flyte/_internal/controllers/remote/__init__.py +38 -9
- flyte/_internal/controllers/remote/_action.py +82 -12
- flyte/_internal/controllers/remote/_client.py +6 -2
- flyte/_internal/controllers/remote/_controller.py +290 -64
- flyte/_internal/controllers/remote/_core.py +155 -95
- flyte/_internal/controllers/remote/_informer.py +40 -20
- flyte/_internal/controllers/remote/_service_protocol.py +2 -2
- flyte/_internal/imagebuild/__init__.py +2 -10
- flyte/_internal/imagebuild/docker_builder.py +391 -84
- flyte/_internal/imagebuild/image_builder.py +111 -55
- flyte/_internal/imagebuild/remote_builder.py +409 -0
- flyte/_internal/imagebuild/utils.py +79 -0
- flyte/_internal/resolvers/_app_env_module.py +92 -0
- flyte/_internal/resolvers/_task_module.py +5 -38
- flyte/_internal/resolvers/app_env.py +26 -0
- flyte/_internal/resolvers/common.py +8 -1
- flyte/_internal/resolvers/default.py +2 -2
- flyte/_internal/runtime/convert.py +319 -36
- flyte/_internal/runtime/entrypoints.py +106 -18
- flyte/_internal/runtime/io.py +71 -23
- flyte/_internal/runtime/resources_serde.py +21 -7
- flyte/_internal/runtime/reuse.py +125 -0
- flyte/_internal/runtime/rusty.py +196 -0
- flyte/_internal/runtime/task_serde.py +239 -66
- flyte/_internal/runtime/taskrunner.py +48 -8
- flyte/_internal/runtime/trigger_serde.py +162 -0
- flyte/_internal/runtime/types_serde.py +7 -16
- flyte/_keyring/file.py +115 -0
- flyte/_link.py +30 -0
- flyte/_logging.py +241 -42
- flyte/_map.py +312 -0
- flyte/_metrics.py +59 -0
- flyte/_module.py +74 -0
- flyte/_pod.py +30 -0
- flyte/_resources.py +296 -33
- flyte/_retry.py +1 -7
- flyte/_reusable_environment.py +72 -7
- flyte/_run.py +462 -132
- flyte/_secret.py +47 -11
- flyte/_serve.py +333 -0
- flyte/_task.py +245 -56
- flyte/_task_environment.py +219 -97
- flyte/_task_plugins.py +47 -0
- flyte/_tools.py +8 -8
- flyte/_trace.py +15 -24
- flyte/_trigger.py +1027 -0
- flyte/_utils/__init__.py +12 -1
- flyte/_utils/asyn.py +3 -1
- flyte/_utils/async_cache.py +139 -0
- flyte/_utils/coro_management.py +5 -4
- flyte/_utils/description_parser.py +19 -0
- flyte/_utils/docker_credentials.py +173 -0
- flyte/_utils/helpers.py +45 -19
- flyte/_utils/module_loader.py +123 -0
- flyte/_utils/org_discovery.py +57 -0
- flyte/_utils/uv_script_parser.py +8 -1
- flyte/_version.py +16 -3
- flyte/app/__init__.py +27 -0
- flyte/app/_app_environment.py +362 -0
- flyte/app/_connector_environment.py +40 -0
- flyte/app/_deploy.py +130 -0
- flyte/app/_parameter.py +343 -0
- flyte/app/_runtime/__init__.py +3 -0
- flyte/app/_runtime/app_serde.py +383 -0
- flyte/app/_types.py +113 -0
- flyte/app/extras/__init__.py +9 -0
- flyte/app/extras/_auth_middleware.py +217 -0
- flyte/app/extras/_fastapi.py +93 -0
- flyte/app/extras/_model_loader/__init__.py +3 -0
- flyte/app/extras/_model_loader/config.py +7 -0
- flyte/app/extras/_model_loader/loader.py +288 -0
- flyte/cli/__init__.py +12 -0
- flyte/cli/_abort.py +28 -0
- flyte/cli/_build.py +114 -0
- flyte/cli/_common.py +493 -0
- flyte/cli/_create.py +371 -0
- flyte/cli/_delete.py +45 -0
- flyte/cli/_deploy.py +401 -0
- flyte/cli/_gen.py +316 -0
- flyte/cli/_get.py +446 -0
- flyte/cli/_option.py +33 -0
- flyte/{_cli → cli}/_params.py +57 -17
- flyte/cli/_plugins.py +209 -0
- flyte/cli/_prefetch.py +292 -0
- flyte/cli/_run.py +690 -0
- flyte/cli/_serve.py +338 -0
- flyte/cli/_update.py +86 -0
- flyte/cli/_user.py +20 -0
- flyte/cli/main.py +246 -0
- flyte/config/__init__.py +2 -167
- flyte/config/_config.py +215 -163
- flyte/config/_internal.py +10 -1
- flyte/config/_reader.py +225 -0
- flyte/connectors/__init__.py +11 -0
- flyte/connectors/_connector.py +330 -0
- flyte/connectors/_server.py +194 -0
- flyte/connectors/utils.py +159 -0
- flyte/errors.py +134 -2
- flyte/extend.py +24 -0
- flyte/extras/_container.py +69 -56
- flyte/git/__init__.py +3 -0
- flyte/git/_config.py +279 -0
- flyte/io/__init__.py +8 -1
- flyte/io/{structured_dataset → _dataframe}/__init__.py +32 -30
- flyte/io/{structured_dataset → _dataframe}/basic_dfs.py +75 -68
- flyte/io/{structured_dataset/structured_dataset.py → _dataframe/dataframe.py} +207 -242
- flyte/io/_dir.py +575 -113
- flyte/io/_file.py +587 -141
- flyte/io/_hashing_io.py +342 -0
- flyte/io/extend.py +7 -0
- flyte/models.py +635 -0
- flyte/prefetch/__init__.py +22 -0
- flyte/prefetch/_hf_model.py +563 -0
- flyte/remote/__init__.py +14 -3
- flyte/remote/_action.py +879 -0
- flyte/remote/_app.py +346 -0
- flyte/remote/_auth_metadata.py +42 -0
- flyte/remote/_client/_protocols.py +62 -4
- flyte/remote/_client/auth/_auth_utils.py +19 -0
- flyte/remote/_client/auth/_authenticators/base.py +8 -2
- flyte/remote/_client/auth/_authenticators/device_code.py +4 -5
- flyte/remote/_client/auth/_authenticators/factory.py +4 -0
- flyte/remote/_client/auth/_authenticators/passthrough.py +79 -0
- flyte/remote/_client/auth/_authenticators/pkce.py +17 -18
- flyte/remote/_client/auth/_channel.py +47 -18
- flyte/remote/_client/auth/_client_config.py +5 -3
- flyte/remote/_client/auth/_keyring.py +15 -2
- flyte/remote/_client/auth/_token_client.py +3 -3
- flyte/remote/_client/controlplane.py +206 -18
- flyte/remote/_common.py +66 -0
- flyte/remote/_data.py +107 -22
- flyte/remote/_logs.py +116 -33
- flyte/remote/_project.py +21 -19
- flyte/remote/_run.py +164 -631
- flyte/remote/_secret.py +72 -29
- flyte/remote/_task.py +387 -46
- flyte/remote/_trigger.py +368 -0
- flyte/remote/_user.py +43 -0
- flyte/report/_report.py +10 -6
- flyte/storage/__init__.py +13 -1
- flyte/storage/_config.py +237 -0
- flyte/storage/_parallel_reader.py +289 -0
- flyte/storage/_storage.py +268 -59
- flyte/syncify/__init__.py +56 -0
- flyte/syncify/_api.py +414 -0
- flyte/types/__init__.py +39 -0
- flyte/types/_interface.py +22 -7
- flyte/{io/pickle/transformer.py → types/_pickle.py} +37 -9
- flyte/types/_string_literals.py +8 -9
- flyte/types/_type_engine.py +226 -126
- flyte/types/_utils.py +1 -1
- flyte-2.0.0b46.data/scripts/debug.py +38 -0
- flyte-2.0.0b46.data/scripts/runtime.py +194 -0
- flyte-2.0.0b46.dist-info/METADATA +352 -0
- flyte-2.0.0b46.dist-info/RECORD +221 -0
- flyte-2.0.0b46.dist-info/entry_points.txt +8 -0
- flyte-2.0.0b46.dist-info/licenses/LICENSE +201 -0
- flyte/_api_commons.py +0 -3
- flyte/_cli/_common.py +0 -299
- flyte/_cli/_create.py +0 -42
- flyte/_cli/_delete.py +0 -23
- flyte/_cli/_deploy.py +0 -140
- flyte/_cli/_get.py +0 -235
- flyte/_cli/_run.py +0 -174
- flyte/_cli/main.py +0 -98
- flyte/_datastructures.py +0 -342
- flyte/_internal/controllers/pbhash.py +0 -39
- flyte/_protos/common/authorization_pb2.py +0 -66
- flyte/_protos/common/authorization_pb2.pyi +0 -108
- flyte/_protos/common/authorization_pb2_grpc.py +0 -4
- flyte/_protos/common/identifier_pb2.py +0 -71
- flyte/_protos/common/identifier_pb2.pyi +0 -82
- flyte/_protos/common/identifier_pb2_grpc.py +0 -4
- flyte/_protos/common/identity_pb2.py +0 -48
- flyte/_protos/common/identity_pb2.pyi +0 -72
- flyte/_protos/common/identity_pb2_grpc.py +0 -4
- flyte/_protos/common/list_pb2.py +0 -36
- flyte/_protos/common/list_pb2.pyi +0 -69
- flyte/_protos/common/list_pb2_grpc.py +0 -4
- flyte/_protos/common/policy_pb2.py +0 -37
- flyte/_protos/common/policy_pb2.pyi +0 -27
- flyte/_protos/common/policy_pb2_grpc.py +0 -4
- flyte/_protos/common/role_pb2.py +0 -37
- flyte/_protos/common/role_pb2.pyi +0 -53
- flyte/_protos/common/role_pb2_grpc.py +0 -4
- flyte/_protos/common/runtime_version_pb2.py +0 -28
- flyte/_protos/common/runtime_version_pb2.pyi +0 -24
- flyte/_protos/common/runtime_version_pb2_grpc.py +0 -4
- flyte/_protos/logs/dataplane/payload_pb2.py +0 -96
- flyte/_protos/logs/dataplane/payload_pb2.pyi +0 -168
- flyte/_protos/logs/dataplane/payload_pb2_grpc.py +0 -4
- flyte/_protos/secret/definition_pb2.py +0 -49
- flyte/_protos/secret/definition_pb2.pyi +0 -93
- flyte/_protos/secret/definition_pb2_grpc.py +0 -4
- flyte/_protos/secret/payload_pb2.py +0 -62
- flyte/_protos/secret/payload_pb2.pyi +0 -94
- flyte/_protos/secret/payload_pb2_grpc.py +0 -4
- flyte/_protos/secret/secret_pb2.py +0 -38
- flyte/_protos/secret/secret_pb2.pyi +0 -6
- flyte/_protos/secret/secret_pb2_grpc.py +0 -198
- flyte/_protos/secret/secret_pb2_grpc_grpc.py +0 -198
- flyte/_protos/validate/validate/validate_pb2.py +0 -76
- flyte/_protos/workflow/node_execution_service_pb2.py +0 -26
- flyte/_protos/workflow/node_execution_service_pb2.pyi +0 -4
- flyte/_protos/workflow/node_execution_service_pb2_grpc.py +0 -32
- flyte/_protos/workflow/queue_service_pb2.py +0 -106
- flyte/_protos/workflow/queue_service_pb2.pyi +0 -141
- flyte/_protos/workflow/queue_service_pb2_grpc.py +0 -172
- flyte/_protos/workflow/run_definition_pb2.py +0 -128
- flyte/_protos/workflow/run_definition_pb2.pyi +0 -310
- flyte/_protos/workflow/run_definition_pb2_grpc.py +0 -4
- flyte/_protos/workflow/run_logs_service_pb2.py +0 -41
- flyte/_protos/workflow/run_logs_service_pb2.pyi +0 -28
- flyte/_protos/workflow/run_logs_service_pb2_grpc.py +0 -69
- flyte/_protos/workflow/run_service_pb2.py +0 -133
- flyte/_protos/workflow/run_service_pb2.pyi +0 -175
- flyte/_protos/workflow/run_service_pb2_grpc.py +0 -412
- flyte/_protos/workflow/state_service_pb2.py +0 -58
- flyte/_protos/workflow/state_service_pb2.pyi +0 -71
- flyte/_protos/workflow/state_service_pb2_grpc.py +0 -138
- flyte/_protos/workflow/task_definition_pb2.py +0 -72
- flyte/_protos/workflow/task_definition_pb2.pyi +0 -65
- flyte/_protos/workflow/task_definition_pb2_grpc.py +0 -4
- flyte/_protos/workflow/task_service_pb2.py +0 -44
- flyte/_protos/workflow/task_service_pb2.pyi +0 -31
- flyte/_protos/workflow/task_service_pb2_grpc.py +0 -104
- flyte/io/_dataframe.py +0 -0
- flyte/io/pickle/__init__.py +0 -0
- flyte/remote/_console.py +0 -18
- flyte-0.2.0b1.dist-info/METADATA +0 -179
- flyte-0.2.0b1.dist-info/RECORD +0 -204
- flyte-0.2.0b1.dist-info/entry_points.txt +0 -3
- /flyte/{_cli → _debug}/__init__.py +0 -0
- /flyte/{_protos → _keyring}/__init__.py +0 -0
- {flyte-0.2.0b1.dist-info → flyte-2.0.0b46.dist-info}/WHEEL +0 -0
- {flyte-0.2.0b1.dist-info → flyte-2.0.0b46.dist-info}/top_level.txt +0 -0
flyte/_initialize.py
CHANGED
|
@@ -1,261 +1,28 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import datetime
|
|
4
3
|
import functools
|
|
5
|
-
import
|
|
4
|
+
import sys
|
|
6
5
|
import threading
|
|
7
6
|
import typing
|
|
8
|
-
from dataclasses import dataclass, replace
|
|
9
|
-
from datetime import timedelta
|
|
7
|
+
from dataclasses import dataclass, field, replace
|
|
10
8
|
from pathlib import Path
|
|
11
|
-
from typing import TYPE_CHECKING,
|
|
9
|
+
from typing import TYPE_CHECKING, Callable, List, Literal, Optional, TypeVar
|
|
12
10
|
|
|
13
11
|
from flyte.errors import InitializationError
|
|
12
|
+
from flyte.syncify import syncify
|
|
14
13
|
|
|
15
|
-
from .
|
|
16
|
-
from ._logging import initialize_logger
|
|
17
|
-
from ._tools import ipython_check
|
|
14
|
+
from ._logging import LogFormat, initialize_logger, logger
|
|
18
15
|
|
|
19
16
|
if TYPE_CHECKING:
|
|
17
|
+
from flyte._internal.imagebuild import ImageBuildEngine
|
|
20
18
|
from flyte.config import Config
|
|
21
19
|
from flyte.remote._client.auth import AuthType, ClientConfig
|
|
22
20
|
from flyte.remote._client.controlplane import ClientSet
|
|
21
|
+
from flyte.storage import Storage
|
|
23
22
|
|
|
24
23
|
Mode = Literal["local", "remote"]
|
|
25
24
|
|
|
26
25
|
|
|
27
|
-
def set_if_exists(d: dict, k: str, val: typing.Any) -> dict:
|
|
28
|
-
"""
|
|
29
|
-
Given a dict ``d`` sets the key ``k`` with value of config ``v``, if the config value ``v`` is set
|
|
30
|
-
and return the updated dictionary.
|
|
31
|
-
"""
|
|
32
|
-
exists = isinstance(val, bool) or bool(val is not None and val)
|
|
33
|
-
if exists:
|
|
34
|
-
d[k] = val
|
|
35
|
-
return d
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@dataclass(init=True, repr=True, eq=True, frozen=True)
|
|
39
|
-
class Storage(object):
|
|
40
|
-
"""
|
|
41
|
-
Data storage configuration that applies across any provider.
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
retries: int = 3
|
|
45
|
-
backoff: datetime.timedelta = datetime.timedelta(seconds=5)
|
|
46
|
-
enable_debug: bool = False
|
|
47
|
-
attach_execution_metadata: bool = True
|
|
48
|
-
|
|
49
|
-
_KEY_ENV_VAR_MAPPING: ClassVar[typing.Dict[str, str]] = {
|
|
50
|
-
"enable_debug": "UNION_STORAGE_DEBUG",
|
|
51
|
-
"retries": "UNION_STORAGE_RETRIES",
|
|
52
|
-
"backoff": "UNION_STORAGE_BACKOFF_SECONDS",
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
def get_fsspec_kwargs(self, anonymous: bool = False, /, **kwargs) -> Dict[str, Any]:
|
|
56
|
-
"""
|
|
57
|
-
Returns the configuration as kwargs for constructing an fsspec filesystem.
|
|
58
|
-
"""
|
|
59
|
-
return {}
|
|
60
|
-
|
|
61
|
-
@classmethod
|
|
62
|
-
def _auto_as_kwargs(cls) -> Dict[str, Any]:
|
|
63
|
-
retries = os.getenv(cls._KEY_ENV_VAR_MAPPING["retries"])
|
|
64
|
-
backoff = os.getenv(cls._KEY_ENV_VAR_MAPPING["backoff"])
|
|
65
|
-
enable_debug = os.getenv(cls._KEY_ENV_VAR_MAPPING["enable_debug"])
|
|
66
|
-
|
|
67
|
-
kwargs: Dict[str, Any] = {}
|
|
68
|
-
kwargs = set_if_exists(kwargs, "enable_debug", enable_debug)
|
|
69
|
-
kwargs = set_if_exists(kwargs, "retries", retries)
|
|
70
|
-
kwargs = set_if_exists(kwargs, "backoff", backoff)
|
|
71
|
-
return kwargs
|
|
72
|
-
|
|
73
|
-
@classmethod
|
|
74
|
-
def auto(cls) -> Storage:
|
|
75
|
-
"""
|
|
76
|
-
Construct the config object automatically from environment variables.
|
|
77
|
-
"""
|
|
78
|
-
return cls(**cls._auto_as_kwargs())
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@dataclass(init=True, repr=True, eq=True, frozen=True)
|
|
82
|
-
class S3(Storage):
|
|
83
|
-
"""
|
|
84
|
-
S3 specific configuration
|
|
85
|
-
"""
|
|
86
|
-
|
|
87
|
-
endpoint: typing.Optional[str] = None
|
|
88
|
-
access_key_id: typing.Optional[str] = None
|
|
89
|
-
secret_access_key: typing.Optional[str] = None
|
|
90
|
-
|
|
91
|
-
_KEY_ENV_VAR_MAPPING: ClassVar[typing.Dict[str, str]] = {
|
|
92
|
-
"endpoint": "FLYTE_AWS_ENDPOINT",
|
|
93
|
-
"access_key_id": "FLYTE_AWS_ACCESS_KEY_ID",
|
|
94
|
-
"secret_access_key": "FLYTE_AWS_SECRET_ACCESS_KEY",
|
|
95
|
-
} | Storage._KEY_ENV_VAR_MAPPING
|
|
96
|
-
|
|
97
|
-
# Refer to https://github.com/developmentseed/obstore/blob/33654fc37f19a657689eb93327b621e9f9e01494/obstore/python/obstore/store/_aws.pyi#L11
|
|
98
|
-
# for key and secret
|
|
99
|
-
_CONFIG_KEY_FSSPEC_S3_KEY_ID: ClassVar = "access_key_id"
|
|
100
|
-
_CONFIG_KEY_FSSPEC_S3_SECRET: ClassVar = "secret_access_key"
|
|
101
|
-
_CONFIG_KEY_ENDPOINT: ClassVar = "endpoint_url"
|
|
102
|
-
_KEY_SKIP_SIGNATURE: ClassVar = "skip_signature"
|
|
103
|
-
|
|
104
|
-
@classmethod
|
|
105
|
-
def auto(cls) -> S3:
|
|
106
|
-
"""
|
|
107
|
-
:return: Config
|
|
108
|
-
"""
|
|
109
|
-
endpoint = os.getenv(cls._KEY_ENV_VAR_MAPPING["endpoint"], None)
|
|
110
|
-
access_key_id = os.getenv(cls._KEY_ENV_VAR_MAPPING["access_key_id"], None)
|
|
111
|
-
secret_access_key = os.getenv(cls._KEY_ENV_VAR_MAPPING["secret_access_key"], None)
|
|
112
|
-
|
|
113
|
-
kwargs = super()._auto_as_kwargs()
|
|
114
|
-
kwargs = set_if_exists(kwargs, "endpoint", endpoint)
|
|
115
|
-
kwargs = set_if_exists(kwargs, "access_key_id", access_key_id)
|
|
116
|
-
kwargs = set_if_exists(kwargs, "secret_access_key", secret_access_key)
|
|
117
|
-
|
|
118
|
-
return S3(**kwargs)
|
|
119
|
-
|
|
120
|
-
@classmethod
|
|
121
|
-
def for_sandbox(cls) -> S3:
|
|
122
|
-
"""
|
|
123
|
-
:return:
|
|
124
|
-
"""
|
|
125
|
-
kwargs = super()._auto_as_kwargs()
|
|
126
|
-
final_kwargs = kwargs | {
|
|
127
|
-
"endpoint": "http://localhost:4566",
|
|
128
|
-
"access_key_id": "minio",
|
|
129
|
-
"secret_access_key": "miniostorage",
|
|
130
|
-
}
|
|
131
|
-
return S3(**final_kwargs)
|
|
132
|
-
|
|
133
|
-
def get_fsspec_kwargs(self, anonymous: bool = False, /, **kwargs) -> Dict[str, Any]:
|
|
134
|
-
# Construct the config object
|
|
135
|
-
config: Dict[str, Any] = {}
|
|
136
|
-
if self._CONFIG_KEY_FSSPEC_S3_KEY_ID in kwargs or self.access_key_id:
|
|
137
|
-
config[self._CONFIG_KEY_FSSPEC_S3_KEY_ID] = kwargs.pop(
|
|
138
|
-
self._CONFIG_KEY_FSSPEC_S3_KEY_ID, self.access_key_id
|
|
139
|
-
)
|
|
140
|
-
if self._CONFIG_KEY_FSSPEC_S3_SECRET in kwargs or self.secret_access_key:
|
|
141
|
-
config[self._CONFIG_KEY_FSSPEC_S3_SECRET] = kwargs.pop(
|
|
142
|
-
self._CONFIG_KEY_FSSPEC_S3_SECRET, self.secret_access_key
|
|
143
|
-
)
|
|
144
|
-
if self._CONFIG_KEY_ENDPOINT in kwargs or self.endpoint:
|
|
145
|
-
config["endpoint_url"] = kwargs.pop(self._CONFIG_KEY_ENDPOINT, self.endpoint)
|
|
146
|
-
|
|
147
|
-
retries = kwargs.pop("retries", self.retries)
|
|
148
|
-
backoff = kwargs.pop("backoff", self.backoff)
|
|
149
|
-
|
|
150
|
-
if anonymous:
|
|
151
|
-
config[self._KEY_SKIP_SIGNATURE] = True
|
|
152
|
-
|
|
153
|
-
retry_config = {
|
|
154
|
-
"max_retries": retries,
|
|
155
|
-
"backoff": {
|
|
156
|
-
"base": 2,
|
|
157
|
-
"init_backoff": backoff,
|
|
158
|
-
"max_backoff": timedelta(seconds=16),
|
|
159
|
-
},
|
|
160
|
-
"retry_timeout": timedelta(minutes=3),
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
client_options = {"timeout": "99999s", "allow_http": True}
|
|
164
|
-
|
|
165
|
-
if config:
|
|
166
|
-
kwargs["config"] = config
|
|
167
|
-
kwargs["client_options"] = client_options or None
|
|
168
|
-
kwargs["retry_config"] = retry_config or None
|
|
169
|
-
|
|
170
|
-
return kwargs
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
@dataclass(init=True, repr=True, eq=True, frozen=True)
|
|
174
|
-
class GCS(Storage):
|
|
175
|
-
"""
|
|
176
|
-
Any GCS specific configuration.
|
|
177
|
-
"""
|
|
178
|
-
|
|
179
|
-
gsutil_parallelism: bool = False
|
|
180
|
-
|
|
181
|
-
_KEY_ENV_VAR_MAPPING: ClassVar[dict[str, str]] = {
|
|
182
|
-
"gsutil_parallelism": "GCP_GSUTIL_PARALLELISM",
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
@classmethod
|
|
186
|
-
def auto(cls) -> GCS:
|
|
187
|
-
gsutil_parallelism = os.getenv(cls._KEY_ENV_VAR_MAPPING["gsutil_parallelism"], None)
|
|
188
|
-
|
|
189
|
-
kwargs: Dict[str, Any] = {}
|
|
190
|
-
kwargs = set_if_exists(kwargs, "gsutil_parallelism", gsutil_parallelism)
|
|
191
|
-
return GCS(**kwargs)
|
|
192
|
-
|
|
193
|
-
def get_fsspec_kwargs(self, anonymous: bool = False, /, **kwargs) -> Dict[str, Any]:
|
|
194
|
-
return kwargs
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
@dataclass(init=True, repr=True, eq=True, frozen=True)
|
|
198
|
-
class ABFS(Storage):
|
|
199
|
-
"""
|
|
200
|
-
Any Azure Blob Storage specific configuration.
|
|
201
|
-
"""
|
|
202
|
-
|
|
203
|
-
account_name: typing.Optional[str] = None
|
|
204
|
-
account_key: typing.Optional[str] = None
|
|
205
|
-
tenant_id: typing.Optional[str] = None
|
|
206
|
-
client_id: typing.Optional[str] = None
|
|
207
|
-
client_secret: typing.Optional[str] = None
|
|
208
|
-
|
|
209
|
-
_KEY_ENV_VAR_MAPPING: ClassVar[dict[str, str]] = {
|
|
210
|
-
"account_name": "AZURE_STORAGE_ACCOUNT_NAME",
|
|
211
|
-
"account_key": "AZURE_STORAGE_ACCOUNT_KEY",
|
|
212
|
-
"tenant_id": "AZURE_TENANT_ID",
|
|
213
|
-
"client_id": "AZURE_CLIENT_ID",
|
|
214
|
-
"client_secret": "AZURE_CLIENT_SECRET",
|
|
215
|
-
}
|
|
216
|
-
_KEY_SKIP_SIGNATURE: ClassVar = "skip_signature"
|
|
217
|
-
|
|
218
|
-
@classmethod
|
|
219
|
-
def auto(cls) -> ABFS:
|
|
220
|
-
account_name = os.getenv(cls._KEY_ENV_VAR_MAPPING["account_name"], None)
|
|
221
|
-
account_key = os.getenv(cls._KEY_ENV_VAR_MAPPING["account_key"], None)
|
|
222
|
-
tenant_id = os.getenv(cls._KEY_ENV_VAR_MAPPING["tenant_id"], None)
|
|
223
|
-
client_id = os.getenv(cls._KEY_ENV_VAR_MAPPING["client_id"], None)
|
|
224
|
-
client_secret = os.getenv(cls._KEY_ENV_VAR_MAPPING["client_secret"], None)
|
|
225
|
-
|
|
226
|
-
kwargs: Dict[str, Any] = {}
|
|
227
|
-
kwargs = set_if_exists(kwargs, "account_name", account_name)
|
|
228
|
-
kwargs = set_if_exists(kwargs, "account_key", account_key)
|
|
229
|
-
kwargs = set_if_exists(kwargs, "tenant_id", tenant_id)
|
|
230
|
-
kwargs = set_if_exists(kwargs, "client_id", client_id)
|
|
231
|
-
kwargs = set_if_exists(kwargs, "client_secret", client_secret)
|
|
232
|
-
return ABFS(**kwargs)
|
|
233
|
-
|
|
234
|
-
def get_fsspec_kwargs(self, anonymous: bool = False, /, **kwargs) -> Dict[str, Any]:
|
|
235
|
-
config: Dict[str, Any] = {}
|
|
236
|
-
if "account_name" in kwargs or self.account_name:
|
|
237
|
-
config["account_name"] = kwargs.get("account_name", self.account_name)
|
|
238
|
-
if "account_key" in kwargs or self.account_key:
|
|
239
|
-
config["account_key"] = kwargs.get("account_key", self.account_key)
|
|
240
|
-
if "client_id" in kwargs or self.client_id:
|
|
241
|
-
config["client_id"] = kwargs.get("client_id", self.client_id)
|
|
242
|
-
if "client_secret" in kwargs or self.client_secret:
|
|
243
|
-
config["client_secret"] = kwargs.get("client_secret", self.client_secret)
|
|
244
|
-
if "tenant_id" in kwargs or self.tenant_id:
|
|
245
|
-
config["tenant_id"] = kwargs.get("tenant_id", self.tenant_id)
|
|
246
|
-
|
|
247
|
-
if anonymous:
|
|
248
|
-
config[self._KEY_SKIP_SIGNATURE] = True
|
|
249
|
-
|
|
250
|
-
client_options = {"timeout": "99999s", "allow_http": "true"}
|
|
251
|
-
|
|
252
|
-
if config:
|
|
253
|
-
kwargs["config"] = config
|
|
254
|
-
kwargs["client_options"] = client_options
|
|
255
|
-
|
|
256
|
-
return kwargs
|
|
257
|
-
|
|
258
|
-
|
|
259
26
|
@dataclass(init=True, repr=True, eq=True, frozen=True, kw_only=True)
|
|
260
27
|
class CommonInit:
|
|
261
28
|
"""
|
|
@@ -266,12 +33,17 @@ class CommonInit:
|
|
|
266
33
|
org: str | None = None
|
|
267
34
|
project: str | None = None
|
|
268
35
|
domain: str | None = None
|
|
36
|
+
batch_size: int = 1000
|
|
37
|
+
source_config_path: Optional[Path] = None # Only used for documentation
|
|
38
|
+
sync_local_sys_paths: bool = True
|
|
269
39
|
|
|
270
40
|
|
|
271
41
|
@dataclass(init=True, kw_only=True, repr=True, eq=True, frozen=True)
|
|
272
42
|
class _InitConfig(CommonInit):
|
|
273
43
|
client: Optional[ClientSet] = None
|
|
274
44
|
storage: Optional[Storage] = None
|
|
45
|
+
image_builder: "ImageBuildEngine.ImageBuilderType" = "local"
|
|
46
|
+
images: typing.Dict[str, str] = field(default_factory=dict)
|
|
275
47
|
|
|
276
48
|
def replace(self, **kwargs) -> _InitConfig:
|
|
277
49
|
return replace(self, **kwargs)
|
|
@@ -304,11 +76,19 @@ async def _initialize_client(
|
|
|
304
76
|
"""
|
|
305
77
|
from flyte.remote._client.controlplane import ClientSet
|
|
306
78
|
|
|
307
|
-
|
|
79
|
+
# https://grpc.io/docs/guides/keepalive/#keepalive-configuration-specification
|
|
80
|
+
channel_options = [
|
|
81
|
+
("grpc.keepalive_permit_without_calls", 1),
|
|
82
|
+
("grpc.keepalive_time_ms", 30000), # Send keepalive ping every 30 seconds
|
|
83
|
+
("grpc.keepalive_timeout_ms", 10000), # Wait 10 seconds for keepalive response
|
|
84
|
+
("grpc.http2.max_pings_without_data", 0), # Allow unlimited pings without data
|
|
85
|
+
("grpc.http2.min_ping_interval_without_data_ms", 30000), # Min 30s between pings
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
if endpoint and api_key is None:
|
|
308
89
|
return await ClientSet.for_endpoint(
|
|
309
90
|
endpoint,
|
|
310
91
|
insecure=insecure,
|
|
311
|
-
api_key=api_key,
|
|
312
92
|
insecure_skip_verify=insecure_skip_verify,
|
|
313
93
|
auth_type=auth_type,
|
|
314
94
|
headless=headless,
|
|
@@ -320,17 +100,46 @@ async def _initialize_client(
|
|
|
320
100
|
client_config=client_config,
|
|
321
101
|
rpc_retries=rpc_retries,
|
|
322
102
|
http_proxy_url=http_proxy_url,
|
|
103
|
+
grpc_options=channel_options,
|
|
323
104
|
)
|
|
324
|
-
|
|
105
|
+
elif api_key:
|
|
106
|
+
return await ClientSet.for_api_key(
|
|
107
|
+
api_key,
|
|
108
|
+
insecure=insecure,
|
|
109
|
+
insecure_skip_verify=insecure_skip_verify,
|
|
110
|
+
auth_type=auth_type,
|
|
111
|
+
headless=headless,
|
|
112
|
+
ca_cert_file_path=ca_cert_file_path,
|
|
113
|
+
command=command,
|
|
114
|
+
proxy_command=proxy_command,
|
|
115
|
+
client_id=client_id,
|
|
116
|
+
client_credentials_secret=client_credentials_secret,
|
|
117
|
+
client_config=client_config,
|
|
118
|
+
rpc_retries=rpc_retries,
|
|
119
|
+
http_proxy_url=http_proxy_url,
|
|
120
|
+
grpc_options=channel_options,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
raise InitializationError(
|
|
124
|
+
"MissingEndpointOrApiKeyError", "user", "Either endpoint or api_key must be provided to initialize the client."
|
|
125
|
+
)
|
|
325
126
|
|
|
326
127
|
|
|
327
|
-
|
|
128
|
+
def _initialize_logger(
|
|
129
|
+
log_level: int | None = None, log_format: LogFormat | None = None, reset_root_logger: bool = False
|
|
130
|
+
) -> None:
|
|
131
|
+
initialize_logger(log_level=log_level, log_format=log_format, enable_rich=True, reset_root_logger=reset_root_logger)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@syncify
|
|
328
135
|
async def init(
|
|
329
136
|
org: str | None = None,
|
|
330
137
|
project: str | None = None,
|
|
331
138
|
domain: str | None = None,
|
|
332
139
|
root_dir: Path | None = None,
|
|
333
140
|
log_level: int | None = None,
|
|
141
|
+
log_format: LogFormat | None = None,
|
|
142
|
+
reset_root_logger: bool = False,
|
|
334
143
|
endpoint: str | None = None,
|
|
335
144
|
headless: bool = False,
|
|
336
145
|
insecure: bool = False,
|
|
@@ -346,7 +155,12 @@ async def init(
|
|
|
346
155
|
rpc_retries: int = 3,
|
|
347
156
|
http_proxy_url: str | None = None,
|
|
348
157
|
storage: Storage | None = None,
|
|
349
|
-
|
|
158
|
+
batch_size: int = 1000,
|
|
159
|
+
image_builder: ImageBuildEngine.ImageBuilderType = "local",
|
|
160
|
+
images: typing.Dict[str, str] | None = None,
|
|
161
|
+
source_config_path: Optional[Path] = None,
|
|
162
|
+
sync_local_sys_paths: bool = True,
|
|
163
|
+
load_plugin_type_transformers: bool = True,
|
|
350
164
|
) -> None:
|
|
351
165
|
"""
|
|
352
166
|
Initialize the Flyte system with the given configuration. This method should be called before any other Flyte
|
|
@@ -355,14 +169,15 @@ async def init(
|
|
|
355
169
|
:param project: Optional project name (not used in this implementation)
|
|
356
170
|
:param domain: Optional domain name (not used in this implementation)
|
|
357
171
|
:param root_dir: Optional root directory from which to determine how to load files, and find paths to files.
|
|
172
|
+
This is useful for determining the root directory for the current project, and for locating files like config etc.
|
|
173
|
+
also use to determine all the code that needs to be copied to the remote location.
|
|
358
174
|
defaults to the editable install directory if the cwd is in a Python editable install, else just the cwd.
|
|
359
175
|
:param log_level: Optional logging level for the logger, default is set using the default initialization policies
|
|
176
|
+
:param log_format: Optional logging format for the logger, default is "console"
|
|
177
|
+
:param reset_root_logger: By default, we clear out root logger handlers and set up our own.
|
|
360
178
|
:param api_key: Optional API key for authentication
|
|
361
179
|
:param endpoint: Optional API endpoint URL
|
|
362
180
|
:param headless: Optional Whether to run in headless mode
|
|
363
|
-
:param mode: Optional execution model (local, remote). Default is local. When local is used,
|
|
364
|
-
the execution will be done locally. When remote is used, the execution will be sent to a remote server,
|
|
365
|
-
In the remote case, the endpoint or api_key must be set.
|
|
366
181
|
:param insecure_skip_verify: Whether to skip SSL certificate verification
|
|
367
182
|
:param auth_client_config: Optional client configuration for authentication
|
|
368
183
|
:param auth_type: The authentication type to use (Pkce, ClientSecret, ExternalCommand, DeviceFlow)
|
|
@@ -376,61 +191,338 @@ async def init(
|
|
|
376
191
|
:param ca_cert_file_path: [optional] str Root Cert to be loaded and used to verify admin
|
|
377
192
|
:param http_proxy_url: [optional] HTTP Proxy to be used for OAuth requests
|
|
378
193
|
:param rpc_retries: [optional] int Number of times to retry the platform calls
|
|
379
|
-
:param audience: oauth2 audience for the token request. This is used to validate the token
|
|
380
194
|
:param insecure: insecure flag for the client
|
|
381
195
|
:param storage: Optional blob store (S3, GCS, Azure) configuration if needed to access (i.e. using Minio)
|
|
382
196
|
:param org: Optional organization override for the client. Should be set by auth instead.
|
|
383
|
-
:param
|
|
384
|
-
|
|
197
|
+
:param batch_size: Optional batch size for operations that use listings, defaults to 1000, so limit larger than
|
|
198
|
+
batch_size will be split into multiple requests.
|
|
199
|
+
:param image_builder: Optional image builder configuration, if not provided, the default image builder will be used.
|
|
200
|
+
:param images: Optional dict of images that can be used by referencing the image name.
|
|
201
|
+
:param source_config_path: Optional path to the source configuration file (This is only used for documentation)
|
|
202
|
+
:param sync_local_sys_paths: Whether to include and synchronize local sys.path entries under the root directory
|
|
203
|
+
into the remote container (default: True).
|
|
204
|
+
:param load_plugin_type_transformers: If enabled (default True), load the type transformer plugins registered under
|
|
205
|
+
the "flyte.plugins.types" entry point group.
|
|
385
206
|
:return: None
|
|
386
207
|
"""
|
|
387
|
-
from flyte._utils import get_cwd_editable_install
|
|
208
|
+
from flyte._utils import get_cwd_editable_install, org_from_endpoint, sanitize_endpoint
|
|
209
|
+
from flyte.types import _load_custom_type_transformers
|
|
388
210
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if log_level:
|
|
393
|
-
initialize_logger(log_level=log_level, enable_rich=interactive_mode)
|
|
211
|
+
_initialize_logger(log_level=log_level, log_format=log_format, reset_root_logger=reset_root_logger)
|
|
212
|
+
if load_plugin_type_transformers:
|
|
213
|
+
_load_custom_type_transformers()
|
|
394
214
|
|
|
395
215
|
global _init_config # noqa: PLW0603
|
|
396
216
|
|
|
397
|
-
|
|
398
|
-
if config is None:
|
|
399
|
-
from flyte.config import Config
|
|
217
|
+
endpoint = sanitize_endpoint(endpoint)
|
|
400
218
|
|
|
401
|
-
|
|
402
|
-
platform_cfg = config.platform
|
|
403
|
-
task_cfg = config.task
|
|
219
|
+
with _init_lock:
|
|
404
220
|
client = None
|
|
405
|
-
if endpoint or
|
|
221
|
+
if endpoint or api_key:
|
|
406
222
|
client = await _initialize_client(
|
|
407
223
|
api_key=api_key,
|
|
408
|
-
auth_type=auth_type
|
|
409
|
-
endpoint=endpoint
|
|
224
|
+
auth_type=auth_type,
|
|
225
|
+
endpoint=endpoint,
|
|
410
226
|
headless=headless,
|
|
411
|
-
insecure=insecure
|
|
412
|
-
insecure_skip_verify=insecure_skip_verify
|
|
413
|
-
ca_cert_file_path=ca_cert_file_path
|
|
414
|
-
command=command
|
|
415
|
-
proxy_command=proxy_command
|
|
416
|
-
client_id=client_id
|
|
417
|
-
client_credentials_secret=client_credentials_secret
|
|
227
|
+
insecure=insecure,
|
|
228
|
+
insecure_skip_verify=insecure_skip_verify,
|
|
229
|
+
ca_cert_file_path=ca_cert_file_path,
|
|
230
|
+
command=command,
|
|
231
|
+
proxy_command=proxy_command,
|
|
232
|
+
client_id=client_id,
|
|
233
|
+
client_credentials_secret=client_credentials_secret,
|
|
418
234
|
client_config=auth_client_config,
|
|
419
|
-
rpc_retries=rpc_retries
|
|
420
|
-
http_proxy_url=http_proxy_url
|
|
235
|
+
rpc_retries=rpc_retries,
|
|
236
|
+
http_proxy_url=http_proxy_url,
|
|
421
237
|
)
|
|
422
238
|
|
|
423
|
-
|
|
239
|
+
if not root_dir:
|
|
240
|
+
editable_root = get_cwd_editable_install()
|
|
241
|
+
if editable_root:
|
|
242
|
+
logger.info(f"Using editable install as root directory: {editable_root}")
|
|
243
|
+
root_dir = editable_root
|
|
244
|
+
else:
|
|
245
|
+
logger.info("No editable install found, using current working directory as root directory.")
|
|
246
|
+
root_dir = Path.cwd()
|
|
247
|
+
# We will inject the root_dir into the sys,path for module resolution
|
|
248
|
+
sys.path.append(str(root_dir))
|
|
249
|
+
|
|
424
250
|
_init_config = _InitConfig(
|
|
425
251
|
root_dir=root_dir,
|
|
426
|
-
project=project
|
|
427
|
-
domain=domain
|
|
252
|
+
project=project,
|
|
253
|
+
domain=domain,
|
|
428
254
|
client=client,
|
|
429
255
|
storage=storage,
|
|
430
|
-
org=org or
|
|
256
|
+
org=org or org_from_endpoint(endpoint),
|
|
257
|
+
batch_size=batch_size,
|
|
258
|
+
image_builder=image_builder,
|
|
259
|
+
images=images or {},
|
|
260
|
+
source_config_path=source_config_path,
|
|
261
|
+
sync_local_sys_paths=sync_local_sys_paths,
|
|
431
262
|
)
|
|
432
263
|
|
|
433
264
|
|
|
265
|
+
@syncify
|
|
266
|
+
async def init_from_config(
|
|
267
|
+
path_or_config: str | Path | Config | None = None,
|
|
268
|
+
root_dir: Path | None = None,
|
|
269
|
+
log_level: int | None = None,
|
|
270
|
+
log_format: LogFormat = "console",
|
|
271
|
+
project: str | None = None,
|
|
272
|
+
domain: str | None = None,
|
|
273
|
+
storage: Storage | None = None,
|
|
274
|
+
batch_size: int = 1000,
|
|
275
|
+
image_builder: ImageBuildEngine.ImageBuilderType | None = None,
|
|
276
|
+
images: tuple[str, ...] | None = None,
|
|
277
|
+
sync_local_sys_paths: bool = True,
|
|
278
|
+
) -> None:
|
|
279
|
+
"""
|
|
280
|
+
Initialize the Flyte system using a configuration file or Config object. This method should be called before any
|
|
281
|
+
other Flyte remote API methods are called. Thread-safe implementation.
|
|
282
|
+
|
|
283
|
+
:param path_or_config: Path to the configuration file or Config object
|
|
284
|
+
:param project: Project name, this will override any project names in the configuration file
|
|
285
|
+
:param domain: Domain name, this will override any domain names in the configuration file
|
|
286
|
+
:param root_dir: Optional root directory from which to determine how to load files, and find paths to
|
|
287
|
+
files like config etc. For example if one uses the copy-style=="all", it is essential to determine the
|
|
288
|
+
root directory for the current project. If not provided, it defaults to the editable install directory or
|
|
289
|
+
if not available, the current working directory.
|
|
290
|
+
:param log_level: Optional logging level for the framework logger,
|
|
291
|
+
default is set using the default initialization policies
|
|
292
|
+
:param log_format: Optional logging format for the logger, default is "console"
|
|
293
|
+
:param storage: Optional blob store (S3, GCS, Azure) configuration if needed to access (i.e. using Minio)
|
|
294
|
+
:param images: List of image strings in format "imagename=imageuri" or just "imageuri".
|
|
295
|
+
:param sync_local_sys_paths: Whether to include and synchronize local sys.path entries under the root directory
|
|
296
|
+
into the remote container (default: True).
|
|
297
|
+
:param batch_size: Optional batch size for operations that use listings, defaults to 1000
|
|
298
|
+
:param image_builder: Optional image builder configuration, if provided,
|
|
299
|
+
will override any defaults set in the configuration.
|
|
300
|
+
:return: None
|
|
301
|
+
"""
|
|
302
|
+
from rich.highlighter import ReprHighlighter
|
|
303
|
+
|
|
304
|
+
import flyte.config as config
|
|
305
|
+
from flyte.cli._common import parse_images
|
|
306
|
+
|
|
307
|
+
cfg: config.Config
|
|
308
|
+
cfg_path: Optional[Path] = None
|
|
309
|
+
if path_or_config is None:
|
|
310
|
+
# If no path is provided, use the default config file
|
|
311
|
+
cfg = config.auto()
|
|
312
|
+
elif isinstance(path_or_config, (str, Path)):
|
|
313
|
+
if root_dir:
|
|
314
|
+
cfg_path = root_dir.expanduser() / path_or_config
|
|
315
|
+
else:
|
|
316
|
+
cfg_path = Path(path_or_config).expanduser()
|
|
317
|
+
if not Path(cfg_path).exists():
|
|
318
|
+
raise InitializationError(
|
|
319
|
+
"ConfigFileNotFoundError",
|
|
320
|
+
"user",
|
|
321
|
+
f"Configuration file '{cfg_path}' does not exist., current working directory is {Path.cwd()}",
|
|
322
|
+
)
|
|
323
|
+
cfg = config.auto(cfg_path)
|
|
324
|
+
else:
|
|
325
|
+
cfg = path_or_config
|
|
326
|
+
|
|
327
|
+
logger.info(f"Flyte config initialized as {cfg}", extra={"highlighter": ReprHighlighter()})
|
|
328
|
+
|
|
329
|
+
# parse image, this will overwrite the image_refs set in the config file
|
|
330
|
+
parse_images(cfg, images)
|
|
331
|
+
|
|
332
|
+
await init.aio(
|
|
333
|
+
org=cfg.task.org,
|
|
334
|
+
project=project or cfg.task.project,
|
|
335
|
+
domain=domain or cfg.task.domain,
|
|
336
|
+
endpoint=cfg.platform.endpoint,
|
|
337
|
+
insecure=cfg.platform.insecure,
|
|
338
|
+
insecure_skip_verify=cfg.platform.insecure_skip_verify,
|
|
339
|
+
ca_cert_file_path=cfg.platform.ca_cert_file_path,
|
|
340
|
+
auth_type=cfg.platform.auth_mode,
|
|
341
|
+
command=cfg.platform.command,
|
|
342
|
+
proxy_command=cfg.platform.proxy_command,
|
|
343
|
+
client_id=cfg.platform.client_id,
|
|
344
|
+
client_credentials_secret=cfg.platform.client_credentials_secret,
|
|
345
|
+
root_dir=root_dir,
|
|
346
|
+
log_level=log_level,
|
|
347
|
+
log_format=log_format,
|
|
348
|
+
image_builder=image_builder or cfg.image.builder,
|
|
349
|
+
batch_size=batch_size,
|
|
350
|
+
images=cfg.image.image_refs,
|
|
351
|
+
storage=storage,
|
|
352
|
+
source_config_path=cfg_path,
|
|
353
|
+
sync_local_sys_paths=sync_local_sys_paths,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
@syncify
|
|
358
|
+
async def init_from_api_key(
|
|
359
|
+
api_key: str | None = None,
|
|
360
|
+
project: str | None = None,
|
|
361
|
+
domain: str | None = None,
|
|
362
|
+
root_dir: Path | None = None,
|
|
363
|
+
log_level: int | None = None,
|
|
364
|
+
log_format: LogFormat | None = None,
|
|
365
|
+
storage: Storage | None = None,
|
|
366
|
+
batch_size: int = 1000,
|
|
367
|
+
image_builder: ImageBuildEngine.ImageBuilderType = "local",
|
|
368
|
+
images: typing.Dict[str, str] | None = None,
|
|
369
|
+
sync_local_sys_paths: bool = True,
|
|
370
|
+
) -> None:
|
|
371
|
+
"""
|
|
372
|
+
Initialize the Flyte system using an API key for authentication. This is a convenience
|
|
373
|
+
method for API key-based authentication. Thread-safe implementation.
|
|
374
|
+
|
|
375
|
+
The API key should be an encoded API key that contains the endpoint, client ID, client secret,
|
|
376
|
+
and organization information. You can obtain this encoded API key from your Flyte administrator
|
|
377
|
+
or cloud provider.
|
|
378
|
+
|
|
379
|
+
:param api_key: Optional encoded API key for authentication. If None, reads from FLYTE_API_KEY
|
|
380
|
+
environment variable. The API key is a base64-encoded string containing endpoint, client_id,
|
|
381
|
+
client_secret, and org information.
|
|
382
|
+
:param project: Optional project name
|
|
383
|
+
:param domain: Optional domain name
|
|
384
|
+
:param root_dir: Optional root directory from which to determine how to load files, and find paths to files.
|
|
385
|
+
defaults to the editable install directory if the cwd is in a Python editable install, else just the cwd.
|
|
386
|
+
:param log_level: Optional logging level for the logger
|
|
387
|
+
:param log_format: Optional logging format for the logger, default is "console"
|
|
388
|
+
:param storage: Optional blob store (S3, GCS, Azure) configuration
|
|
389
|
+
:param batch_size: Optional batch size for operations that use listings, defaults to 1000
|
|
390
|
+
:param image_builder: Optional image builder configuration
|
|
391
|
+
:param images: Optional dict of images that can be used by referencing the image name
|
|
392
|
+
:param sync_local_sys_paths: Whether to include and synchronize local sys.path entries under the root directory
|
|
393
|
+
into the remote container (default: True)
|
|
394
|
+
:return: None
|
|
395
|
+
"""
|
|
396
|
+
import os
|
|
397
|
+
|
|
398
|
+
from flyte._utils import sanitize_endpoint
|
|
399
|
+
from flyte.remote._client.auth._auth_utils import decode_api_key
|
|
400
|
+
|
|
401
|
+
# If api_key is not provided, read from environment variable
|
|
402
|
+
if api_key is None:
|
|
403
|
+
api_key = os.getenv("FLYTE_API_KEY")
|
|
404
|
+
if api_key is None:
|
|
405
|
+
raise InitializationError(
|
|
406
|
+
"MissingApiKeyError",
|
|
407
|
+
"user",
|
|
408
|
+
"API key must be provided either as a parameter or via the FLYTE_API_KEY environment variable.",
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
# Decode the API key to extract endpoint, client_id, client_secret, and org
|
|
412
|
+
endpoint, client_id, client_secret, org = decode_api_key(api_key)
|
|
413
|
+
|
|
414
|
+
# Sanitize the endpoint
|
|
415
|
+
endpoint = sanitize_endpoint(endpoint) # type: ignore[assignment]
|
|
416
|
+
|
|
417
|
+
await init.aio(
|
|
418
|
+
org=None if org == "None" else org,
|
|
419
|
+
project=project,
|
|
420
|
+
domain=domain,
|
|
421
|
+
endpoint=endpoint,
|
|
422
|
+
api_key=api_key,
|
|
423
|
+
client_id=client_id,
|
|
424
|
+
client_credentials_secret=client_secret,
|
|
425
|
+
auth_type="ClientSecret", # API keys use client credentials flow
|
|
426
|
+
root_dir=root_dir,
|
|
427
|
+
log_level=log_level,
|
|
428
|
+
log_format=log_format,
|
|
429
|
+
insecure=False,
|
|
430
|
+
insecure_skip_verify=False,
|
|
431
|
+
storage=storage,
|
|
432
|
+
batch_size=batch_size,
|
|
433
|
+
image_builder=image_builder,
|
|
434
|
+
images=images,
|
|
435
|
+
sync_local_sys_paths=sync_local_sys_paths,
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
@syncify
|
|
440
|
+
async def init_in_cluster(
|
|
441
|
+
org: str | None = None,
|
|
442
|
+
project: str | None = None,
|
|
443
|
+
domain: str | None = None,
|
|
444
|
+
api_key: str | None = None,
|
|
445
|
+
endpoint: str | None = None,
|
|
446
|
+
insecure: bool = False,
|
|
447
|
+
) -> dict[str, typing.Any]:
|
|
448
|
+
import os
|
|
449
|
+
|
|
450
|
+
from flyte._utils import str2bool
|
|
451
|
+
|
|
452
|
+
PROJECT_NAME = "FLYTE_INTERNAL_EXECUTION_PROJECT"
|
|
453
|
+
DOMAIN_NAME = "FLYTE_INTERNAL_EXECUTION_DOMAIN"
|
|
454
|
+
ORG_NAME = "_U_ORG_NAME"
|
|
455
|
+
ENDPOINT_OVERRIDE = "_U_EP_OVERRIDE"
|
|
456
|
+
INSECURE_SKIP_VERIFY_OVERRIDE = "_U_INSECURE_SKIP_VERIFY"
|
|
457
|
+
INSECURE_OVERRIDE = "_U_INSECURE"
|
|
458
|
+
_UNION_EAGER_API_KEY_ENV_VAR = "_UNION_EAGER_API_KEY"
|
|
459
|
+
EAGER_API_KEY = "EAGER_API_KEY"
|
|
460
|
+
|
|
461
|
+
org = org or os.getenv(ORG_NAME)
|
|
462
|
+
project = project or os.getenv(PROJECT_NAME)
|
|
463
|
+
domain = domain or os.getenv(DOMAIN_NAME)
|
|
464
|
+
api_key = api_key or os.getenv(_UNION_EAGER_API_KEY_ENV_VAR) or os.getenv(EAGER_API_KEY)
|
|
465
|
+
|
|
466
|
+
remote_kwargs: dict[str, typing.Any] = {"insecure": insecure}
|
|
467
|
+
if api_key:
|
|
468
|
+
logger.info("Using api key from environment")
|
|
469
|
+
remote_kwargs["api_key"] = api_key
|
|
470
|
+
else:
|
|
471
|
+
ep = endpoint or os.environ.get(ENDPOINT_OVERRIDE, "host.docker.internal:8090")
|
|
472
|
+
remote_kwargs["endpoint"] = ep
|
|
473
|
+
if not insecure:
|
|
474
|
+
if "localhost" in ep or "docker" in ep:
|
|
475
|
+
remote_kwargs["insecure"] = True
|
|
476
|
+
if str2bool(os.getenv(INSECURE_OVERRIDE, "")):
|
|
477
|
+
remote_kwargs["insecure"] = True
|
|
478
|
+
logger.debug(f"Using controller endpoint: {ep} with kwargs: {remote_kwargs}")
|
|
479
|
+
|
|
480
|
+
# Check for insecure_skip_verify override (e.g. for self-signed certs)
|
|
481
|
+
insecure_skip_verify_str = os.getenv(INSECURE_SKIP_VERIFY_OVERRIDE, "")
|
|
482
|
+
if str2bool(insecure_skip_verify_str):
|
|
483
|
+
remote_kwargs["insecure_skip_verify"] = True
|
|
484
|
+
logger.info("SSL certificate verification disabled (insecure_skip_verify=True)")
|
|
485
|
+
|
|
486
|
+
await init.aio(
|
|
487
|
+
org=org, project=project, domain=domain, root_dir=Path.cwd(), image_builder="remote", **remote_kwargs
|
|
488
|
+
)
|
|
489
|
+
return remote_kwargs
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
@syncify
|
|
493
|
+
async def init_passthrough(
|
|
494
|
+
endpoint: str | None = None,
|
|
495
|
+
org: str | None = None,
|
|
496
|
+
project: str | None = None,
|
|
497
|
+
domain: str | None = None,
|
|
498
|
+
insecure: bool = False,
|
|
499
|
+
) -> dict[str, typing.Any]:
|
|
500
|
+
"""
|
|
501
|
+
Initialize the Flyte system with passthrough authentication.
|
|
502
|
+
|
|
503
|
+
This authentication mode allows you to pass custom authentication metadata
|
|
504
|
+
using the `flyte.remote.auth_metadata()` context manager.
|
|
505
|
+
|
|
506
|
+
:param org: Optional organization name
|
|
507
|
+
:param project: Optional project name
|
|
508
|
+
:param domain: Optional domain name
|
|
509
|
+
:param endpoint: Optional API endpoint URL
|
|
510
|
+
:param insecure: Whether to use an insecure channel
|
|
511
|
+
:return: Dictionary of remote kwargs used for initialization
|
|
512
|
+
"""
|
|
513
|
+
await init.aio(
|
|
514
|
+
org=org,
|
|
515
|
+
project=project,
|
|
516
|
+
domain=domain,
|
|
517
|
+
root_dir=Path.cwd(),
|
|
518
|
+
image_builder="remote",
|
|
519
|
+
endpoint=endpoint,
|
|
520
|
+
insecure=insecure,
|
|
521
|
+
auth_type="Passthrough",
|
|
522
|
+
)
|
|
523
|
+
return {"endpoint": endpoint, "insecure": insecure}
|
|
524
|
+
|
|
525
|
+
|
|
434
526
|
def _get_init_config() -> Optional[_InitConfig]:
|
|
435
527
|
"""
|
|
436
528
|
Get the current initialization configuration. Thread-safe implementation.
|
|
@@ -441,7 +533,7 @@ def _get_init_config() -> Optional[_InitConfig]:
|
|
|
441
533
|
return _init_config
|
|
442
534
|
|
|
443
535
|
|
|
444
|
-
def
|
|
536
|
+
def get_init_config() -> _InitConfig:
|
|
445
537
|
"""
|
|
446
538
|
Get the current initialization configuration. Thread-safe implementation.
|
|
447
539
|
|
|
@@ -450,15 +542,15 @@ def get_common_config() -> CommonInit:
|
|
|
450
542
|
cfg = _get_init_config()
|
|
451
543
|
if cfg is None:
|
|
452
544
|
raise InitializationError(
|
|
453
|
-
"
|
|
545
|
+
"ClientNotInitializedError",
|
|
454
546
|
"user",
|
|
455
|
-
"Configuration has not been initialized. Call flyte.init() with a valid endpoint
|
|
456
|
-
"
|
|
547
|
+
"Configuration has not been initialized. Call flyte.init() with a valid endpoint/api-key before",
|
|
548
|
+
" using this function or Call flyte.init_from_config() with a valid path to the config file",
|
|
457
549
|
)
|
|
458
550
|
return cfg
|
|
459
551
|
|
|
460
552
|
|
|
461
|
-
def get_storage() -> Storage:
|
|
553
|
+
def get_storage() -> Storage | None:
|
|
462
554
|
"""
|
|
463
555
|
Get the current storage configuration. Thread-safe implementation.
|
|
464
556
|
|
|
@@ -469,12 +561,10 @@ def get_storage() -> Storage:
|
|
|
469
561
|
raise InitializationError(
|
|
470
562
|
"StorageNotInitializedError",
|
|
471
563
|
"user",
|
|
472
|
-
"Configuration has not been initialized. Call flyte.init() with a valid
|
|
473
|
-
"
|
|
564
|
+
"Configuration has not been initialized. Call flyte.init() with a valid"
|
|
565
|
+
" storage configuration before using this function or Call flyte.init_from_config()"
|
|
566
|
+
" with a valid path to the config file",
|
|
474
567
|
)
|
|
475
|
-
if cfg.storage is None:
|
|
476
|
-
# return default local storage
|
|
477
|
-
return typing.cast(Storage, cfg.replace(storage=Storage()).storage)
|
|
478
568
|
return cfg.storage
|
|
479
569
|
|
|
480
570
|
|
|
@@ -489,8 +579,8 @@ def get_client() -> ClientSet:
|
|
|
489
579
|
raise InitializationError(
|
|
490
580
|
"ClientNotInitializedError",
|
|
491
581
|
"user",
|
|
492
|
-
"Client has not been initialized. Call flyte.init() with a valid endpoint
|
|
493
|
-
"
|
|
582
|
+
"Client has not been initialized. Call flyte.init() with a valid endpoint/api-key "
|
|
583
|
+
"before using this function or Call flyte.init_from_config() with a valid path to the config file",
|
|
494
584
|
)
|
|
495
585
|
return cfg.client
|
|
496
586
|
|
|
@@ -504,41 +594,31 @@ def is_initialized() -> bool:
|
|
|
504
594
|
return _get_init_config() is not None
|
|
505
595
|
|
|
506
596
|
|
|
507
|
-
def initialize_in_cluster(
|
|
597
|
+
def initialize_in_cluster() -> None:
|
|
508
598
|
"""
|
|
509
599
|
Initialize the system for in-cluster execution. This is a placeholder function and does not perform any actions.
|
|
510
600
|
|
|
511
601
|
:return: None
|
|
512
602
|
"""
|
|
513
|
-
init(
|
|
603
|
+
init()
|
|
514
604
|
|
|
515
605
|
|
|
516
606
|
# Define a generic type variable for the decorated function
|
|
517
607
|
T = TypeVar("T", bound=Callable)
|
|
518
608
|
|
|
519
609
|
|
|
520
|
-
def
|
|
610
|
+
def ensure_client():
|
|
521
611
|
"""
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
:param func: Function to decorate
|
|
526
|
-
:return: Decorated function that checks for initialization
|
|
612
|
+
Ensure that the client is initialized. If not, raise an InitializationError.
|
|
613
|
+
This function is used to check if the client is initialized before executing any Flyte remote API methods.
|
|
527
614
|
"""
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
"user",
|
|
536
|
-
f"Function '{func.__name__}' requires client to be initialized. "
|
|
537
|
-
f"Call flyte.init() with a valid endpoint or api-key before using this function.",
|
|
538
|
-
)
|
|
539
|
-
return func(*args, **kwargs)
|
|
540
|
-
|
|
541
|
-
return typing.cast(T, wrapper)
|
|
615
|
+
if _get_init_config() is None or _get_init_config().client is None:
|
|
616
|
+
raise InitializationError(
|
|
617
|
+
"ClientNotInitializedError",
|
|
618
|
+
"user",
|
|
619
|
+
"Client has not been initialized. Call flyte.init() with a valid endpoint/api-key before using"
|
|
620
|
+
" this function or Call flyte.init_from_config() with a valid path to the config file",
|
|
621
|
+
)
|
|
542
622
|
|
|
543
623
|
|
|
544
624
|
def requires_storage(func: T) -> T:
|
|
@@ -557,7 +637,8 @@ def requires_storage(func: T) -> T:
|
|
|
557
637
|
"StorageNotInitializedError",
|
|
558
638
|
"user",
|
|
559
639
|
f"Function '{func.__name__}' requires storage to be initialized. "
|
|
560
|
-
|
|
640
|
+
"Call flyte.init() with a valid storage configuration before using this function."
|
|
641
|
+
"or Call flyte.init_from_config() with a valid path to the config file",
|
|
561
642
|
)
|
|
562
643
|
return func(*args, **kwargs)
|
|
563
644
|
|
|
@@ -583,7 +664,8 @@ def requires_upload_location(func: T) -> T:
|
|
|
583
664
|
"No upload path configured",
|
|
584
665
|
"user",
|
|
585
666
|
f"Function '{func.__name__}' requires client to be initialized. "
|
|
586
|
-
|
|
667
|
+
"Call flyte.init() with storage configuration before using this function."
|
|
668
|
+
"or Call flyte.init_from_config() with a valid path to the config file."
|
|
587
669
|
)
|
|
588
670
|
return func(*args, **kwargs)
|
|
589
671
|
|
|
@@ -605,13 +687,42 @@ def requires_initialization(func: T) -> T:
|
|
|
605
687
|
raise InitializationError(
|
|
606
688
|
"NotInitConfiguredError",
|
|
607
689
|
"user",
|
|
608
|
-
f"Function '{func.__name__}' requires initialization. Call flyte.init() before using this function
|
|
690
|
+
f"Function '{func.__name__}' requires initialization. Call flyte.init() before using this function"
|
|
691
|
+
" or Call flyte.init_from_config() with a valid path to the config file."
|
|
609
692
|
)
|
|
610
693
|
return func(*args, **kwargs)
|
|
611
694
|
|
|
612
695
|
return typing.cast(T, wrapper)
|
|
613
696
|
|
|
614
697
|
|
|
698
|
+
def require_project_and_domain(func):
|
|
699
|
+
"""
|
|
700
|
+
Decorator that ensures the current Flyte configuration defines
|
|
701
|
+
both 'project' and 'domain'. Raises a clear error if not found.
|
|
702
|
+
"""
|
|
703
|
+
|
|
704
|
+
@functools.wraps(func)
|
|
705
|
+
def wrapper(*args, **kwargs):
|
|
706
|
+
cfg = get_init_config()
|
|
707
|
+
if cfg.project is None:
|
|
708
|
+
raise ValueError(
|
|
709
|
+
"Project must be provided to initialize the client. "
|
|
710
|
+
"Please set 'project' in the 'task' section of your config file, "
|
|
711
|
+
"or pass it directly to flyte.init(project='your-project-name')."
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
if cfg.domain is None:
|
|
715
|
+
raise ValueError(
|
|
716
|
+
"Domain must be provided to initialize the client. "
|
|
717
|
+
"Please set 'domain' in the 'task' section of your config file, "
|
|
718
|
+
"or pass it directly to flyte.init(domain='your-domain-name')."
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
return func(*args, **kwargs)
|
|
722
|
+
|
|
723
|
+
return wrapper
|
|
724
|
+
|
|
725
|
+
|
|
615
726
|
async def _init_for_testing(
|
|
616
727
|
project: str | None = None,
|
|
617
728
|
domain: str | None = None,
|
|
@@ -641,3 +752,32 @@ def replace_client(client):
|
|
|
641
752
|
|
|
642
753
|
with _init_lock:
|
|
643
754
|
_init_config = _init_config.replace(client=client)
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
def current_domain() -> str:
|
|
758
|
+
"""
|
|
759
|
+
Returns the current domain from Runtime environment (on the cluster) or from the initialized configuration.
|
|
760
|
+
This is safe to be used during `deploy`, `run` and within `task` code.
|
|
761
|
+
|
|
762
|
+
NOTE: This will not work if you deploy a task to a domain and then run it in another domain.
|
|
763
|
+
|
|
764
|
+
Raises InitializationError if the configuration is not initialized or domain is not set.
|
|
765
|
+
:return: The current domain
|
|
766
|
+
"""
|
|
767
|
+
from ._context import ctx
|
|
768
|
+
|
|
769
|
+
tctx = ctx()
|
|
770
|
+
if tctx is not None:
|
|
771
|
+
domain = tctx.action.domain
|
|
772
|
+
if domain is not None:
|
|
773
|
+
return domain
|
|
774
|
+
|
|
775
|
+
cfg = _get_init_config()
|
|
776
|
+
if cfg is None or cfg.domain is None:
|
|
777
|
+
raise InitializationError(
|
|
778
|
+
"DomainNotInitializedError",
|
|
779
|
+
"user",
|
|
780
|
+
"Domain has not been initialized. Call flyte.init() with a valid domain before using this function"
|
|
781
|
+
" or Call flyte.init_from_config() with a valid path to the config file"
|
|
782
|
+
)
|
|
783
|
+
return cfg.domain
|