flyte 2.0.0b32__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 +108 -0
- flyte/_bin/__init__.py +0 -0
- flyte/_bin/debug.py +38 -0
- flyte/_bin/runtime.py +195 -0
- flyte/_bin/serve.py +178 -0
- flyte/_build.py +26 -0
- flyte/_cache/__init__.py +12 -0
- flyte/_cache/cache.py +147 -0
- flyte/_cache/defaults.py +9 -0
- flyte/_cache/local_cache.py +216 -0
- flyte/_cache/policy_function_body.py +42 -0
- flyte/_code_bundle/__init__.py +8 -0
- flyte/_code_bundle/_ignore.py +121 -0
- flyte/_code_bundle/_packaging.py +218 -0
- flyte/_code_bundle/_utils.py +347 -0
- flyte/_code_bundle/bundle.py +266 -0
- flyte/_constants.py +1 -0
- flyte/_context.py +155 -0
- flyte/_custom_context.py +73 -0
- flyte/_debug/__init__.py +0 -0
- flyte/_debug/constants.py +38 -0
- flyte/_debug/utils.py +17 -0
- flyte/_debug/vscode.py +307 -0
- flyte/_deploy.py +408 -0
- flyte/_deployer.py +109 -0
- flyte/_doc.py +29 -0
- flyte/_docstring.py +32 -0
- flyte/_environment.py +122 -0
- flyte/_excepthook.py +37 -0
- flyte/_group.py +32 -0
- flyte/_hash.py +8 -0
- flyte/_image.py +1055 -0
- flyte/_initialize.py +628 -0
- flyte/_interface.py +119 -0
- flyte/_internal/__init__.py +3 -0
- flyte/_internal/controllers/__init__.py +129 -0
- flyte/_internal/controllers/_local_controller.py +239 -0
- flyte/_internal/controllers/_trace.py +48 -0
- flyte/_internal/controllers/remote/__init__.py +58 -0
- flyte/_internal/controllers/remote/_action.py +211 -0
- flyte/_internal/controllers/remote/_client.py +47 -0
- flyte/_internal/controllers/remote/_controller.py +583 -0
- flyte/_internal/controllers/remote/_core.py +465 -0
- flyte/_internal/controllers/remote/_informer.py +381 -0
- flyte/_internal/controllers/remote/_service_protocol.py +50 -0
- flyte/_internal/imagebuild/__init__.py +3 -0
- flyte/_internal/imagebuild/docker_builder.py +706 -0
- flyte/_internal/imagebuild/image_builder.py +277 -0
- flyte/_internal/imagebuild/remote_builder.py +386 -0
- flyte/_internal/imagebuild/utils.py +78 -0
- flyte/_internal/resolvers/__init__.py +0 -0
- flyte/_internal/resolvers/_task_module.py +21 -0
- flyte/_internal/resolvers/common.py +31 -0
- flyte/_internal/resolvers/default.py +28 -0
- flyte/_internal/runtime/__init__.py +0 -0
- flyte/_internal/runtime/convert.py +486 -0
- flyte/_internal/runtime/entrypoints.py +204 -0
- flyte/_internal/runtime/io.py +188 -0
- flyte/_internal/runtime/resources_serde.py +152 -0
- flyte/_internal/runtime/reuse.py +125 -0
- flyte/_internal/runtime/rusty.py +193 -0
- flyte/_internal/runtime/task_serde.py +362 -0
- flyte/_internal/runtime/taskrunner.py +209 -0
- flyte/_internal/runtime/trigger_serde.py +160 -0
- flyte/_internal/runtime/types_serde.py +54 -0
- flyte/_keyring/__init__.py +0 -0
- flyte/_keyring/file.py +115 -0
- flyte/_logging.py +300 -0
- flyte/_map.py +312 -0
- flyte/_module.py +72 -0
- flyte/_pod.py +30 -0
- flyte/_resources.py +473 -0
- flyte/_retry.py +32 -0
- flyte/_reusable_environment.py +102 -0
- flyte/_run.py +724 -0
- flyte/_secret.py +96 -0
- flyte/_task.py +550 -0
- flyte/_task_environment.py +316 -0
- flyte/_task_plugins.py +47 -0
- flyte/_timeout.py +47 -0
- flyte/_tools.py +27 -0
- flyte/_trace.py +119 -0
- flyte/_trigger.py +1000 -0
- flyte/_utils/__init__.py +30 -0
- flyte/_utils/asyn.py +121 -0
- flyte/_utils/async_cache.py +139 -0
- flyte/_utils/coro_management.py +27 -0
- flyte/_utils/docker_credentials.py +173 -0
- flyte/_utils/file_handling.py +72 -0
- flyte/_utils/helpers.py +134 -0
- flyte/_utils/lazy_module.py +54 -0
- flyte/_utils/module_loader.py +104 -0
- flyte/_utils/org_discovery.py +57 -0
- flyte/_utils/uv_script_parser.py +49 -0
- flyte/_version.py +34 -0
- flyte/app/__init__.py +22 -0
- flyte/app/_app_environment.py +157 -0
- flyte/app/_deploy.py +125 -0
- flyte/app/_input.py +160 -0
- flyte/app/_runtime/__init__.py +3 -0
- flyte/app/_runtime/app_serde.py +347 -0
- flyte/app/_types.py +101 -0
- flyte/app/extras/__init__.py +3 -0
- flyte/app/extras/_fastapi.py +151 -0
- flyte/cli/__init__.py +12 -0
- flyte/cli/_abort.py +28 -0
- flyte/cli/_build.py +114 -0
- flyte/cli/_common.py +468 -0
- flyte/cli/_create.py +371 -0
- flyte/cli/_delete.py +45 -0
- flyte/cli/_deploy.py +293 -0
- flyte/cli/_gen.py +176 -0
- flyte/cli/_get.py +370 -0
- flyte/cli/_option.py +33 -0
- flyte/cli/_params.py +554 -0
- flyte/cli/_plugins.py +209 -0
- flyte/cli/_run.py +597 -0
- flyte/cli/_serve.py +64 -0
- flyte/cli/_update.py +37 -0
- flyte/cli/_user.py +17 -0
- flyte/cli/main.py +221 -0
- flyte/config/__init__.py +3 -0
- flyte/config/_config.py +248 -0
- flyte/config/_internal.py +73 -0
- flyte/config/_reader.py +225 -0
- flyte/connectors/__init__.py +11 -0
- flyte/connectors/_connector.py +270 -0
- flyte/connectors/_server.py +197 -0
- flyte/connectors/utils.py +135 -0
- flyte/errors.py +243 -0
- flyte/extend.py +19 -0
- flyte/extras/__init__.py +5 -0
- flyte/extras/_container.py +286 -0
- flyte/git/__init__.py +3 -0
- flyte/git/_config.py +21 -0
- flyte/io/__init__.py +29 -0
- flyte/io/_dataframe/__init__.py +131 -0
- flyte/io/_dataframe/basic_dfs.py +223 -0
- flyte/io/_dataframe/dataframe.py +1026 -0
- flyte/io/_dir.py +910 -0
- flyte/io/_file.py +914 -0
- flyte/io/_hashing_io.py +342 -0
- flyte/models.py +479 -0
- flyte/py.typed +0 -0
- flyte/remote/__init__.py +35 -0
- flyte/remote/_action.py +738 -0
- flyte/remote/_app.py +57 -0
- flyte/remote/_client/__init__.py +0 -0
- flyte/remote/_client/_protocols.py +189 -0
- flyte/remote/_client/auth/__init__.py +12 -0
- flyte/remote/_client/auth/_auth_utils.py +14 -0
- flyte/remote/_client/auth/_authenticators/__init__.py +0 -0
- flyte/remote/_client/auth/_authenticators/base.py +403 -0
- flyte/remote/_client/auth/_authenticators/client_credentials.py +73 -0
- flyte/remote/_client/auth/_authenticators/device_code.py +117 -0
- flyte/remote/_client/auth/_authenticators/external_command.py +79 -0
- flyte/remote/_client/auth/_authenticators/factory.py +200 -0
- flyte/remote/_client/auth/_authenticators/pkce.py +516 -0
- flyte/remote/_client/auth/_channel.py +213 -0
- flyte/remote/_client/auth/_client_config.py +85 -0
- flyte/remote/_client/auth/_default_html.py +32 -0
- flyte/remote/_client/auth/_grpc_utils/__init__.py +0 -0
- flyte/remote/_client/auth/_grpc_utils/auth_interceptor.py +288 -0
- flyte/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +151 -0
- flyte/remote/_client/auth/_keyring.py +152 -0
- flyte/remote/_client/auth/_token_client.py +260 -0
- flyte/remote/_client/auth/errors.py +16 -0
- flyte/remote/_client/controlplane.py +128 -0
- flyte/remote/_common.py +30 -0
- flyte/remote/_console.py +19 -0
- flyte/remote/_data.py +161 -0
- flyte/remote/_logs.py +185 -0
- flyte/remote/_project.py +88 -0
- flyte/remote/_run.py +386 -0
- flyte/remote/_secret.py +142 -0
- flyte/remote/_task.py +527 -0
- flyte/remote/_trigger.py +306 -0
- flyte/remote/_user.py +33 -0
- flyte/report/__init__.py +3 -0
- flyte/report/_report.py +182 -0
- flyte/report/_template.html +124 -0
- flyte/storage/__init__.py +36 -0
- flyte/storage/_config.py +237 -0
- flyte/storage/_parallel_reader.py +274 -0
- flyte/storage/_remote_fs.py +34 -0
- flyte/storage/_storage.py +456 -0
- flyte/storage/_utils.py +5 -0
- flyte/syncify/__init__.py +56 -0
- flyte/syncify/_api.py +375 -0
- flyte/types/__init__.py +52 -0
- flyte/types/_interface.py +40 -0
- flyte/types/_pickle.py +145 -0
- flyte/types/_renderer.py +162 -0
- flyte/types/_string_literals.py +119 -0
- flyte/types/_type_engine.py +2254 -0
- flyte/types/_utils.py +80 -0
- flyte-2.0.0b32.data/scripts/debug.py +38 -0
- flyte-2.0.0b32.data/scripts/runtime.py +195 -0
- flyte-2.0.0b32.dist-info/METADATA +351 -0
- flyte-2.0.0b32.dist-info/RECORD +204 -0
- flyte-2.0.0b32.dist-info/WHEEL +5 -0
- flyte-2.0.0b32.dist-info/entry_points.txt +7 -0
- flyte-2.0.0b32.dist-info/licenses/LICENSE +201 -0
- flyte-2.0.0b32.dist-info/top_level.txt +1 -0
flyte/remote/_run.py
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import AsyncGenerator, AsyncIterator, Literal, Tuple
|
|
5
|
+
|
|
6
|
+
import grpc
|
|
7
|
+
import rich.repr
|
|
8
|
+
from flyteidl2.common import identifier_pb2, list_pb2
|
|
9
|
+
from flyteidl2.workflow import run_definition_pb2, run_service_pb2
|
|
10
|
+
|
|
11
|
+
from flyte._initialize import ensure_client, get_client, get_init_config
|
|
12
|
+
from flyte._logging import logger
|
|
13
|
+
from flyte.syncify import syncify
|
|
14
|
+
|
|
15
|
+
from . import Action, ActionDetails, ActionInputs, ActionOutputs
|
|
16
|
+
from ._action import _action_details_rich_repr, _action_rich_repr
|
|
17
|
+
from ._common import ToJSONMixin
|
|
18
|
+
from ._console import get_run_url
|
|
19
|
+
|
|
20
|
+
# @kumare3 is sadpanda, because we have to create a mirror of phase types here, because protobuf phases are ghastly
|
|
21
|
+
Phase = Literal[
|
|
22
|
+
"queued", "waiting_for_resources", "initializing", "running", "succeeded", "failed", "aborted", "timed_out"
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class Run(ToJSONMixin):
|
|
28
|
+
"""
|
|
29
|
+
A class representing a run of a task. It is used to manage the run of a task and its state on the remote
|
|
30
|
+
Union API.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
pb2: run_definition_pb2.Run
|
|
34
|
+
action: Action = field(init=False)
|
|
35
|
+
_details: RunDetails | None = None
|
|
36
|
+
|
|
37
|
+
def __post_init__(self):
|
|
38
|
+
"""
|
|
39
|
+
Initialize the Run object with the given run definition.
|
|
40
|
+
"""
|
|
41
|
+
if not self.pb2.HasField("action"):
|
|
42
|
+
raise RuntimeError("Run does not have an action")
|
|
43
|
+
self.action = Action(self.pb2.action)
|
|
44
|
+
|
|
45
|
+
@syncify
|
|
46
|
+
@classmethod
|
|
47
|
+
async def listall(
|
|
48
|
+
cls,
|
|
49
|
+
in_phase: Tuple[Phase] | None = None,
|
|
50
|
+
created_by_subject: str | None = None,
|
|
51
|
+
sort_by: Tuple[str, Literal["asc", "desc"]] | None = None,
|
|
52
|
+
limit: int = 100,
|
|
53
|
+
) -> AsyncIterator[Run]:
|
|
54
|
+
"""
|
|
55
|
+
Get all runs for the current project and domain.
|
|
56
|
+
|
|
57
|
+
:param in_phase: Filter runs by one or more phases.
|
|
58
|
+
:param created_by_subject: Filter runs by the subject that created them. (this is not username, but the subject)
|
|
59
|
+
:param sort_by: The sorting criteria for the project list, in the format (field, order).
|
|
60
|
+
:param limit: The maximum number of runs to return.
|
|
61
|
+
:return: An iterator of runs.
|
|
62
|
+
"""
|
|
63
|
+
ensure_client()
|
|
64
|
+
token = None
|
|
65
|
+
sort_by = sort_by or ("created_at", "asc")
|
|
66
|
+
sort_pb2 = list_pb2.Sort(
|
|
67
|
+
key=sort_by[0],
|
|
68
|
+
direction=(list_pb2.Sort.ASCENDING if sort_by[1] == "asc" else list_pb2.Sort.DESCENDING),
|
|
69
|
+
)
|
|
70
|
+
filters = []
|
|
71
|
+
if in_phase:
|
|
72
|
+
phases = [str(run_definition_pb2.Phase.Value(f"PHASE_{p.upper()}")) for p in in_phase]
|
|
73
|
+
logger.debug(f"Fetching run phases: {phases}")
|
|
74
|
+
if len(phases) > 1:
|
|
75
|
+
filters.append(
|
|
76
|
+
list_pb2.Filter(
|
|
77
|
+
function=list_pb2.Filter.Function.VALUE_IN,
|
|
78
|
+
field="phase",
|
|
79
|
+
values=phases,
|
|
80
|
+
),
|
|
81
|
+
)
|
|
82
|
+
else:
|
|
83
|
+
filters.append(
|
|
84
|
+
list_pb2.Filter(
|
|
85
|
+
function=list_pb2.Filter.Function.EQUAL,
|
|
86
|
+
field="phase",
|
|
87
|
+
values=phases[0],
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
if created_by_subject:
|
|
91
|
+
logger.debug(f"Fetching runs created by: {created_by_subject}")
|
|
92
|
+
filters.append(
|
|
93
|
+
list_pb2.Filter(
|
|
94
|
+
function=list_pb2.Filter.Function.EQUAL,
|
|
95
|
+
field="created_by",
|
|
96
|
+
values=[created_by_subject],
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
cfg = get_init_config()
|
|
101
|
+
i = 0
|
|
102
|
+
while True:
|
|
103
|
+
req = list_pb2.ListRequest(
|
|
104
|
+
limit=min(100, limit),
|
|
105
|
+
token=token,
|
|
106
|
+
sort_by=sort_pb2,
|
|
107
|
+
filters=filters,
|
|
108
|
+
)
|
|
109
|
+
resp = await get_client().run_service.ListRuns(
|
|
110
|
+
run_service_pb2.ListRunsRequest(
|
|
111
|
+
request=req,
|
|
112
|
+
org=cfg.org,
|
|
113
|
+
project_id=identifier_pb2.ProjectIdentifier(
|
|
114
|
+
organization=cfg.org,
|
|
115
|
+
domain=cfg.domain,
|
|
116
|
+
name=cfg.project,
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
token = resp.token
|
|
121
|
+
for r in resp.runs:
|
|
122
|
+
i += 1
|
|
123
|
+
if i > limit:
|
|
124
|
+
return
|
|
125
|
+
yield cls(r)
|
|
126
|
+
if not token:
|
|
127
|
+
break
|
|
128
|
+
|
|
129
|
+
@syncify
|
|
130
|
+
@classmethod
|
|
131
|
+
async def get(cls, name: str) -> Run:
|
|
132
|
+
"""
|
|
133
|
+
Get the current run.
|
|
134
|
+
|
|
135
|
+
:return: The current run.
|
|
136
|
+
"""
|
|
137
|
+
ensure_client()
|
|
138
|
+
run_details: RunDetails = await RunDetails.get.aio(name=name)
|
|
139
|
+
run = run_definition_pb2.Run(
|
|
140
|
+
action=run_definition_pb2.Action(
|
|
141
|
+
id=run_details.action_id,
|
|
142
|
+
metadata=run_details.action_details.pb2.metadata,
|
|
143
|
+
status=run_details.action_details.pb2.status,
|
|
144
|
+
),
|
|
145
|
+
)
|
|
146
|
+
return cls(pb2=run, _details=run_details)
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def name(self) -> str:
|
|
150
|
+
"""
|
|
151
|
+
Get the name of the run.
|
|
152
|
+
"""
|
|
153
|
+
return self.pb2.action.id.run.name
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def phase(self) -> str:
|
|
157
|
+
"""
|
|
158
|
+
Get the phase of the run.
|
|
159
|
+
"""
|
|
160
|
+
return self.action.phase
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def raw_phase(self) -> run_definition_pb2.Phase:
|
|
164
|
+
"""
|
|
165
|
+
Get the raw phase of the run.
|
|
166
|
+
"""
|
|
167
|
+
return self.action.raw_phase
|
|
168
|
+
|
|
169
|
+
@syncify
|
|
170
|
+
async def wait(self, quiet: bool = False, wait_for: Literal["terminal", "running"] = "terminal") -> None:
|
|
171
|
+
"""
|
|
172
|
+
Wait for the run to complete, displaying a rich progress panel with status transitions,
|
|
173
|
+
time elapsed, and error details in case of failure.
|
|
174
|
+
"""
|
|
175
|
+
return await self.action.wait(quiet=quiet, wait_for=wait_for)
|
|
176
|
+
|
|
177
|
+
async def watch(self, cache_data_on_done: bool = False) -> AsyncGenerator[ActionDetails, None]:
|
|
178
|
+
"""
|
|
179
|
+
Get the details of the run. This is a placeholder for getting the run details.
|
|
180
|
+
"""
|
|
181
|
+
return self.action.watch(cache_data_on_done=cache_data_on_done)
|
|
182
|
+
|
|
183
|
+
@syncify
|
|
184
|
+
async def show_logs(
|
|
185
|
+
self,
|
|
186
|
+
attempt: int | None = None,
|
|
187
|
+
max_lines: int = 100,
|
|
188
|
+
show_ts: bool = False,
|
|
189
|
+
raw: bool = False,
|
|
190
|
+
filter_system: bool = False,
|
|
191
|
+
):
|
|
192
|
+
await self.action.show_logs.aio(attempt, max_lines, show_ts, raw, filter_system=filter_system)
|
|
193
|
+
|
|
194
|
+
@syncify
|
|
195
|
+
async def details(self) -> RunDetails:
|
|
196
|
+
"""
|
|
197
|
+
Get the details of the run. This is a placeholder for getting the run details.
|
|
198
|
+
"""
|
|
199
|
+
if self._details is None or not self._details.done():
|
|
200
|
+
self._details = await RunDetails.get_details.aio(self.pb2.action.id.run)
|
|
201
|
+
return self._details
|
|
202
|
+
|
|
203
|
+
@syncify
|
|
204
|
+
async def inputs(self) -> ActionInputs:
|
|
205
|
+
"""
|
|
206
|
+
Get the inputs of the run. This is a placeholder for getting the run inputs.
|
|
207
|
+
"""
|
|
208
|
+
details = await self.details.aio()
|
|
209
|
+
return await details.inputs()
|
|
210
|
+
|
|
211
|
+
@syncify
|
|
212
|
+
async def outputs(self) -> ActionOutputs:
|
|
213
|
+
"""
|
|
214
|
+
Get the outputs of the run. This is a placeholder for getting the run outputs.
|
|
215
|
+
"""
|
|
216
|
+
details = await self.details.aio()
|
|
217
|
+
return await details.outputs()
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def url(self) -> str:
|
|
221
|
+
"""
|
|
222
|
+
Get the URL of the run.
|
|
223
|
+
"""
|
|
224
|
+
client = get_client()
|
|
225
|
+
return get_run_url(
|
|
226
|
+
client.endpoint,
|
|
227
|
+
insecure=client.insecure,
|
|
228
|
+
project=self.pb2.action.id.run.project,
|
|
229
|
+
domain=self.pb2.action.id.run.domain,
|
|
230
|
+
run_name=self.name,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
@syncify
|
|
234
|
+
async def abort(self):
|
|
235
|
+
"""
|
|
236
|
+
Aborts / Terminates the run.
|
|
237
|
+
"""
|
|
238
|
+
try:
|
|
239
|
+
await get_client().run_service.AbortRun(
|
|
240
|
+
run_service_pb2.AbortRunRequest(
|
|
241
|
+
run_id=self.pb2.action.id.run,
|
|
242
|
+
)
|
|
243
|
+
)
|
|
244
|
+
except grpc.aio.AioRpcError as e:
|
|
245
|
+
if e.code() == grpc.StatusCode.NOT_FOUND:
|
|
246
|
+
return
|
|
247
|
+
raise
|
|
248
|
+
|
|
249
|
+
def done(self) -> bool:
|
|
250
|
+
"""
|
|
251
|
+
Check if the run is done.
|
|
252
|
+
"""
|
|
253
|
+
return self.action.done()
|
|
254
|
+
|
|
255
|
+
def sync(self) -> Run:
|
|
256
|
+
"""
|
|
257
|
+
Sync the run with the remote server. This is a placeholder for syncing the run.
|
|
258
|
+
"""
|
|
259
|
+
return self
|
|
260
|
+
|
|
261
|
+
# TODO add add_done_callback, maybe implement sync apis etc
|
|
262
|
+
|
|
263
|
+
def __rich_repr__(self) -> rich.repr.Result:
|
|
264
|
+
"""
|
|
265
|
+
Rich representation of the Run object.
|
|
266
|
+
"""
|
|
267
|
+
yield "url", f"[blue bold][link={self.url}]link[/link][/blue bold]"
|
|
268
|
+
yield from _action_rich_repr(self.pb2.action)
|
|
269
|
+
|
|
270
|
+
def __repr__(self) -> str:
|
|
271
|
+
"""
|
|
272
|
+
String representation of the Action object.
|
|
273
|
+
"""
|
|
274
|
+
import rich.pretty
|
|
275
|
+
|
|
276
|
+
return rich.pretty.pretty_repr(self)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@dataclass
|
|
280
|
+
class RunDetails(ToJSONMixin):
|
|
281
|
+
"""
|
|
282
|
+
A class representing a run of a task. It is used to manage the run of a task and its state on the remote
|
|
283
|
+
Union API.
|
|
284
|
+
"""
|
|
285
|
+
|
|
286
|
+
pb2: run_definition_pb2.RunDetails
|
|
287
|
+
action_details: ActionDetails = field(init=False)
|
|
288
|
+
|
|
289
|
+
def __post_init__(self):
|
|
290
|
+
"""
|
|
291
|
+
Initialize the RunDetails object with the given run definition.
|
|
292
|
+
"""
|
|
293
|
+
self.action_details = ActionDetails(self.pb2.action)
|
|
294
|
+
|
|
295
|
+
@syncify
|
|
296
|
+
@classmethod
|
|
297
|
+
async def get_details(cls, run_id: identifier_pb2.RunIdentifier) -> RunDetails:
|
|
298
|
+
"""
|
|
299
|
+
Get the details of the run. This is a placeholder for getting the run details.
|
|
300
|
+
"""
|
|
301
|
+
ensure_client()
|
|
302
|
+
resp = await get_client().run_service.GetRunDetails(
|
|
303
|
+
run_service_pb2.GetRunDetailsRequest(
|
|
304
|
+
run_id=run_id,
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
return cls(resp.details)
|
|
308
|
+
|
|
309
|
+
@syncify
|
|
310
|
+
@classmethod
|
|
311
|
+
async def get(cls, name: str | None = None) -> RunDetails:
|
|
312
|
+
"""
|
|
313
|
+
Get a run by its ID or name. If both are provided, the ID will take precedence.
|
|
314
|
+
|
|
315
|
+
:param uri: The URI of the run.
|
|
316
|
+
:param name: The name of the run.
|
|
317
|
+
"""
|
|
318
|
+
ensure_client()
|
|
319
|
+
cfg = get_init_config()
|
|
320
|
+
return await RunDetails.get_details.aio(
|
|
321
|
+
run_id=identifier_pb2.RunIdentifier(
|
|
322
|
+
org=cfg.org,
|
|
323
|
+
project=cfg.project,
|
|
324
|
+
domain=cfg.domain,
|
|
325
|
+
name=name,
|
|
326
|
+
),
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
@property
|
|
330
|
+
def name(self) -> str:
|
|
331
|
+
"""
|
|
332
|
+
Get the name of the action.
|
|
333
|
+
"""
|
|
334
|
+
return self.action_details.run_name
|
|
335
|
+
|
|
336
|
+
@property
|
|
337
|
+
def task_name(self) -> str | None:
|
|
338
|
+
"""
|
|
339
|
+
Get the name of the task.
|
|
340
|
+
"""
|
|
341
|
+
return self.action_details.task_name
|
|
342
|
+
|
|
343
|
+
@property
|
|
344
|
+
def action_id(self) -> identifier_pb2.ActionIdentifier:
|
|
345
|
+
"""
|
|
346
|
+
Get the action ID.
|
|
347
|
+
"""
|
|
348
|
+
return self.action_details.action_id
|
|
349
|
+
|
|
350
|
+
def done(self) -> bool:
|
|
351
|
+
"""
|
|
352
|
+
Check if the run is in a terminal state (completed or failed). This is a placeholder for checking the
|
|
353
|
+
run state.
|
|
354
|
+
"""
|
|
355
|
+
return self.action_details.done()
|
|
356
|
+
|
|
357
|
+
async def inputs(self) -> ActionInputs:
|
|
358
|
+
"""
|
|
359
|
+
Placeholder for inputs. This can be extended to handle inputs from the run context.
|
|
360
|
+
"""
|
|
361
|
+
return await self.action_details.inputs()
|
|
362
|
+
|
|
363
|
+
async def outputs(self) -> ActionOutputs:
|
|
364
|
+
"""
|
|
365
|
+
Placeholder for outputs. This can be extended to handle outputs from the run context.
|
|
366
|
+
"""
|
|
367
|
+
return await self.action_details.outputs()
|
|
368
|
+
|
|
369
|
+
def __rich_repr__(self) -> rich.repr.Result:
|
|
370
|
+
"""
|
|
371
|
+
Rich representation of the Run object.
|
|
372
|
+
"""
|
|
373
|
+
yield "labels", str(self.pb2.run_spec.labels)
|
|
374
|
+
yield "annotations", str(self.pb2.run_spec.annotations)
|
|
375
|
+
yield "env-vars", str(self.pb2.run_spec.envs)
|
|
376
|
+
yield "is-interruptible", str(self.pb2.run_spec.interruptible)
|
|
377
|
+
yield "cache-overwrite", self.pb2.run_spec.overwrite_cache
|
|
378
|
+
yield from _action_details_rich_repr(self.pb2.action)
|
|
379
|
+
|
|
380
|
+
def __repr__(self) -> str:
|
|
381
|
+
"""
|
|
382
|
+
String representation of the Action object.
|
|
383
|
+
"""
|
|
384
|
+
import rich.pretty
|
|
385
|
+
|
|
386
|
+
return rich.pretty.pretty_repr(self)
|
flyte/remote/_secret.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import AsyncIterator, Literal, Union
|
|
5
|
+
|
|
6
|
+
import rich.repr
|
|
7
|
+
from flyteidl2.secret import definition_pb2, payload_pb2
|
|
8
|
+
|
|
9
|
+
from flyte._initialize import ensure_client, get_client, get_init_config
|
|
10
|
+
from flyte.remote._common import ToJSONMixin
|
|
11
|
+
from flyte.syncify import syncify
|
|
12
|
+
|
|
13
|
+
SecretTypes = Literal["regular", "image_pull"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class Secret(ToJSONMixin):
|
|
18
|
+
pb2: definition_pb2.Secret
|
|
19
|
+
|
|
20
|
+
@syncify
|
|
21
|
+
@classmethod
|
|
22
|
+
async def create(cls, name: str, value: Union[str, bytes], type: SecretTypes = "regular"):
|
|
23
|
+
ensure_client()
|
|
24
|
+
cfg = get_init_config()
|
|
25
|
+
project = cfg.project
|
|
26
|
+
domain = cfg.domain
|
|
27
|
+
|
|
28
|
+
if type == "regular":
|
|
29
|
+
secret_type = definition_pb2.SecretType.SECRET_TYPE_GENERIC
|
|
30
|
+
|
|
31
|
+
else:
|
|
32
|
+
secret_type = definition_pb2.SecretType.SECRET_TYPE_IMAGE_PULL_SECRET
|
|
33
|
+
if project or domain:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
f"Project `{project}` or domain `{domain}` should not be set when creating the image pull secret."
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if isinstance(value, str):
|
|
39
|
+
secret = definition_pb2.SecretSpec(
|
|
40
|
+
type=secret_type,
|
|
41
|
+
string_value=value,
|
|
42
|
+
)
|
|
43
|
+
else:
|
|
44
|
+
secret = definition_pb2.SecretSpec(
|
|
45
|
+
type=secret_type,
|
|
46
|
+
binary_value=value,
|
|
47
|
+
)
|
|
48
|
+
await get_client().secrets_service.CreateSecret( # type: ignore
|
|
49
|
+
request=payload_pb2.CreateSecretRequest(
|
|
50
|
+
id=definition_pb2.SecretIdentifier(
|
|
51
|
+
organization=cfg.org,
|
|
52
|
+
project=project,
|
|
53
|
+
domain=domain,
|
|
54
|
+
name=name,
|
|
55
|
+
),
|
|
56
|
+
secret_spec=secret,
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
@syncify
|
|
61
|
+
@classmethod
|
|
62
|
+
async def get(cls, name: str) -> Secret:
|
|
63
|
+
ensure_client()
|
|
64
|
+
cfg = get_init_config()
|
|
65
|
+
resp = await get_client().secrets_service.GetSecret(
|
|
66
|
+
request=payload_pb2.GetSecretRequest(
|
|
67
|
+
id=definition_pb2.SecretIdentifier(
|
|
68
|
+
organization=cfg.org,
|
|
69
|
+
project=cfg.project,
|
|
70
|
+
domain=cfg.domain,
|
|
71
|
+
name=name,
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
return Secret(pb2=resp.secret)
|
|
76
|
+
|
|
77
|
+
@syncify
|
|
78
|
+
@classmethod
|
|
79
|
+
async def listall(cls, limit: int = 10) -> AsyncIterator[Secret]:
|
|
80
|
+
ensure_client()
|
|
81
|
+
cfg = get_init_config()
|
|
82
|
+
per_cluster_tokens = None
|
|
83
|
+
while True:
|
|
84
|
+
resp = await get_client().secrets_service.ListSecrets( # type: ignore
|
|
85
|
+
request=payload_pb2.ListSecretsRequest(
|
|
86
|
+
organization=cfg.org,
|
|
87
|
+
project=cfg.project,
|
|
88
|
+
domain=cfg.domain,
|
|
89
|
+
per_cluster_tokens=per_cluster_tokens,
|
|
90
|
+
limit=limit,
|
|
91
|
+
),
|
|
92
|
+
)
|
|
93
|
+
per_cluster_tokens = resp.per_cluster_tokens
|
|
94
|
+
round_items = [v for _, v in per_cluster_tokens.items() if v]
|
|
95
|
+
has_next = any(round_items)
|
|
96
|
+
for r in resp.secrets:
|
|
97
|
+
yield cls(r)
|
|
98
|
+
if not has_next:
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
@syncify
|
|
102
|
+
@classmethod
|
|
103
|
+
async def delete(cls, name):
|
|
104
|
+
ensure_client()
|
|
105
|
+
cfg = get_init_config()
|
|
106
|
+
await get_client().secrets_service.DeleteSecret( # type: ignore
|
|
107
|
+
request=payload_pb2.DeleteSecretRequest(
|
|
108
|
+
id=definition_pb2.SecretIdentifier(
|
|
109
|
+
organization=cfg.org,
|
|
110
|
+
project=cfg.project,
|
|
111
|
+
domain=cfg.domain,
|
|
112
|
+
name=name,
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def name(self) -> str:
|
|
119
|
+
return self.pb2.id.name
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def type(self) -> str:
|
|
123
|
+
if self.pb2.secret_metadata.type == definition_pb2.SecretType.SECRET_TYPE_GENERIC:
|
|
124
|
+
return "regular"
|
|
125
|
+
elif self.pb2.secret_metadata.type == definition_pb2.SecretType.SECRET_TYPE_IMAGE_PULL_SECRET:
|
|
126
|
+
return "image_pull"
|
|
127
|
+
raise ValueError("unknown type")
|
|
128
|
+
|
|
129
|
+
def __rich_repr__(self) -> rich.repr.Result:
|
|
130
|
+
yield "project", self.pb2.id.project or "-"
|
|
131
|
+
yield "domain", self.pb2.id.domain or "-"
|
|
132
|
+
yield "name", self.name
|
|
133
|
+
yield "type", self.type
|
|
134
|
+
yield "created_time", self.pb2.secret_metadata.created_time.ToDatetime().isoformat()
|
|
135
|
+
yield "status", definition_pb2.OverallStatus.Name(self.pb2.secret_metadata.secret_status.overall_status)
|
|
136
|
+
yield (
|
|
137
|
+
"cluster_status",
|
|
138
|
+
{
|
|
139
|
+
s.cluster.name: definition_pb2.SecretPresenceStatus.Name(s.presence_status)
|
|
140
|
+
for s in self.pb2.secret_metadata.secret_status.cluster_status
|
|
141
|
+
},
|
|
142
|
+
)
|