flyte 0.0.1b3__py3-none-any.whl → 0.2.0b0__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.
Potentially problematic release.
This version of flyte might be problematic. Click here for more details.
- flyte/_cli/_common.py +12 -0
- {union → flyte}/_cli/_params.py +106 -147
- flyte/_cli/_run.py +24 -2
- flyte/_cli/main.py +28 -2
- flyte/_image.py +1 -2
- flyte/_initialize.py +24 -15
- flyte/_internal/runtime/convert.py +6 -0
- flyte/_run.py +0 -1
- flyte/_version.py +2 -2
- flyte/config/__init__.py +168 -0
- flyte/config/_config.py +196 -0
- flyte/config/_internal.py +64 -0
- flyte/remote/_console.py +1 -1
- flyte/types/_type_engine.py +4 -3
- {flyte-0.0.1b3.dist-info → flyte-0.2.0b0.dist-info}/METADATA +1 -1
- flyte-0.2.0b0.dist-info/RECORD +204 -0
- flyte-0.0.1b3.dist-info/RECORD +0 -390
- union/__init__.py +0 -54
- union/_api_commons.py +0 -3
- union/_bin/__init__.py +0 -0
- union/_bin/runtime.py +0 -113
- union/_build.py +0 -25
- union/_cache/__init__.py +0 -12
- union/_cache/cache.py +0 -141
- union/_cache/defaults.py +0 -9
- union/_cache/policy_function_body.py +0 -42
- union/_cli/__init__.py +0 -0
- union/_cli/_common.py +0 -263
- union/_cli/_create.py +0 -40
- union/_cli/_delete.py +0 -23
- union/_cli/_deploy.py +0 -120
- union/_cli/_get.py +0 -162
- union/_cli/_run.py +0 -150
- union/_cli/main.py +0 -72
- union/_code_bundle/__init__.py +0 -8
- union/_code_bundle/_ignore.py +0 -113
- union/_code_bundle/_packaging.py +0 -187
- union/_code_bundle/_utils.py +0 -342
- union/_code_bundle/bundle.py +0 -176
- union/_context.py +0 -146
- union/_datastructures.py +0 -295
- union/_deploy.py +0 -185
- union/_doc.py +0 -29
- union/_docstring.py +0 -26
- union/_environment.py +0 -43
- union/_group.py +0 -31
- union/_hash.py +0 -23
- union/_image.py +0 -760
- union/_initialize.py +0 -585
- union/_interface.py +0 -84
- union/_internal/__init__.py +0 -3
- union/_internal/controllers/__init__.py +0 -77
- union/_internal/controllers/_local_controller.py +0 -77
- union/_internal/controllers/pbhash.py +0 -39
- union/_internal/controllers/remote/__init__.py +0 -40
- union/_internal/controllers/remote/_action.py +0 -131
- union/_internal/controllers/remote/_client.py +0 -43
- union/_internal/controllers/remote/_controller.py +0 -169
- union/_internal/controllers/remote/_core.py +0 -341
- union/_internal/controllers/remote/_informer.py +0 -260
- union/_internal/controllers/remote/_service_protocol.py +0 -44
- union/_internal/imagebuild/__init__.py +0 -11
- union/_internal/imagebuild/docker_builder.py +0 -416
- union/_internal/imagebuild/image_builder.py +0 -243
- union/_internal/imagebuild/remote_builder.py +0 -0
- union/_internal/resolvers/__init__.py +0 -0
- union/_internal/resolvers/_task_module.py +0 -31
- union/_internal/resolvers/common.py +0 -24
- union/_internal/resolvers/default.py +0 -27
- union/_internal/runtime/__init__.py +0 -0
- union/_internal/runtime/convert.py +0 -163
- union/_internal/runtime/entrypoints.py +0 -121
- union/_internal/runtime/io.py +0 -136
- union/_internal/runtime/resources_serde.py +0 -134
- union/_internal/runtime/task_serde.py +0 -202
- union/_internal/runtime/taskrunner.py +0 -179
- union/_internal/runtime/types_serde.py +0 -53
- union/_logging.py +0 -124
- union/_protos/__init__.py +0 -0
- union/_protos/common/authorization_pb2.py +0 -66
- union/_protos/common/authorization_pb2.pyi +0 -106
- union/_protos/common/authorization_pb2_grpc.py +0 -4
- union/_protos/common/identifier_pb2.py +0 -71
- union/_protos/common/identifier_pb2.pyi +0 -82
- union/_protos/common/identifier_pb2_grpc.py +0 -4
- union/_protos/common/identity_pb2.py +0 -48
- union/_protos/common/identity_pb2.pyi +0 -72
- union/_protos/common/identity_pb2_grpc.py +0 -4
- union/_protos/common/list_pb2.py +0 -36
- union/_protos/common/list_pb2.pyi +0 -69
- union/_protos/common/list_pb2_grpc.py +0 -4
- union/_protos/common/policy_pb2.py +0 -37
- union/_protos/common/policy_pb2.pyi +0 -27
- union/_protos/common/policy_pb2_grpc.py +0 -4
- union/_protos/common/role_pb2.py +0 -37
- union/_protos/common/role_pb2.pyi +0 -51
- union/_protos/common/role_pb2_grpc.py +0 -4
- union/_protos/common/runtime_version_pb2.py +0 -28
- union/_protos/common/runtime_version_pb2.pyi +0 -24
- union/_protos/common/runtime_version_pb2_grpc.py +0 -4
- union/_protos/logs/dataplane/payload_pb2.py +0 -96
- union/_protos/logs/dataplane/payload_pb2.pyi +0 -168
- union/_protos/logs/dataplane/payload_pb2_grpc.py +0 -4
- union/_protos/secret/definition_pb2.py +0 -49
- union/_protos/secret/definition_pb2.pyi +0 -93
- union/_protos/secret/definition_pb2_grpc.py +0 -4
- union/_protos/secret/payload_pb2.py +0 -62
- union/_protos/secret/payload_pb2.pyi +0 -94
- union/_protos/secret/payload_pb2_grpc.py +0 -4
- union/_protos/secret/secret_pb2.py +0 -38
- union/_protos/secret/secret_pb2.pyi +0 -6
- union/_protos/secret/secret_pb2_grpc.py +0 -198
- union/_protos/validate/validate/validate_pb2.py +0 -76
- union/_protos/workflow/node_execution_service_pb2.py +0 -26
- union/_protos/workflow/node_execution_service_pb2.pyi +0 -4
- union/_protos/workflow/node_execution_service_pb2_grpc.py +0 -32
- union/_protos/workflow/queue_service_pb2.py +0 -75
- union/_protos/workflow/queue_service_pb2.pyi +0 -103
- union/_protos/workflow/queue_service_pb2_grpc.py +0 -172
- union/_protos/workflow/run_definition_pb2.py +0 -100
- union/_protos/workflow/run_definition_pb2.pyi +0 -256
- union/_protos/workflow/run_definition_pb2_grpc.py +0 -4
- union/_protos/workflow/run_logs_service_pb2.py +0 -41
- union/_protos/workflow/run_logs_service_pb2.pyi +0 -28
- union/_protos/workflow/run_logs_service_pb2_grpc.py +0 -69
- union/_protos/workflow/run_service_pb2.py +0 -133
- union/_protos/workflow/run_service_pb2.pyi +0 -173
- union/_protos/workflow/run_service_pb2_grpc.py +0 -412
- union/_protos/workflow/state_service_pb2.py +0 -58
- union/_protos/workflow/state_service_pb2.pyi +0 -69
- union/_protos/workflow/state_service_pb2_grpc.py +0 -138
- union/_protos/workflow/task_definition_pb2.py +0 -72
- union/_protos/workflow/task_definition_pb2.pyi +0 -65
- union/_protos/workflow/task_definition_pb2_grpc.py +0 -4
- union/_protos/workflow/task_service_pb2.py +0 -44
- union/_protos/workflow/task_service_pb2.pyi +0 -31
- union/_protos/workflow/task_service_pb2_grpc.py +0 -104
- union/_resources.py +0 -226
- union/_retry.py +0 -32
- union/_reusable_environment.py +0 -25
- union/_run.py +0 -374
- union/_secret.py +0 -61
- union/_task.py +0 -354
- union/_task_environment.py +0 -186
- union/_timeout.py +0 -47
- union/_tools.py +0 -27
- union/_utils/__init__.py +0 -11
- union/_utils/asyn.py +0 -119
- union/_utils/file_handling.py +0 -71
- union/_utils/helpers.py +0 -46
- union/_utils/lazy_module.py +0 -54
- union/_utils/uv_script_parser.py +0 -49
- union/_version.py +0 -21
- union/connectors/__init__.py +0 -0
- union/errors.py +0 -128
- union/extras/__init__.py +0 -5
- union/extras/_container.py +0 -263
- union/io/__init__.py +0 -11
- union/io/_dataframe.py +0 -0
- union/io/_dir.py +0 -425
- union/io/_file.py +0 -418
- union/io/pickle/__init__.py +0 -0
- union/io/pickle/transformer.py +0 -117
- union/io/structured_dataset/__init__.py +0 -122
- union/io/structured_dataset/basic_dfs.py +0 -219
- union/io/structured_dataset/structured_dataset.py +0 -1057
- union/py.typed +0 -0
- union/remote/__init__.py +0 -23
- union/remote/_client/__init__.py +0 -0
- union/remote/_client/_protocols.py +0 -129
- union/remote/_client/auth/__init__.py +0 -12
- union/remote/_client/auth/_authenticators/__init__.py +0 -0
- union/remote/_client/auth/_authenticators/base.py +0 -391
- union/remote/_client/auth/_authenticators/client_credentials.py +0 -73
- union/remote/_client/auth/_authenticators/device_code.py +0 -120
- union/remote/_client/auth/_authenticators/external_command.py +0 -77
- union/remote/_client/auth/_authenticators/factory.py +0 -200
- union/remote/_client/auth/_authenticators/pkce.py +0 -515
- union/remote/_client/auth/_channel.py +0 -184
- union/remote/_client/auth/_client_config.py +0 -83
- union/remote/_client/auth/_default_html.py +0 -32
- union/remote/_client/auth/_grpc_utils/__init__.py +0 -0
- union/remote/_client/auth/_grpc_utils/auth_interceptor.py +0 -204
- union/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +0 -144
- union/remote/_client/auth/_keyring.py +0 -154
- union/remote/_client/auth/_token_client.py +0 -258
- union/remote/_client/auth/errors.py +0 -16
- union/remote/_client/controlplane.py +0 -86
- union/remote/_data.py +0 -149
- union/remote/_logs.py +0 -74
- union/remote/_project.py +0 -86
- union/remote/_run.py +0 -820
- union/remote/_secret.py +0 -132
- union/remote/_task.py +0 -193
- union/report/__init__.py +0 -3
- union/report/_report.py +0 -178
- union/report/_template.html +0 -124
- union/storage/__init__.py +0 -24
- union/storage/_remote_fs.py +0 -34
- union/storage/_storage.py +0 -247
- union/storage/_utils.py +0 -5
- union/types/__init__.py +0 -11
- union/types/_renderer.py +0 -162
- union/types/_string_literals.py +0 -120
- union/types/_type_engine.py +0 -2131
- union/types/_utils.py +0 -80
- {flyte-0.0.1b3.dist-info → flyte-0.2.0b0.dist-info}/WHEEL +0 -0
- {flyte-0.0.1b3.dist-info → flyte-0.2.0b0.dist-info}/entry_points.txt +0 -0
- {flyte-0.0.1b3.dist-info → flyte-0.2.0b0.dist-info}/top_level.txt +0 -0
flyte/_initialize.py
CHANGED
|
@@ -17,6 +17,7 @@ from ._logging import initialize_logger
|
|
|
17
17
|
from ._tools import ipython_check
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
|
+
from flyte.config import Config
|
|
20
21
|
from flyte.remote._client.auth import AuthType, ClientConfig
|
|
21
22
|
from flyte.remote._client.controlplane import ClientSet
|
|
22
23
|
|
|
@@ -345,6 +346,7 @@ async def init(
|
|
|
345
346
|
rpc_retries: int = 3,
|
|
346
347
|
http_proxy_url: str | None = None,
|
|
347
348
|
storage: Storage | None = None,
|
|
349
|
+
config: Config | None = None,
|
|
348
350
|
) -> None:
|
|
349
351
|
"""
|
|
350
352
|
Initialize the Flyte system with the given configuration. This method should be called before any other Flyte
|
|
@@ -378,6 +380,7 @@ async def init(
|
|
|
378
380
|
:param insecure: insecure flag for the client
|
|
379
381
|
:param storage: Optional blob store (S3, GCS, Azure) configuration if needed to access (i.e. using Minio)
|
|
380
382
|
:param org: Optional organization override for the client. Should be set by auth instead.
|
|
383
|
+
:param config: Optional config to override the init parameters
|
|
381
384
|
|
|
382
385
|
:return: None
|
|
383
386
|
"""
|
|
@@ -392,33 +395,39 @@ async def init(
|
|
|
392
395
|
global _init_config # noqa: PLW0603
|
|
393
396
|
|
|
394
397
|
with _init_lock:
|
|
398
|
+
if config is None:
|
|
399
|
+
from flyte.config import Config
|
|
400
|
+
|
|
401
|
+
config = Config.auto()
|
|
402
|
+
platform_cfg = config.platform
|
|
403
|
+
task_cfg = config.task
|
|
395
404
|
client = None
|
|
396
|
-
if endpoint or api_key:
|
|
405
|
+
if endpoint or platform_cfg.endpoint or api_key:
|
|
397
406
|
client = await _initialize_client(
|
|
398
407
|
api_key=api_key,
|
|
399
|
-
auth_type=auth_type,
|
|
400
|
-
endpoint=endpoint,
|
|
408
|
+
auth_type=auth_type or platform_cfg.auth_mode,
|
|
409
|
+
endpoint=endpoint or platform_cfg.endpoint,
|
|
401
410
|
headless=headless,
|
|
402
|
-
insecure=insecure,
|
|
403
|
-
insecure_skip_verify=insecure_skip_verify,
|
|
404
|
-
ca_cert_file_path=ca_cert_file_path,
|
|
405
|
-
command=command,
|
|
406
|
-
proxy_command=proxy_command,
|
|
407
|
-
client_id=client_id,
|
|
408
|
-
client_credentials_secret=client_credentials_secret,
|
|
411
|
+
insecure=insecure or platform_cfg.insecure,
|
|
412
|
+
insecure_skip_verify=insecure_skip_verify or platform_cfg.insecure_skip_verify,
|
|
413
|
+
ca_cert_file_path=ca_cert_file_path or platform_cfg.ca_cert_file_path,
|
|
414
|
+
command=command or platform_cfg.command,
|
|
415
|
+
proxy_command=proxy_command or platform_cfg.proxy_command,
|
|
416
|
+
client_id=client_id or platform_cfg.client_id,
|
|
417
|
+
client_credentials_secret=client_credentials_secret or platform_cfg.client_credentials_secret,
|
|
409
418
|
client_config=auth_client_config,
|
|
410
|
-
rpc_retries=rpc_retries,
|
|
411
|
-
http_proxy_url=http_proxy_url,
|
|
419
|
+
rpc_retries=rpc_retries or platform_cfg.rpc_retries,
|
|
420
|
+
http_proxy_url=http_proxy_url or platform_cfg.http_proxy_url,
|
|
412
421
|
)
|
|
413
422
|
|
|
414
423
|
root_dir = root_dir or get_cwd_editable_install() or Path.cwd()
|
|
415
424
|
_init_config = _InitConfig(
|
|
416
425
|
root_dir=root_dir,
|
|
417
|
-
project=project,
|
|
418
|
-
domain=domain,
|
|
426
|
+
project=project or task_cfg.project,
|
|
427
|
+
domain=domain or task_cfg.domain,
|
|
419
428
|
client=client,
|
|
420
429
|
storage=storage,
|
|
421
|
-
org=org,
|
|
430
|
+
org=org or task_cfg.org,
|
|
422
431
|
)
|
|
423
432
|
|
|
424
433
|
|
|
@@ -60,6 +60,12 @@ async def convert_from_native_to_inputs(interface: NativeInterface, *args, **kwa
|
|
|
60
60
|
kwargs = interface.convert_to_kwargs(*args, **kwargs)
|
|
61
61
|
if len(kwargs) == 0:
|
|
62
62
|
return Inputs.empty()
|
|
63
|
+
# fill in defaults if missing
|
|
64
|
+
for input_name, (input_type, default_value) in interface.inputs.items():
|
|
65
|
+
if input_name not in kwargs:
|
|
66
|
+
if default_value is not None:
|
|
67
|
+
kwargs[input_name] = default_value
|
|
68
|
+
# todo: fill in Nones for optional inputs
|
|
63
69
|
if len(kwargs) < len(interface.inputs):
|
|
64
70
|
raise ValueError(
|
|
65
71
|
f"Received {len(kwargs)} inputs but interface has {len(interface.inputs)}. "
|
flyte/_run.py
CHANGED
|
@@ -277,7 +277,6 @@ class _Runner:
|
|
|
277
277
|
from flyte._internal.runtime.entrypoints import direct_dispatch
|
|
278
278
|
|
|
279
279
|
controller = create_controller(ct="local")
|
|
280
|
-
|
|
281
280
|
inputs = await convert_from_native_to_inputs(obj.native_interface, *args, **kwargs)
|
|
282
281
|
if self._name is None:
|
|
283
282
|
action = ActionID.create_random()
|
flyte/_version.py
CHANGED
|
@@ -17,5 +17,5 @@ __version__: str
|
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
|
18
18
|
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
__version__ = version = '0.
|
|
21
|
-
__version_tuple__ = version_tuple = (0,
|
|
20
|
+
__version__ = version = '0.2.0b0'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 2, 0, 'b0')
|
flyte/config/__init__.py
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import typing
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from flyte._logging import logger
|
|
7
|
+
from flyte.config import _internal
|
|
8
|
+
from flyte.config._config import ConfigFile, get_config_file, read_file_if_exists
|
|
9
|
+
|
|
10
|
+
_all__ = ["ConfigFile", "PlatformConfig", "TaskConfig"]
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from flyte.remote._client.auth import AuthType
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(init=True, repr=True, eq=True, frozen=True)
|
|
17
|
+
class PlatformConfig(object):
|
|
18
|
+
"""
|
|
19
|
+
This object contains the settings to talk to a Flyte backend (the DNS location of your Admin server basically).
|
|
20
|
+
|
|
21
|
+
:param endpoint: DNS for Flyte backend
|
|
22
|
+
:param insecure: Whether or not to use SSL
|
|
23
|
+
:param insecure_skip_verify: Whether to skip SSL certificate verification
|
|
24
|
+
:param console_endpoint: endpoint for console if different from Flyte backend
|
|
25
|
+
:param command: This command is executed to return a token using an external process
|
|
26
|
+
:param proxy_command: This command is executed to return a token for proxy authorization using an external process
|
|
27
|
+
:param client_id: This is the public identifier for the app which handles authorization for a Flyte deployment.
|
|
28
|
+
More details here: https://www.oauth.com/oauth2-servers/client-registration/client-id-secret/.
|
|
29
|
+
:param client_credentials_secret: Used for service auth, which is automatically called during pyflyte. This will
|
|
30
|
+
allow the Flyte engine to read the password directly from the environment variable. Note that this is
|
|
31
|
+
less secure! Please only use this if mounting the secret as a file is impossible
|
|
32
|
+
:param scopes: List of scopes to request. This is only applicable to the client credentials flow
|
|
33
|
+
:param auth_mode: The OAuth mode to use. Defaults to pkce flow
|
|
34
|
+
:param ca_cert_file_path: [optional] str Root Cert to be loaded and used to verify admin
|
|
35
|
+
:param http_proxy_url: [optional] HTTP Proxy to be used for OAuth requests
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
endpoint: str | None = None
|
|
39
|
+
insecure: bool = False
|
|
40
|
+
insecure_skip_verify: bool = False
|
|
41
|
+
ca_cert_file_path: typing.Optional[str] = None
|
|
42
|
+
console_endpoint: typing.Optional[str] = None
|
|
43
|
+
command: typing.Optional[typing.List[str]] = None
|
|
44
|
+
proxy_command: typing.Optional[typing.List[str]] = None
|
|
45
|
+
client_id: typing.Optional[str] = None
|
|
46
|
+
client_credentials_secret: typing.Optional[str] = None
|
|
47
|
+
scopes: typing.List[str] = field(default_factory=list)
|
|
48
|
+
auth_mode: "AuthType" = "Pkce"
|
|
49
|
+
audience: typing.Optional[str] = None
|
|
50
|
+
rpc_retries: int = 3
|
|
51
|
+
http_proxy_url: typing.Optional[str] = None
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def auto(cls, config_file: typing.Optional[typing.Union[str, ConfigFile]] = None) -> "PlatformConfig":
|
|
55
|
+
"""
|
|
56
|
+
Reads from a config file, and overrides from Environment variables. Refer to ConfigEntry for details
|
|
57
|
+
:param config_file:
|
|
58
|
+
:return:
|
|
59
|
+
"""
|
|
60
|
+
from .._initialize import set_if_exists
|
|
61
|
+
|
|
62
|
+
config_file = get_config_file(config_file)
|
|
63
|
+
kwargs: typing.Dict[str, typing.Any] = {}
|
|
64
|
+
kwargs = set_if_exists(kwargs, "insecure", _internal.Platform.INSECURE.read(config_file))
|
|
65
|
+
kwargs = set_if_exists(
|
|
66
|
+
kwargs, "insecure_skip_verify", _internal.Platform.INSECURE_SKIP_VERIFY.read(config_file)
|
|
67
|
+
)
|
|
68
|
+
kwargs = set_if_exists(kwargs, "ca_cert_file_path", _internal.Platform.CA_CERT_FILE_PATH.read(config_file))
|
|
69
|
+
kwargs = set_if_exists(kwargs, "command", _internal.Credentials.COMMAND.read(config_file))
|
|
70
|
+
kwargs = set_if_exists(kwargs, "proxy_command", _internal.Credentials.PROXY_COMMAND.read(config_file))
|
|
71
|
+
kwargs = set_if_exists(kwargs, "client_id", _internal.Credentials.CLIENT_ID.read(config_file))
|
|
72
|
+
|
|
73
|
+
is_client_secret = False
|
|
74
|
+
client_credentials_secret = read_file_if_exists(
|
|
75
|
+
_internal.Credentials.CLIENT_CREDENTIALS_SECRET_LOCATION.read(config_file)
|
|
76
|
+
)
|
|
77
|
+
if client_credentials_secret:
|
|
78
|
+
is_client_secret = True
|
|
79
|
+
if client_credentials_secret.endswith("\n"):
|
|
80
|
+
logger.info("Newline stripped from client secret")
|
|
81
|
+
client_credentials_secret = client_credentials_secret.strip()
|
|
82
|
+
kwargs = set_if_exists(
|
|
83
|
+
kwargs,
|
|
84
|
+
"client_credentials_secret",
|
|
85
|
+
client_credentials_secret,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
client_credentials_secret_env_var = _internal.Credentials.CLIENT_CREDENTIALS_SECRET_ENV_VAR.read(config_file)
|
|
89
|
+
if client_credentials_secret_env_var:
|
|
90
|
+
client_credentials_secret = os.getenv(client_credentials_secret_env_var)
|
|
91
|
+
if client_credentials_secret:
|
|
92
|
+
is_client_secret = True
|
|
93
|
+
kwargs = set_if_exists(kwargs, "client_credentials_secret", client_credentials_secret)
|
|
94
|
+
kwargs = set_if_exists(kwargs, "scopes", _internal.Credentials.SCOPES.read(config_file))
|
|
95
|
+
kwargs = set_if_exists(kwargs, "auth_mode", _internal.Credentials.AUTH_MODE.read(config_file))
|
|
96
|
+
if is_client_secret:
|
|
97
|
+
kwargs = set_if_exists(kwargs, "auth_mode", "ClientSecret")
|
|
98
|
+
kwargs = set_if_exists(kwargs, "endpoint", _internal.Platform.URL.read(config_file))
|
|
99
|
+
kwargs = set_if_exists(kwargs, "console_endpoint", _internal.Platform.CONSOLE_ENDPOINT.read(config_file))
|
|
100
|
+
|
|
101
|
+
kwargs = set_if_exists(kwargs, "http_proxy_url", _internal.Platform.HTTP_PROXY_URL.read(config_file))
|
|
102
|
+
return PlatformConfig(**kwargs)
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def for_endpoint(cls, endpoint: str, insecure: bool = False) -> "PlatformConfig":
|
|
106
|
+
return PlatformConfig(endpoint=endpoint, insecure=insecure)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass(init=True, repr=True, eq=True, frozen=True)
|
|
110
|
+
class TaskConfig(object):
|
|
111
|
+
org: str | None = None
|
|
112
|
+
project: str | None = None
|
|
113
|
+
domain: str | None = None
|
|
114
|
+
|
|
115
|
+
@classmethod
|
|
116
|
+
def auto(cls, config_file: typing.Optional[typing.Union[str, ConfigFile]] = None) -> "TaskConfig":
|
|
117
|
+
"""
|
|
118
|
+
Reads from a config file, and overrides from Environment variables. Refer to ConfigEntry for details
|
|
119
|
+
:param config_file:
|
|
120
|
+
:return:
|
|
121
|
+
"""
|
|
122
|
+
from flyte._initialize import set_if_exists
|
|
123
|
+
|
|
124
|
+
config_file = get_config_file(config_file)
|
|
125
|
+
kwargs: typing.Dict[str, typing.Any] = {}
|
|
126
|
+
kwargs = set_if_exists(kwargs, "org", _internal.Task.ORG.read(config_file))
|
|
127
|
+
kwargs = set_if_exists(kwargs, "project", _internal.Task.PROJECT.read(config_file))
|
|
128
|
+
kwargs = set_if_exists(kwargs, "domain", _internal.Task.DOMAIN.read(config_file))
|
|
129
|
+
return TaskConfig(**kwargs)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@dataclass(init=True, repr=True, eq=True, frozen=True)
|
|
133
|
+
class Config(object):
|
|
134
|
+
"""
|
|
135
|
+
This the parent configuration object and holds all the underlying configuration object types. An instance of
|
|
136
|
+
this object holds all the config necessary to
|
|
137
|
+
|
|
138
|
+
1. Interactive session with Flyte backend
|
|
139
|
+
2. Some parts are required for Serialization, for example Platform Config is not required
|
|
140
|
+
3. Runtime of a task
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
platform: PlatformConfig = field(default=PlatformConfig())
|
|
144
|
+
task: TaskConfig = field(default=TaskConfig())
|
|
145
|
+
|
|
146
|
+
def with_params(
|
|
147
|
+
self,
|
|
148
|
+
platform: PlatformConfig | None = None,
|
|
149
|
+
task: TaskConfig | None = None,
|
|
150
|
+
) -> "Config":
|
|
151
|
+
return Config(
|
|
152
|
+
platform=platform or self.platform,
|
|
153
|
+
task=task or self.task,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
@classmethod
|
|
157
|
+
def auto(cls, config_file: typing.Union[str, ConfigFile, None] = None) -> "Config":
|
|
158
|
+
"""
|
|
159
|
+
Automatically constructs the Config Object. The order of precedence is as follows
|
|
160
|
+
1. first try to find any env vars that match the config vars specified in the FLYTE_CONFIG format.
|
|
161
|
+
2. If not found in environment then values ar read from the config file
|
|
162
|
+
3. If not found in the file, then the default values are used.
|
|
163
|
+
|
|
164
|
+
:param config_file: file path to read the config from, if not specified default locations are searched
|
|
165
|
+
:return: Config
|
|
166
|
+
"""
|
|
167
|
+
config_file = get_config_file(config_file)
|
|
168
|
+
return Config(platform=PlatformConfig.auto(config_file), task=TaskConfig.auto(config_file))
|
flyte/config/_config.py
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pathlib
|
|
3
|
+
import typing
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from functools import lru_cache
|
|
6
|
+
from os import getenv
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import yaml
|
|
10
|
+
|
|
11
|
+
from flyte._logging import logger
|
|
12
|
+
|
|
13
|
+
# This is the default config file name for flyte
|
|
14
|
+
FLYTECTL_CONFIG_ENV_VAR = "FLYTECTL_CONFIG"
|
|
15
|
+
UCTL_CONFIG_ENV_VAR = "UCTL_CONFIG"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class YamlConfigEntry(object):
|
|
20
|
+
"""
|
|
21
|
+
Creates a record for the config entry.
|
|
22
|
+
Args:
|
|
23
|
+
switch: dot-delimited string that should match flytectl args. Leaving it as dot-delimited instead of a list
|
|
24
|
+
of strings because it's easier to maintain alignment with flytectl.
|
|
25
|
+
config_value_type: Expected type of the value
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
switch: str
|
|
29
|
+
config_value_type: typing.Type = str
|
|
30
|
+
|
|
31
|
+
def get_env_name(self) -> str:
|
|
32
|
+
var_name = self.switch.upper().replace(".", "_")
|
|
33
|
+
return f"FLYTE_{var_name}"
|
|
34
|
+
|
|
35
|
+
def read_from_env(self, transform: typing.Optional[typing.Callable] = None) -> typing.Optional[typing.Any]:
|
|
36
|
+
"""
|
|
37
|
+
Reads the config entry from environment variable, the structure of the env var is current
|
|
38
|
+
``FLYTE_{SECTION}_{OPTION}`` all upper cased. We will change this in the future.
|
|
39
|
+
:return:
|
|
40
|
+
"""
|
|
41
|
+
env = self.get_env_name()
|
|
42
|
+
v = os.environ.get(env, None)
|
|
43
|
+
if v is None:
|
|
44
|
+
return None
|
|
45
|
+
return transform(v) if transform else v
|
|
46
|
+
|
|
47
|
+
def read_from_file(
|
|
48
|
+
self, cfg: "ConfigFile", transform: typing.Optional[typing.Callable] = None
|
|
49
|
+
) -> typing.Optional[typing.Any]:
|
|
50
|
+
if not cfg:
|
|
51
|
+
return None
|
|
52
|
+
try:
|
|
53
|
+
v = cfg.get(self)
|
|
54
|
+
if isinstance(v, bool) or bool(v is not None and v):
|
|
55
|
+
return transform(v) if transform else v
|
|
56
|
+
except Exception:
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class ConfigEntry(object):
|
|
64
|
+
"""
|
|
65
|
+
A top level Config entry holder, that holds multiple different representations of the config.
|
|
66
|
+
Legacy means the INI style config files. YAML support is for the flytectl config file, which is there by default
|
|
67
|
+
when flytectl starts a sandbox
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
yaml_entry: YamlConfigEntry
|
|
71
|
+
transform: typing.Optional[typing.Callable[[str], typing.Any]] = None
|
|
72
|
+
|
|
73
|
+
def read(self, cfg: typing.Optional["ConfigFile"] = None) -> typing.Optional[typing.Any]:
|
|
74
|
+
"""
|
|
75
|
+
Reads the config Entry from the various sources in the following order,
|
|
76
|
+
#. First try to read from the relevant environment variable,
|
|
77
|
+
#. If missing, then try to read from the legacy config file, if one was parsed.
|
|
78
|
+
#. If missing, then try to read from the yaml file.
|
|
79
|
+
|
|
80
|
+
The constructor for ConfigFile currently does not allow specification of both the ini and yaml style formats.
|
|
81
|
+
|
|
82
|
+
:param cfg:
|
|
83
|
+
:return:
|
|
84
|
+
"""
|
|
85
|
+
from_env = self.yaml_entry.read_from_env(self.transform)
|
|
86
|
+
if from_env is not None:
|
|
87
|
+
return from_env
|
|
88
|
+
if cfg and cfg.yaml_config and self.yaml_entry:
|
|
89
|
+
return self.yaml_entry.read_from_file(cfg, self.transform)
|
|
90
|
+
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class ConfigFile(object):
|
|
95
|
+
def __init__(self, location: str):
|
|
96
|
+
"""
|
|
97
|
+
Load the config from this location
|
|
98
|
+
"""
|
|
99
|
+
self._location = location
|
|
100
|
+
self._yaml_config = self._read_yaml_config(location)
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _read_yaml_config(location: str) -> typing.Optional[typing.Dict[str, typing.Any]]:
|
|
104
|
+
with open(location, "r") as fh:
|
|
105
|
+
try:
|
|
106
|
+
yaml_contents = yaml.safe_load(fh)
|
|
107
|
+
return yaml_contents
|
|
108
|
+
except yaml.YAMLError as exc:
|
|
109
|
+
logger.warning(f"Error {exc} reading yaml config file at {location}, ignoring...")
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
def _get_from_yaml(self, c: YamlConfigEntry) -> typing.Any:
|
|
113
|
+
keys = c.switch.split(".") # flytectl switches are dot delimited
|
|
114
|
+
d = typing.cast(typing.Dict[str, typing.Any], self.yaml_config)
|
|
115
|
+
try:
|
|
116
|
+
for k in keys:
|
|
117
|
+
d = d[k]
|
|
118
|
+
return d
|
|
119
|
+
except KeyError:
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
def get(self, c: YamlConfigEntry) -> typing.Any:
|
|
123
|
+
return self._get_from_yaml(c)
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def yaml_config(self) -> typing.Dict[str, typing.Any] | None:
|
|
127
|
+
return self._yaml_config
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def resolve_config_path() -> pathlib.Path | None:
|
|
131
|
+
"""
|
|
132
|
+
Config is read from the following locations in order of precedence:
|
|
133
|
+
1. `UCTL_CONFIG` environment variable
|
|
134
|
+
2. `FLYTECTL_CONFIG` environment variable
|
|
135
|
+
3. ~/.union/config.yaml if it exists
|
|
136
|
+
4. ~/.flyte/config.yaml if it exists
|
|
137
|
+
5. ./config.yaml if it exists
|
|
138
|
+
"""
|
|
139
|
+
uctl_path_from_env = getenv(UCTL_CONFIG_ENV_VAR, None)
|
|
140
|
+
if uctl_path_from_env:
|
|
141
|
+
return pathlib.Path(uctl_path_from_env)
|
|
142
|
+
logger.debug("No UCTL_CONFIG environment variable found, checking FLYTECTL_CONFIG")
|
|
143
|
+
|
|
144
|
+
flytectl_path_from_env = getenv(FLYTECTL_CONFIG_ENV_VAR, None)
|
|
145
|
+
if flytectl_path_from_env:
|
|
146
|
+
return pathlib.Path(flytectl_path_from_env)
|
|
147
|
+
logger.debug("No FLYTECTL_CONFIG environment variable found, checking default locations")
|
|
148
|
+
|
|
149
|
+
home_dir_union_config = Path(Path.home(), ".union", "config.yaml")
|
|
150
|
+
if home_dir_union_config.exists():
|
|
151
|
+
return home_dir_union_config
|
|
152
|
+
logger.debug("No ~/.union/config.yaml found, checking current directory")
|
|
153
|
+
|
|
154
|
+
home_dir_flytectl_config = Path(Path.home(), ".flyte", "config.yaml")
|
|
155
|
+
if home_dir_flytectl_config.exists():
|
|
156
|
+
return home_dir_flytectl_config
|
|
157
|
+
logger.debug("No ~/.flyte/config.yaml found, checking current directory")
|
|
158
|
+
|
|
159
|
+
current_location_config = Path("config.yaml")
|
|
160
|
+
if current_location_config.exists():
|
|
161
|
+
return current_location_config
|
|
162
|
+
logger.debug("No ./config.yaml found, returning None")
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@lru_cache
|
|
167
|
+
def get_config_file(c: typing.Union[str, ConfigFile, None]) -> ConfigFile | None:
|
|
168
|
+
"""
|
|
169
|
+
Checks if the given argument is a file or a configFile and returns a loaded configFile else returns None
|
|
170
|
+
"""
|
|
171
|
+
if "PYTEST_VERSION" in os.environ:
|
|
172
|
+
# Use default local config in the pytest environment
|
|
173
|
+
return None
|
|
174
|
+
if isinstance(c, str):
|
|
175
|
+
logger.debug(f"Using specified config file at {c}")
|
|
176
|
+
return ConfigFile(c)
|
|
177
|
+
config_path = resolve_config_path()
|
|
178
|
+
if config_path:
|
|
179
|
+
return ConfigFile(str(config_path))
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def read_file_if_exists(filename: typing.Optional[str], encoding=None) -> typing.Optional[str]:
|
|
184
|
+
"""
|
|
185
|
+
Reads the contents of the file if passed a path. Otherwise, returns None.
|
|
186
|
+
|
|
187
|
+
:param filename: The file path to load
|
|
188
|
+
:param encoding: The encoding to use when reading the file.
|
|
189
|
+
:return: The contents of the file as a string or None.
|
|
190
|
+
"""
|
|
191
|
+
if not filename:
|
|
192
|
+
return None
|
|
193
|
+
|
|
194
|
+
file = pathlib.Path(filename)
|
|
195
|
+
logger.debug(f"Reading file contents from [{file}] with current directory [{os.getcwd()}].")
|
|
196
|
+
return file.read_text(encoding=encoding)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from flyte.config._config import ConfigEntry, YamlConfigEntry
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Platform(object):
|
|
5
|
+
URL = ConfigEntry(YamlConfigEntry("admin.endpoint"))
|
|
6
|
+
INSECURE = ConfigEntry(YamlConfigEntry("admin.insecure", bool))
|
|
7
|
+
INSECURE_SKIP_VERIFY = ConfigEntry(YamlConfigEntry("admin.insecureSkipVerify", bool))
|
|
8
|
+
CONSOLE_ENDPOINT = ConfigEntry(YamlConfigEntry("console.endpoint"))
|
|
9
|
+
CA_CERT_FILE_PATH = ConfigEntry(YamlConfigEntry("admin.caCertFilePath"))
|
|
10
|
+
HTTP_PROXY_URL = ConfigEntry(YamlConfigEntry("admin.httpProxyURL"))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Credentials(object):
|
|
14
|
+
SECTION = "credentials"
|
|
15
|
+
COMMAND = ConfigEntry(YamlConfigEntry("admin.command", list))
|
|
16
|
+
"""
|
|
17
|
+
This command is executed to return a token using an external process.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
PROXY_COMMAND = ConfigEntry(YamlConfigEntry("admin.proxyCommand", list))
|
|
21
|
+
"""
|
|
22
|
+
This command is executed to return a token for authorization with a proxy
|
|
23
|
+
in front of Flyte using an external process.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
CLIENT_ID = ConfigEntry(YamlConfigEntry("admin.clientId"))
|
|
27
|
+
"""
|
|
28
|
+
This is the public identifier for the app which handles authorization for a Flyte deployment.
|
|
29
|
+
More details here: https://www.oauth.com/oauth2-servers/client-registration/client-id-secret/.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
CLIENT_CREDENTIALS_SECRET_LOCATION = ConfigEntry(YamlConfigEntry("admin.clientSecretLocation"))
|
|
33
|
+
"""
|
|
34
|
+
Used for basic auth, which is automatically called during pyflyte. This will allow the Flyte engine to read the
|
|
35
|
+
password from a mounted file.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
CLIENT_CREDENTIALS_SECRET_ENV_VAR = ConfigEntry(YamlConfigEntry("admin.clientSecretEnvVar"))
|
|
39
|
+
"""
|
|
40
|
+
Used for basic auth, which is automatically called during pyflyte. This will allow the Flyte engine to read the
|
|
41
|
+
password from a mounted environment variable.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
SCOPES = ConfigEntry(YamlConfigEntry("admin.scopes", list))
|
|
45
|
+
"""
|
|
46
|
+
This setting can be used to manually pass in scopes into authenticator flows - eg.) for Auth0 compatibility
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
AUTH_MODE = ConfigEntry(YamlConfigEntry("admin.authType"))
|
|
50
|
+
"""
|
|
51
|
+
The auth mode defines the behavior used to request and refresh credentials. The currently supported modes include:
|
|
52
|
+
- 'standard' or 'Pkce': This uses the pkce-enhanced authorization code flow by opening a browser window to initiate
|
|
53
|
+
credentials access.
|
|
54
|
+
- "DeviceFlow": This uses the Device Authorization Flow
|
|
55
|
+
- 'basic', 'client_credentials' or 'clientSecret': This uses symmetric key auth in which the end user enters a
|
|
56
|
+
client id and a client secret and public key encryption is used to facilitate authentication.
|
|
57
|
+
- None: No auth will be attempted.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class Task(object):
|
|
62
|
+
ORG = ConfigEntry(YamlConfigEntry("task.org"))
|
|
63
|
+
PROJECT = ConfigEntry(YamlConfigEntry("task.project"))
|
|
64
|
+
DOMAIN = ConfigEntry(YamlConfigEntry("task.domain"))
|
flyte/remote/_console.py
CHANGED
|
@@ -7,7 +7,7 @@ def _get_http_domain(endpoint: str, insecure: bool) -> str:
|
|
|
7
7
|
if parsed.scheme == "dns":
|
|
8
8
|
domain = parsed.path.lstrip("/")
|
|
9
9
|
else:
|
|
10
|
-
domain = parsed.netloc
|
|
10
|
+
domain = parsed.netloc or parsed.path
|
|
11
11
|
# TODO: make console url configurable
|
|
12
12
|
if domain.split(":")[0] == "localhost":
|
|
13
13
|
domain = "localhost:8080"
|
flyte/types/_type_engine.py
CHANGED
|
@@ -450,7 +450,6 @@ class DataclassTransformer(TypeTransformer[object]):
|
|
|
450
450
|
# However, FooSchema is created by flytekit and it's not equal to the user-defined dataclass (Foo).
|
|
451
451
|
# Therefore, we should iterate all attributes in the dataclass and check the type of value in dataclass
|
|
452
452
|
# matches the expected_type.
|
|
453
|
-
|
|
454
453
|
expected_fields_dict = {}
|
|
455
454
|
|
|
456
455
|
for f in dataclasses.fields(expected_type):
|
|
@@ -1992,7 +1991,9 @@ DatetimeTransformer = SimpleTransformer(
|
|
|
1992
1991
|
datetime.datetime,
|
|
1993
1992
|
types_pb2.LiteralType(simple=types_pb2.SimpleType.DATETIME),
|
|
1994
1993
|
lambda x: Literal(scalar=Scalar(primitive=Primitive(datetime=x))),
|
|
1995
|
-
lambda x: x.scalar.primitive.datetime
|
|
1994
|
+
lambda x: x.scalar.primitive.datetime.ToDatetime().replace(tzinfo=datetime.timezone.utc)
|
|
1995
|
+
if x.scalar.primitive.HasField("datetime")
|
|
1996
|
+
else None,
|
|
1996
1997
|
)
|
|
1997
1998
|
|
|
1998
1999
|
TimedeltaTransformer = SimpleTransformer(
|
|
@@ -2000,7 +2001,7 @@ TimedeltaTransformer = SimpleTransformer(
|
|
|
2000
2001
|
datetime.timedelta,
|
|
2001
2002
|
types_pb2.LiteralType(simple=types_pb2.SimpleType.DURATION),
|
|
2002
2003
|
lambda x: Literal(scalar=Scalar(primitive=Primitive(duration=x))),
|
|
2003
|
-
lambda x: x.scalar.primitive.duration if x.scalar.primitive.HasField("duration") else None,
|
|
2004
|
+
lambda x: x.scalar.primitive.duration.ToTimedelta() if x.scalar.primitive.HasField("duration") else None,
|
|
2004
2005
|
)
|
|
2005
2006
|
|
|
2006
2007
|
DateTransformer = SimpleTransformer(
|