flyte 2.0.0b25__py3-none-any.whl → 2.0.0b28__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/__init__.py +2 -0
- flyte/_bin/runtime.py +8 -0
- flyte/_code_bundle/_utils.py +4 -4
- flyte/_code_bundle/bundle.py +1 -1
- flyte/_constants.py +1 -0
- flyte/_deploy.py +0 -1
- flyte/_excepthook.py +1 -1
- flyte/_initialize.py +10 -0
- flyte/_interface.py +2 -0
- flyte/_internal/imagebuild/docker_builder.py +3 -1
- flyte/_internal/imagebuild/remote_builder.py +3 -1
- flyte/_internal/resolvers/_task_module.py +4 -37
- flyte/_internal/runtime/convert.py +3 -2
- flyte/_internal/runtime/entrypoints.py +24 -1
- flyte/_internal/runtime/rusty.py +3 -3
- flyte/_internal/runtime/task_serde.py +19 -4
- flyte/_internal/runtime/trigger_serde.py +2 -2
- flyte/_map.py +2 -35
- flyte/_module.py +68 -0
- flyte/_resources.py +38 -0
- flyte/_run.py +23 -6
- flyte/_task.py +1 -2
- flyte/_task_plugins.py +4 -2
- flyte/_trigger.py +623 -5
- flyte/_utils/__init__.py +2 -1
- flyte/_utils/asyn.py +3 -1
- flyte/_utils/docker_credentials.py +173 -0
- flyte/_utils/module_loader.py +15 -0
- flyte/_version.py +3 -3
- flyte/cli/_common.py +15 -3
- flyte/cli/_create.py +100 -3
- flyte/cli/_deploy.py +38 -4
- flyte/cli/_plugins.py +208 -0
- flyte/cli/_run.py +69 -6
- flyte/cli/_serve.py +154 -0
- flyte/cli/main.py +6 -0
- flyte/connectors/__init__.py +3 -0
- flyte/connectors/_connector.py +270 -0
- flyte/connectors/_server.py +183 -0
- flyte/connectors/utils.py +26 -0
- flyte/models.py +13 -4
- flyte/remote/_client/auth/_channel.py +9 -5
- flyte/remote/_console.py +3 -2
- flyte/remote/_secret.py +6 -4
- flyte/remote/_trigger.py +2 -2
- flyte/types/_type_engine.py +1 -2
- {flyte-2.0.0b25.data → flyte-2.0.0b28.data}/scripts/runtime.py +8 -0
- {flyte-2.0.0b25.dist-info → flyte-2.0.0b28.dist-info}/METADATA +6 -2
- {flyte-2.0.0b25.dist-info → flyte-2.0.0b28.dist-info}/RECORD +54 -46
- {flyte-2.0.0b25.data → flyte-2.0.0b28.data}/scripts/debug.py +0 -0
- {flyte-2.0.0b25.dist-info → flyte-2.0.0b28.dist-info}/WHEEL +0 -0
- {flyte-2.0.0b25.dist-info → flyte-2.0.0b28.dist-info}/entry_points.txt +0 -0
- {flyte-2.0.0b25.dist-info → flyte-2.0.0b28.dist-info}/licenses/LICENSE +0 -0
- {flyte-2.0.0b25.dist-info → flyte-2.0.0b28.dist-info}/top_level.txt +0 -0
flyte/_utils/__init__.py
CHANGED
|
@@ -9,12 +9,13 @@ from .coro_management import run_coros
|
|
|
9
9
|
from .file_handling import filehash_update, update_hasher_for_source
|
|
10
10
|
from .helpers import get_cwd_editable_install
|
|
11
11
|
from .lazy_module import lazy_module
|
|
12
|
-
from .module_loader import load_python_modules
|
|
12
|
+
from .module_loader import adjust_sys_path, load_python_modules
|
|
13
13
|
from .org_discovery import hostname_from_url, org_from_endpoint, sanitize_endpoint
|
|
14
14
|
from .uv_script_parser import parse_uv_script_file
|
|
15
15
|
|
|
16
16
|
__all__ = [
|
|
17
17
|
"AsyncLRUCache",
|
|
18
|
+
"adjust_sys_path",
|
|
18
19
|
"filehash_update",
|
|
19
20
|
"get_cwd_editable_install",
|
|
20
21
|
"hostname_from_url",
|
flyte/_utils/asyn.py
CHANGED
|
@@ -9,6 +9,8 @@ async def async_add(a: int, b: int) -> int:
|
|
|
9
9
|
result = run_sync(async_add, a=10, b=12)
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
12
14
|
import asyncio
|
|
13
15
|
import atexit
|
|
14
16
|
import functools
|
|
@@ -88,7 +90,7 @@ class _TaskRunner:
|
|
|
88
90
|
|
|
89
91
|
|
|
90
92
|
class _AsyncLoopManager:
|
|
91
|
-
def __init__(self):
|
|
93
|
+
def __init__(self: _AsyncLoopManager):
|
|
92
94
|
self._runner_map: dict[str, _TaskRunner] = {}
|
|
93
95
|
|
|
94
96
|
def run_sync(self, coro_func: Callable[..., Awaitable[T]], *args, **kwargs) -> T:
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Helper functions for creating Docker registry credentials for image pull secrets."""
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
_CONFIG_JSON = "config.json"
|
|
14
|
+
_DEFAULT_CONFIG_PATH = f"~/.docker/{_CONFIG_JSON}"
|
|
15
|
+
_CRED_HELPERS = "credHelpers"
|
|
16
|
+
_CREDS_STORE = "credsStore"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _load_docker_config(config_path: str | Path | None = None) -> dict[str, Any]:
|
|
20
|
+
"""
|
|
21
|
+
Load Docker config from specified path.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
config_path: Path to Docker config file. If None, uses DOCKER_CONFIG env var
|
|
25
|
+
or defaults to ~/.docker/config.json
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dictionary containing Docker config
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
FileNotFoundError: If the config file does not exist
|
|
32
|
+
json.JSONDecodeError: If the config file is not valid JSON
|
|
33
|
+
"""
|
|
34
|
+
if not config_path:
|
|
35
|
+
docker_config_env = os.environ.get("DOCKER_CONFIG")
|
|
36
|
+
if docker_config_env:
|
|
37
|
+
config_path = Path(docker_config_env) / _CONFIG_JSON
|
|
38
|
+
else:
|
|
39
|
+
config_path = Path(_DEFAULT_CONFIG_PATH).expanduser()
|
|
40
|
+
else:
|
|
41
|
+
config_path = Path(config_path).expanduser()
|
|
42
|
+
|
|
43
|
+
with open(config_path) as f:
|
|
44
|
+
return json.load(f)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _get_credential_helper(config: dict[str, Any], registry: str | None = None) -> str | None:
|
|
48
|
+
"""Get credential helper for registry or global default."""
|
|
49
|
+
if registry and _CRED_HELPERS in config and registry in config[_CRED_HELPERS]:
|
|
50
|
+
return config[_CRED_HELPERS].get(registry)
|
|
51
|
+
return config.get(_CREDS_STORE)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _get_credentials_from_helper(helper: str, registry: str) -> tuple[str, str] | None:
|
|
55
|
+
"""
|
|
56
|
+
Get credentials from system credential helper.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
helper: Name of the credential helper (e.g., "osxkeychain", "wincred")
|
|
60
|
+
registry: Registry hostname to get credentials for
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Tuple of (username, password) or None if credentials cannot be retrieved
|
|
64
|
+
"""
|
|
65
|
+
helper_cmd = f"docker-credential-{helper}"
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
process = subprocess.Popen(
|
|
69
|
+
[helper_cmd, "get"],
|
|
70
|
+
stdin=subprocess.PIPE,
|
|
71
|
+
stdout=subprocess.PIPE,
|
|
72
|
+
stderr=subprocess.PIPE,
|
|
73
|
+
text=True,
|
|
74
|
+
)
|
|
75
|
+
output, error = process.communicate(input=registry)
|
|
76
|
+
|
|
77
|
+
if process.returncode != 0:
|
|
78
|
+
logger.error(f"Credential helper error: {error}")
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
creds = json.loads(output)
|
|
82
|
+
return creds.get("Username"), creds.get("Secret")
|
|
83
|
+
except FileNotFoundError:
|
|
84
|
+
logger.error(f"Credential helper {helper_cmd} not found in PATH")
|
|
85
|
+
return None
|
|
86
|
+
except Exception as e:
|
|
87
|
+
logger.error(f"Error getting credentials: {e!s}")
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def create_dockerconfigjson_from_config(
|
|
92
|
+
registries: list[str] | None = None,
|
|
93
|
+
docker_config_path: str | Path | None = None,
|
|
94
|
+
) -> str:
|
|
95
|
+
"""
|
|
96
|
+
Create a dockerconfigjson string from existing Docker config.
|
|
97
|
+
|
|
98
|
+
This function extracts Docker registry credentials from the user's Docker config file
|
|
99
|
+
and creates a JSON string containing only the credentials for the specified registries.
|
|
100
|
+
It handles credentials stored directly in the config file as well as those managed by
|
|
101
|
+
credential helpers.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
registries: List of registries to extract credentials for. If None, all registries
|
|
105
|
+
from the config will be used.
|
|
106
|
+
docker_config_path: Path to the Docker config file. If None, the function will look
|
|
107
|
+
for the config file in the standard locations.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
JSON string in dockerconfigjson format: {"auths": {"registry": {"auth": "..."}}}
|
|
111
|
+
|
|
112
|
+
Raises:
|
|
113
|
+
FileNotFoundError: If Docker config file cannot be found
|
|
114
|
+
ValueError: If no credentials can be extracted
|
|
115
|
+
"""
|
|
116
|
+
config = _load_docker_config(docker_config_path)
|
|
117
|
+
|
|
118
|
+
# Create new config structure with empty auths
|
|
119
|
+
new_config: dict[str, Any] = {"auths": {}}
|
|
120
|
+
|
|
121
|
+
# Use specified registries or all from config
|
|
122
|
+
target_registries = registries or list(config.get("auths", {}).keys())
|
|
123
|
+
|
|
124
|
+
if not target_registries:
|
|
125
|
+
raise ValueError("No registries found in Docker config and none specified")
|
|
126
|
+
|
|
127
|
+
for registry in target_registries:
|
|
128
|
+
registry_config = config.get("auths", {}).get(registry, {})
|
|
129
|
+
if registry_config.get("auth"):
|
|
130
|
+
# Direct auth token exists
|
|
131
|
+
new_config["auths"][registry] = {"auth": registry_config["auth"]}
|
|
132
|
+
else:
|
|
133
|
+
# Try to get credentials from helper
|
|
134
|
+
helper = _get_credential_helper(config, registry)
|
|
135
|
+
if helper:
|
|
136
|
+
creds = _get_credentials_from_helper(helper, registry)
|
|
137
|
+
if creds:
|
|
138
|
+
username, password = creds
|
|
139
|
+
auth_string = f"{username}:{password}"
|
|
140
|
+
new_config["auths"][registry] = {"auth": base64.b64encode(auth_string.encode()).decode()}
|
|
141
|
+
else:
|
|
142
|
+
logger.warning(f"Could not retrieve credentials for {registry} from credential helper")
|
|
143
|
+
else:
|
|
144
|
+
logger.warning(f"No credentials found for {registry}")
|
|
145
|
+
|
|
146
|
+
if not new_config["auths"]:
|
|
147
|
+
raise ValueError(f"No credentials could be extracted for registries: {', '.join(target_registries)}")
|
|
148
|
+
|
|
149
|
+
return json.dumps(new_config)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def create_dockerconfigjson_from_credentials(
|
|
153
|
+
registry: str,
|
|
154
|
+
username: str,
|
|
155
|
+
password: str,
|
|
156
|
+
) -> str:
|
|
157
|
+
"""
|
|
158
|
+
Create a dockerconfigjson string from explicit credentials.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
registry: Registry hostname (e.g., "ghcr.io", "docker.io")
|
|
162
|
+
username: Username or token name for the registry
|
|
163
|
+
password: Password or access token for the registry
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
JSON string in dockerconfigjson format: {"auths": {"registry": {"auth": "..."}}}
|
|
167
|
+
"""
|
|
168
|
+
auth_string = f"{username}:{password}"
|
|
169
|
+
auth_token = base64.b64encode(auth_string.encode()).decode()
|
|
170
|
+
|
|
171
|
+
config = {"auths": {registry: {"auth": auth_token}}}
|
|
172
|
+
|
|
173
|
+
return json.dumps(config)
|
flyte/_utils/module_loader.py
CHANGED
|
@@ -6,6 +6,8 @@ from pathlib import Path
|
|
|
6
6
|
from typing import List, Tuple
|
|
7
7
|
|
|
8
8
|
import flyte.errors
|
|
9
|
+
from flyte._constants import FLYTE_SYS_PATH
|
|
10
|
+
from flyte._logging import logger
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
def load_python_modules(path: Path, recursive: bool = False) -> Tuple[List[str], List[Tuple[Path, str]]]:
|
|
@@ -87,3 +89,16 @@ def _load_module_from_file(file_path: Path) -> str | None:
|
|
|
87
89
|
|
|
88
90
|
except Exception as e:
|
|
89
91
|
raise flyte.errors.ModuleLoadError(f"Failed to load module from {file_path}: {e}") from e
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def adjust_sys_path():
|
|
95
|
+
"""
|
|
96
|
+
Adjust sys.path to include local sys.path entries under the root directory.
|
|
97
|
+
"""
|
|
98
|
+
if "." not in sys.path or os.getcwd() not in sys.path:
|
|
99
|
+
sys.path.insert(0, ".")
|
|
100
|
+
logger.info(f"Added {os.getcwd()} to sys.path")
|
|
101
|
+
for p in os.environ.get(FLYTE_SYS_PATH, "").split(":"):
|
|
102
|
+
if p and p not in sys.path:
|
|
103
|
+
sys.path.insert(0, p)
|
|
104
|
+
logger.info(f"Added {p} to sys.path")
|
flyte/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '2.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (2, 0, 0, '
|
|
31
|
+
__version__ = version = '2.0.0b28'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 0, 0, 'b28')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'gb62a542c8'
|
flyte/cli/_common.py
CHANGED
|
@@ -120,6 +120,7 @@ class CLIConfig:
|
|
|
120
120
|
domain: str | None = None,
|
|
121
121
|
root_dir: str | None = None,
|
|
122
122
|
images: tuple[str, ...] | None = None,
|
|
123
|
+
sync_local_sys_paths: bool = True,
|
|
123
124
|
):
|
|
124
125
|
from flyte.config._config import TaskConfig
|
|
125
126
|
|
|
@@ -140,7 +141,13 @@ class CLIConfig:
|
|
|
140
141
|
|
|
141
142
|
updated_config = self.config.with_params(platform_cfg, task_cfg)
|
|
142
143
|
|
|
143
|
-
flyte.init_from_config(
|
|
144
|
+
flyte.init_from_config(
|
|
145
|
+
updated_config,
|
|
146
|
+
log_level=self.log_level,
|
|
147
|
+
root_dir=root_dir,
|
|
148
|
+
images=images,
|
|
149
|
+
sync_local_sys_paths=sync_local_sys_paths,
|
|
150
|
+
)
|
|
144
151
|
|
|
145
152
|
|
|
146
153
|
class InvokeBaseMixin:
|
|
@@ -440,7 +447,12 @@ def parse_images(cfg: Config, values: tuple[str, ...] | None) -> None:
|
|
|
440
447
|
|
|
441
448
|
@lru_cache()
|
|
442
449
|
def initialize_config(
|
|
443
|
-
ctx: click.Context,
|
|
450
|
+
ctx: click.Context,
|
|
451
|
+
project: str,
|
|
452
|
+
domain: str,
|
|
453
|
+
root_dir: str | None = None,
|
|
454
|
+
images: tuple[str, ...] | None = None,
|
|
455
|
+
sync_local_sys_paths: bool = True,
|
|
444
456
|
):
|
|
445
457
|
obj: CLIConfig | None = ctx.obj
|
|
446
458
|
if obj is None:
|
|
@@ -448,5 +460,5 @@ def initialize_config(
|
|
|
448
460
|
|
|
449
461
|
obj = CLIConfig(flyte.config.auto(), ctx)
|
|
450
462
|
|
|
451
|
-
obj.init(project, domain, root_dir, images)
|
|
463
|
+
obj.init(project, domain, root_dir, images, sync_local_sys_paths)
|
|
452
464
|
return obj
|
flyte/cli/_create.py
CHANGED
|
@@ -24,18 +24,49 @@ def create():
|
|
|
24
24
|
prompt="Enter secret value",
|
|
25
25
|
hide_input=True,
|
|
26
26
|
cls=MutuallyExclusiveOption,
|
|
27
|
-
mutually_exclusive=["from_file"],
|
|
27
|
+
mutually_exclusive=["from_file", "from_docker_config", "registry"],
|
|
28
28
|
)
|
|
29
29
|
@click.option(
|
|
30
30
|
"--from-file",
|
|
31
31
|
type=click.Path(exists=True),
|
|
32
32
|
help="Path to the file with the binary secret.",
|
|
33
33
|
cls=MutuallyExclusiveOption,
|
|
34
|
-
mutually_exclusive=["value"],
|
|
34
|
+
mutually_exclusive=["value", "from_docker_config", "registry"],
|
|
35
35
|
)
|
|
36
36
|
@click.option(
|
|
37
37
|
"--type", type=click.Choice(get_args(SecretTypes)), default="regular", help="Type of the secret.", show_default=True
|
|
38
38
|
)
|
|
39
|
+
@click.option(
|
|
40
|
+
"--from-docker-config",
|
|
41
|
+
is_flag=True,
|
|
42
|
+
help="Create image pull secret from Docker config file (only for --type image_pull).",
|
|
43
|
+
cls=MutuallyExclusiveOption,
|
|
44
|
+
mutually_exclusive=["value", "from_file", "registry", "username", "password"],
|
|
45
|
+
)
|
|
46
|
+
@click.option(
|
|
47
|
+
"--docker-config-path",
|
|
48
|
+
type=click.Path(exists=True),
|
|
49
|
+
help="Path to Docker config file (defaults to ~/.docker/config.json or $DOCKER_CONFIG).",
|
|
50
|
+
)
|
|
51
|
+
@click.option(
|
|
52
|
+
"--registries",
|
|
53
|
+
help="Comma-separated list of registries to include (only with --from-docker-config).",
|
|
54
|
+
)
|
|
55
|
+
@click.option(
|
|
56
|
+
"--registry",
|
|
57
|
+
help="Registry hostname (e.g., ghcr.io, docker.io) for explicit credentials (only for --type image_pull).",
|
|
58
|
+
cls=MutuallyExclusiveOption,
|
|
59
|
+
mutually_exclusive=["value", "from_file", "from_docker_config"],
|
|
60
|
+
)
|
|
61
|
+
@click.option(
|
|
62
|
+
"--username",
|
|
63
|
+
help="Username for the registry (only with --registry).",
|
|
64
|
+
)
|
|
65
|
+
@click.option(
|
|
66
|
+
"--password",
|
|
67
|
+
help="Password for the registry (only with --registry). If not provided, will prompt.",
|
|
68
|
+
hide_input=True,
|
|
69
|
+
)
|
|
39
70
|
@click.pass_obj
|
|
40
71
|
def secret(
|
|
41
72
|
cfg: common.CLIConfig,
|
|
@@ -43,6 +74,12 @@ def secret(
|
|
|
43
74
|
value: str | bytes | None = None,
|
|
44
75
|
from_file: str | None = None,
|
|
45
76
|
type: SecretTypes = "regular",
|
|
77
|
+
from_docker_config: bool = False,
|
|
78
|
+
docker_config_path: str | None = None,
|
|
79
|
+
registries: str | None = None,
|
|
80
|
+
registry: str | None = None,
|
|
81
|
+
username: str | None = None,
|
|
82
|
+
password: str | None = None,
|
|
46
83
|
project: str | None = None,
|
|
47
84
|
domain: str | None = None,
|
|
48
85
|
):
|
|
@@ -73,9 +110,24 @@ def secret(
|
|
|
73
110
|
Other secrets should be specified as `regular`.
|
|
74
111
|
If no type is specified, `regular` is assumed.
|
|
75
112
|
|
|
113
|
+
For image pull secrets, you have several options:
|
|
114
|
+
|
|
115
|
+
1. Interactive mode (prompts for registry, username, password):
|
|
76
116
|
```bash
|
|
77
117
|
$ flyte create secret my_secret --type image_pull
|
|
78
118
|
```
|
|
119
|
+
|
|
120
|
+
2. With explicit credentials:
|
|
121
|
+
```bash
|
|
122
|
+
$ flyte create secret my_secret --type image_pull --registry ghcr.io --username myuser
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
3. Lastly, you can create a secret from your existing Docker installation (i.e., you've run `docker login` in
|
|
126
|
+
the past) and you just want to pull from those credentials. Since you may have logged in to multiple registries,
|
|
127
|
+
you can specify which registries to include. If no registries are specified, all registries are added.
|
|
128
|
+
```bash
|
|
129
|
+
$ flyte create secret my_secret --type image_pull --from-docker-config --registries ghcr.io,docker.io
|
|
130
|
+
```
|
|
79
131
|
"""
|
|
80
132
|
from flyte.remote import Secret
|
|
81
133
|
|
|
@@ -84,9 +136,54 @@ def secret(
|
|
|
84
136
|
project = "" if project is None else project
|
|
85
137
|
domain = "" if domain is None else domain
|
|
86
138
|
cfg.init(project, domain)
|
|
87
|
-
|
|
139
|
+
|
|
140
|
+
# Handle image pull secret creation
|
|
141
|
+
if type == "image_pull":
|
|
142
|
+
if project != "" or domain != "":
|
|
143
|
+
raise click.ClickException("Project and domain must not be set when creating an image pull secret.")
|
|
144
|
+
|
|
145
|
+
if from_docker_config:
|
|
146
|
+
# Mode 3: From Docker config
|
|
147
|
+
from flyte._utils.docker_credentials import create_dockerconfigjson_from_config
|
|
148
|
+
|
|
149
|
+
registry_list = [r.strip() for r in registries.split(",")] if registries else None
|
|
150
|
+
try:
|
|
151
|
+
value = create_dockerconfigjson_from_config(
|
|
152
|
+
registries=registry_list,
|
|
153
|
+
docker_config_path=docker_config_path,
|
|
154
|
+
)
|
|
155
|
+
except Exception as e:
|
|
156
|
+
raise click.ClickException(f"Failed to create dockerconfigjson from Docker config: {e}") from e
|
|
157
|
+
|
|
158
|
+
elif registry:
|
|
159
|
+
# Mode 2: Explicit credentials
|
|
160
|
+
from flyte._utils.docker_credentials import create_dockerconfigjson_from_credentials
|
|
161
|
+
|
|
162
|
+
if not username:
|
|
163
|
+
username = click.prompt("Username")
|
|
164
|
+
if not password:
|
|
165
|
+
password = click.prompt("Password", hide_input=True)
|
|
166
|
+
|
|
167
|
+
value = create_dockerconfigjson_from_credentials(registry, username, password)
|
|
168
|
+
|
|
169
|
+
else:
|
|
170
|
+
# Mode 1: Interactive prompts
|
|
171
|
+
from flyte._utils.docker_credentials import create_dockerconfigjson_from_credentials
|
|
172
|
+
|
|
173
|
+
registry = click.prompt("Registry (e.g., ghcr.io, docker.io)")
|
|
174
|
+
username = click.prompt("Username")
|
|
175
|
+
password = click.prompt("Password", hide_input=True)
|
|
176
|
+
|
|
177
|
+
value = create_dockerconfigjson_from_credentials(registry, username, password)
|
|
178
|
+
|
|
179
|
+
elif from_file:
|
|
88
180
|
with open(from_file, "rb") as f:
|
|
89
181
|
value = f.read()
|
|
182
|
+
|
|
183
|
+
# Encode string values to bytes
|
|
184
|
+
if isinstance(value, str):
|
|
185
|
+
value = value.encode("utf-8")
|
|
186
|
+
|
|
90
187
|
Secret.create(name=name, value=value, type=type)
|
|
91
188
|
|
|
92
189
|
|
flyte/cli/_deploy.py
CHANGED
|
@@ -83,6 +83,19 @@ class DeployArguments:
|
|
|
83
83
|
)
|
|
84
84
|
},
|
|
85
85
|
)
|
|
86
|
+
no_sync_local_sys_paths: bool = field(
|
|
87
|
+
default=True,
|
|
88
|
+
metadata={
|
|
89
|
+
"click.option": click.Option(
|
|
90
|
+
["--no-sync-local-sys-paths"],
|
|
91
|
+
is_flag=True,
|
|
92
|
+
flag_value=True,
|
|
93
|
+
default=False,
|
|
94
|
+
help="Disable synchronization of local sys.path entries under the root directory "
|
|
95
|
+
"to the remote container.",
|
|
96
|
+
)
|
|
97
|
+
},
|
|
98
|
+
)
|
|
86
99
|
|
|
87
100
|
@classmethod
|
|
88
101
|
def from_dict(cls, d: Dict[str, Any]) -> "DeployArguments":
|
|
@@ -107,7 +120,12 @@ class DeployEnvCommand(click.RichCommand):
|
|
|
107
120
|
console = common.get_console()
|
|
108
121
|
console.print(f"Deploying root - environment: {self.env_name}")
|
|
109
122
|
obj: CLIConfig = ctx.obj
|
|
110
|
-
obj.init(
|
|
123
|
+
obj.init(
|
|
124
|
+
self.deploy_args.project,
|
|
125
|
+
self.deploy_args.domain,
|
|
126
|
+
root_dir=self.deploy_args.root_dir,
|
|
127
|
+
sync_local_sys_paths=not self.deploy_args.no_sync_local_sys_paths,
|
|
128
|
+
)
|
|
111
129
|
with console.status("Deploying...", spinner="dots"):
|
|
112
130
|
deployment = flyte.deploy(
|
|
113
131
|
self.env,
|
|
@@ -161,7 +179,11 @@ class DeployEnvRecursiveCommand(click.Command):
|
|
|
161
179
|
f"Failed to load {len(failed_paths)} files. Use --ignore-load-errors to ignore these errors."
|
|
162
180
|
)
|
|
163
181
|
# Now start connection and deploy all environments
|
|
164
|
-
obj.init(
|
|
182
|
+
obj.init(
|
|
183
|
+
self.deploy_args.project,
|
|
184
|
+
self.deploy_args.domain,
|
|
185
|
+
sync_local_sys_paths=not self.deploy_args.no_sync_local_sys_paths,
|
|
186
|
+
)
|
|
165
187
|
with console.status("Deploying...", spinner="dots"):
|
|
166
188
|
deployments = flyte.deploy(
|
|
167
189
|
*all_envs,
|
|
@@ -190,11 +212,23 @@ class EnvPerFileGroup(common.ObjectsPerFileGroup):
|
|
|
190
212
|
return {k: v for k, v in module.__dict__.items() if isinstance(v, flyte.Environment)}
|
|
191
213
|
|
|
192
214
|
def list_commands(self, ctx):
|
|
193
|
-
common.initialize_config(
|
|
215
|
+
common.initialize_config(
|
|
216
|
+
ctx,
|
|
217
|
+
self.deploy_args.project,
|
|
218
|
+
self.deploy_args.domain,
|
|
219
|
+
self.deploy_args.root_dir,
|
|
220
|
+
sync_local_sys_paths=not self.deploy_args.no_sync_local_sys_paths,
|
|
221
|
+
)
|
|
194
222
|
return super().list_commands(ctx)
|
|
195
223
|
|
|
196
224
|
def get_command(self, ctx, obj_name):
|
|
197
|
-
common.initialize_config(
|
|
225
|
+
common.initialize_config(
|
|
226
|
+
ctx,
|
|
227
|
+
self.deploy_args.project,
|
|
228
|
+
self.deploy_args.domain,
|
|
229
|
+
self.deploy_args.root_dir,
|
|
230
|
+
sync_local_sys_paths=not self.deploy_args.no_sync_local_sys_paths,
|
|
231
|
+
)
|
|
198
232
|
return super().get_command(ctx, obj_name)
|
|
199
233
|
|
|
200
234
|
def _get_command_for_obj(self, ctx: click.Context, obj_name: str, obj: Any) -> click.Command:
|