zenml-nightly 0.80.1.dev20250407__py3-none-any.whl → 0.80.1.dev20250409__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.
- zenml/VERSION +1 -1
- zenml/cli/base.py +1 -1
- zenml/cli/integration.py +36 -0
- zenml/client.py +6 -0
- zenml/config/step_configurations.py +3 -2
- zenml/constants.py +1 -1
- zenml/entrypoints/step_entrypoint_configuration.py +2 -0
- zenml/integrations/airflow/orchestrators/airflow_orchestrator.py +7 -2
- zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +2 -0
- zenml/integrations/azure/orchestrators/azureml_orchestrator.py +2 -0
- zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +3 -1
- zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +2 -0
- zenml/integrations/hyperai/orchestrators/hyperai_orchestrator.py +3 -1
- zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +3 -1
- zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +12 -0
- zenml/integrations/kubernetes/orchestrators/kube_utils.py +3 -0
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +4 -1
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +164 -19
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint_configuration.py +8 -1
- zenml/integrations/lightning/orchestrators/lightning_orchestrator.py +3 -1
- zenml/integrations/mlflow/__init__.py +0 -27
- zenml/integrations/mlflow/services/mlflow_deployment.py +25 -7
- zenml/integrations/pandas/materializers/pandas_materializer.py +41 -2
- zenml/integrations/seldon/services/seldon_deployment.py +1 -1
- zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +3 -1
- zenml/integrations/tekton/orchestrators/tekton_orchestrator.py +3 -1
- zenml/integrations/vllm/services/vllm_deployment.py +1 -1
- zenml/model/model.py +3 -1
- zenml/models/__init__.py +5 -0
- zenml/models/v2/core/run_template.py +32 -1
- zenml/orchestrators/base_orchestrator.py +3 -0
- zenml/orchestrators/dag_runner.py +48 -15
- zenml/orchestrators/local/local_orchestrator.py +3 -1
- zenml/orchestrators/local_docker/local_docker_orchestrator.py +3 -1
- zenml/steps/base_step.py +11 -8
- zenml/utils/secret_utils.py +2 -2
- zenml/zen_server/dashboard/assets/{404-2I8egBQu.js → 404-CYPi9d8E.js} +1 -1
- zenml/zen_server/dashboard/assets/@radix-C7hRs6Kx.js +95 -0
- zenml/zen_server/dashboard/assets/{@react-router-BUo5vhN4.js → @react-router-BGgzhn5D.js} +5 -5
- zenml/zen_server/dashboard/assets/@reactflow-CQi1Z1Wq.js +17 -0
- zenml/zen_server/dashboard/assets/@tanstack-CSxjHCME.js +22 -0
- zenml/zen_server/dashboard/assets/{AlertDialogDropdownItem-D7KZcPFw.js → AlertDialogDropdownItem-Dn8bgaXG.js} +1 -1
- zenml/zen_server/dashboard/assets/{CodeSnippet-DUkCnBpQ.js → CodeSnippet-CSINAl3I.js} +1 -1
- zenml/zen_server/dashboard/assets/{CollapsibleCard-B5-5Plnd.js → CollapsibleCard-CQOb53t9.js} +1 -1
- zenml/zen_server/dashboard/assets/{Commands-CbOMmarC.js → Commands-CPleXvse.js} +1 -1
- zenml/zen_server/dashboard/assets/{ComponentBadge-FrujKBC6.js → ComponentBadge-CIFj0W7T.js} +1 -1
- zenml/zen_server/dashboard/assets/{ComponentIcon-Dx5fBrDX.js → ComponentIcon-D3JHFhJU.js} +1 -1
- zenml/zen_server/dashboard/assets/{CsvVizualization-B8E3p9we.js → CsvVizualization-Cklc1Vb5.js} +6 -6
- zenml/zen_server/dashboard/assets/{DeleteAlertDialog-BgTZbbAt.js → DeleteAlertDialog-Bzq-uSd7.js} +1 -1
- zenml/zen_server/dashboard/assets/{DialogItem-CNWLiJcc.js → DialogItem-zjMgCmCl.js} +1 -1
- zenml/zen_server/dashboard/assets/{DisplayDate-C5Aw-Yca.js → DisplayDate-CYVBBSgr.js} +1 -1
- zenml/zen_server/dashboard/assets/{EmptyState-DpbfQBDE.js → EmptyState-M1jafpg6.js} +1 -1
- zenml/zen_server/dashboard/assets/{Error-BkUP4Luv.js → Error-kdeNHm_o.js} +1 -1
- zenml/zen_server/dashboard/assets/{ExecutionStatus-CD8Vj7sp.js → ExecutionStatus-UE6Rbmtk.js} +1 -1
- zenml/zen_server/dashboard/assets/{Helpbox-DIx6mDOH.js → Helpbox-CeM-FPQl.js} +1 -1
- zenml/zen_server/dashboard/assets/{Infobox-BHEdNmME.js → Infobox-CD0fDbYF.js} +1 -1
- zenml/zen_server/dashboard/assets/{InlineAvatar-Bin9UPKJ.js → InlineAvatar-CrHWwlf4.js} +1 -1
- zenml/zen_server/dashboard/assets/{Lock-tO9Z41I9.js → Lock-DW-0_M0o.js} +1 -1
- zenml/zen_server/dashboard/assets/{MarkdownVisualization-C3JLiPCY.js → MarkdownVisualization-URCyUPcZ.js} +2 -2
- zenml/zen_server/dashboard/assets/{NestedCollapsible-Da-k0Mff.js → NestedCollapsible-DfTTGG8u.js} +1 -1
- zenml/zen_server/dashboard/assets/{NumberBox-BvBJYxCu.js → NumberBox-D2A7ENHb.js} +1 -1
- zenml/zen_server/dashboard/assets/Partials-DggkUpWp.js +1 -0
- zenml/zen_server/dashboard/assets/{PasswordChecker-B4Uw6BJZ.js → PasswordChecker-lYTOtNom.js} +1 -1
- zenml/zen_server/dashboard/assets/ProBadge-BCdprj69.js +1 -0
- zenml/zen_server/dashboard/assets/{ProCta-7_FtpX3I.js → ProCta-szzPO0Y7.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProviderIcon-CxeziA5a.js → ProviderIcon-MdqWDO6-.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProviderRadio-DPmZHff_.js → ProviderRadio-B4CB4vzP.js} +1 -1
- zenml/zen_server/dashboard/assets/{RunSelector-BVKB4Z8F.js → RunSelector-Bhb83FyB.js} +1 -1
- zenml/zen_server/dashboard/assets/{RunsBody-Cj4sIqQB.js → RunsBody-Csn2VEOE.js} +1 -1
- zenml/zen_server/dashboard/assets/{SearchField-DjAOZic5.js → SearchField-Cce00eQL.js} +1 -1
- zenml/zen_server/dashboard/assets/{SecretTooltip-mMAAP4dM.js → SecretTooltip-DaDLBVj-.js} +1 -1
- zenml/zen_server/dashboard/assets/{SetPassword-B0o5kSJU.js → SetPassword-tX6fom1Y.js} +1 -1
- zenml/zen_server/dashboard/assets/{StackList-5UB8LoEq.js → StackList-CQt1xGRh.js} +1 -1
- zenml/zen_server/dashboard/assets/{Tabs-AuhCyzle.js → Tabs-CCQyIqRb.js} +1 -1
- zenml/zen_server/dashboard/assets/{Tick-CHW0jc8Y.js → Tick-D63_jhf1.js} +1 -1
- zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-Bauivjf-.js → UpdatePasswordSchemas-CbbvoGYV.js} +1 -1
- zenml/zen_server/dashboard/assets/{UsageReason-Dr5ca5M4.js → UsageReason-C2cNrUeS.js} +1 -1
- zenml/zen_server/dashboard/assets/{Wizard-XEp9rGmf.js → Wizard-BVkN2a2x.js} +1 -1
- zenml/zen_server/dashboard/assets/WizardFooter-Bk7gIKiS.js +1 -0
- zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-COvsm3bC.js → all-pipeline-runs-query-BLclwQSi.js} +1 -1
- zenml/zen_server/dashboard/assets/{arrow-left-B2hyhFky.js → arrow-left-CwgF2MEM.js} +1 -1
- zenml/zen_server/dashboard/assets/{check-DZ0KAh3W.js → check-DK77doTf.js} +1 -1
- zenml/zen_server/dashboard/assets/{check-circle-DyCCYTA0.js → check-circle-mvyzYvIW.js} +1 -1
- zenml/zen_server/dashboard/assets/{chevron-down-A3PXOshS.js → chevron-down-A-rmltmI.js} +1 -1
- zenml/zen_server/dashboard/assets/{chevron-right-double-zKz7rAaU.js → chevron-right-double-uNWbJT-C.js} +1 -1
- zenml/zen_server/dashboard/assets/{clock-k5T5tYrt.js → clock-CPA5cYxq.js} +1 -1
- zenml/zen_server/dashboard/assets/{code-browser-DvB0W2Ix.js → code-browser-j2EpcxIA.js} +1 -1
- zenml/zen_server/dashboard/assets/{configuration-form-BJUCr0wl.js → configuration-form-CjrAp0GS.js} +1 -1
- zenml/zen_server/dashboard/assets/{create-stack-B2c98UlP.js → create-stack-Bd2JdQer.js} +1 -1
- zenml/zen_server/dashboard/assets/delete-run-Cwpxu1-d.js +1 -0
- zenml/zen_server/dashboard/assets/{docker-B3Sqzd8J.js → docker-BuDBFEDL.js} +1 -1
- zenml/zen_server/dashboard/assets/{file-text-CgxVzNph.js → file-text-BdxZdjP_.js} +1 -1
- zenml/zen_server/dashboard/assets/{flavor-select-D8CranSY.js → flavor-select-c0w-6o9w.js} +1 -1
- zenml/zen_server/dashboard/assets/{form-schemas-Bm-dTV3L.js → form-schemas-B5Ax1SZf.js} +1 -1
- zenml/zen_server/dashboard/assets/{gcp-0u4le6mC.js → gcp-CHNvgEss.js} +1 -1
- zenml/zen_server/dashboard/assets/{help-CfT0tY2I.js → help-DyMolRxD.js} +1 -1
- zenml/zen_server/dashboard/assets/index-BW-KaQ2p.js +1 -0
- zenml/zen_server/dashboard/assets/{index-DPjvk73v.js → index-Be2jLIYM.js} +8 -8
- zenml/zen_server/dashboard/assets/{index-D-n6tspq.js → index-CjdtNrfJ.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-BVVKxTWC.js → index-DR30v9MZ.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-CzhJC6pc.js → index-d_40qKeY.js} +1 -1
- zenml/zen_server/dashboard/assets/index.esm-D7jFlf5N.js +1 -0
- zenml/zen_server/dashboard/assets/{key-icon-CjwWwoOU.js → key-icon-DO4DPJHZ.js} +1 -1
- zenml/zen_server/dashboard/assets/{kubernetes-eA-Y6gE7.js → kubernetes-D6OUjwSK.js} +1 -1
- zenml/zen_server/dashboard/assets/{layout-3_rgDUxf.js → layout-h3cbx8WZ.js} +1 -1
- zenml/zen_server/dashboard/assets/{link-external-BYm_zH_8.js → link-external-DUhCSKNm.js} +1 -1
- zenml/zen_server/dashboard/assets/{login-mutation-D6uiKsKk.js → login-mutation-DOajKct8.js} +1 -1
- zenml/zen_server/dashboard/assets/{logs-D6_diV2k.js → logs-B5n0U7tB.js} +1 -1
- zenml/zen_server/dashboard/assets/{not-found-DFrksY0r.js → not-found-DolTp0dr.js} +1 -1
- zenml/zen_server/dashboard/assets/{package-BOms6B-A.js → package-D1Mhqeh8.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DBNBYSwq.js → page-48DMcIQw.js} +2 -2
- zenml/zen_server/dashboard/assets/{page-DOzFoJuo.js → page-B32kCGPe.js} +1 -1
- zenml/zen_server/dashboard/assets/page-BAjhc2bs.js +1 -0
- zenml/zen_server/dashboard/assets/{page-D5GZlpKq.js → page-BBNrvxC1.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DF9q7ySu.js → page-BEAx6ZvH.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DDvwWgKP.js → page-BRfeowe0.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BJ15SGwt.js → page-BbRtQC2E.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-D2F0Rvak.js → page-BgUR_5z3.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-D0Zt2-7X.js → page-BiAjLLww.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-B80TE04v.js → page-BkPPfNfG.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DkJfgcDi.js → page-BmTf1Lf1.js} +2 -2
- zenml/zen_server/dashboard/assets/{page-CAKBSE9f.js → page-BuZC8z6N.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BwAFqFCf.js → page-C4zMMcaH.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BnUwQBeg.js → page-CKVbEdX2.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BXh1mF-D.js → page-CPRymOIS.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BMZaECzB.js → page-CaTJVICi.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-NIWnUdVg.js → page-CmzmFF4S.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BIseZTJt.js → page-CwAbTnvK.js} +2 -2
- zenml/zen_server/dashboard/assets/{page-BeFiRx31.js → page-D-MjLTXS.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-B1Un9vAU.js → page-D3m9-YWJ.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DhNnHHmX.js → page-DCpZju6a.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DEUeF3mO.js +1 -0
- zenml/zen_server/dashboard/assets/{page-B150LbzG.js → page-DWOAh8Pp.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-EhqRFAZc.js → page-DezabeEO.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BTvnIFGR.js → page-DivlNKt9.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BqQ6y8Hb.js → page-DmOcZO8U.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DnY59jOg.js +1 -0
- zenml/zen_server/dashboard/assets/{page-DaHH2ZEF.js → page-Dv3qtvm8.js} +1 -1
- zenml/zen_server/dashboard/assets/page-P81CcE2L.js +1 -0
- zenml/zen_server/dashboard/assets/{page-Dd-0y3SU.js → page-a1c6o4vv.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BJrZsPSh.js → page-bS5tHLDW.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-C11vPVkH.js → page-gRfUvR0E.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BZUxCBoD.js → page-hNHJPQtK.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-kYlFrH53.js → page-ir7Scz2Y.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-ygCPGHAV.js → page-mtwS5oci.js} +1 -1
- zenml/zen_server/dashboard/assets/{persist-DHGuHP2H.js → persist-BUqILw7G.js} +1 -1
- zenml/zen_server/dashboard/assets/{persist-C5RlwSq6.js → persist-BbdfLc0W.js} +1 -1
- zenml/zen_server/dashboard/assets/{plus-CoKtHiA9.js → plus-COjQg3AG.js} +1 -1
- zenml/zen_server/dashboard/assets/{react-error-boundary.esm-BkGIR1Du.js → react-error-boundary.esm-fyoUBS25.js} +1 -1
- zenml/zen_server/dashboard/assets/{refresh-CupyU1Vs.js → refresh-CM5T3QeU.js} +1 -1
- zenml/zen_server/dashboard/assets/{rocket-k68ONPDS.js → rocket-Cf-B-XOR.js} +1 -1
- zenml/zen_server/dashboard/assets/{service-Do7yitqe.js → service-CV2zjc-p.js} +1 -1
- zenml/zen_server/dashboard/assets/{sharedSchema-i_9Y4WcA.js → sharedSchema-DpGc9kQg.js} +1 -1
- zenml/zen_server/dashboard/assets/stack-detail-query-BpzLZjvw.js +1 -0
- zenml/zen_server/dashboard/assets/{terminal-square-URAPn9DB.js → terminal-square-DMtel8mb.js} +1 -1
- zenml/zen_server/dashboard/assets/{tick-circle-AaVBszPn.js → tick-circle-m94Aa6Zt.js} +1 -1
- zenml/zen_server/dashboard/assets/{trash-B_JgTgqd.js → trash-BWSZ7NRK.js} +1 -1
- zenml/zen_server/dashboard/assets/update-server-settings-mutation-Dv6qHtK9.js +1 -0
- zenml/zen_server/dashboard/assets/{zod-CRNUMWWg.js → zod-C0xYeTvL.js} +1 -1
- zenml/zen_server/dashboard/index.html +6 -6
- zenml/zen_server/template_execution/utils.py +53 -33
- zenml/zen_stores/migrations/versions/6611d4bcc95b_add_hidden_option_for_templates.py +47 -0
- zenml/zen_stores/schemas/run_template_schemas.py +7 -0
- {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/METADATA +2 -2
- {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/RECORD +168 -167
- zenml/zen_server/dashboard/assets/@radix-AvWw-1nd.js +0 -95
- zenml/zen_server/dashboard/assets/@reactflow-BHoFKFSZ.js +0 -17
- zenml/zen_server/dashboard/assets/@tanstack-CcI3lvwB.js +0 -22
- zenml/zen_server/dashboard/assets/Partials-TNaYjHsV.js +0 -1
- zenml/zen_server/dashboard/assets/ProBadge-BfPp-B97.js +0 -1
- zenml/zen_server/dashboard/assets/WizardFooter-BtL1Gi1k.js +0 -1
- zenml/zen_server/dashboard/assets/delete-run-Do3XyF4W.js +0 -1
- zenml/zen_server/dashboard/assets/index-eIIP-0dQ.js +0 -1
- zenml/zen_server/dashboard/assets/index.esm-cf-8NBxV.js +0 -1
- zenml/zen_server/dashboard/assets/page-B-uHUFcm.js +0 -1
- zenml/zen_server/dashboard/assets/page-B0Llmzo_.js +0 -1
- zenml/zen_server/dashboard/assets/page-BzlVs5tC.js +0 -1
- zenml/zen_server/dashboard/assets/page-CPe9nQSo.js +0 -1
- zenml/zen_server/dashboard/assets/stack-detail-query-omCumL7U.js +0 -1
- zenml/zen_server/dashboard/assets/update-server-settings-mutation-B4eE33z-.js +0 -1
- {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/entry_points.txt +0 -0
zenml/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.80.1.
|
1
|
+
0.80.1.dev20250409
|
zenml/cli/base.py
CHANGED
@@ -87,7 +87,7 @@ ZENML_PROJECT_TEMPLATES = dict(
|
|
87
87
|
),
|
88
88
|
nlp=ZenMLProjectTemplateLocation(
|
89
89
|
github_url="zenml-io/template-nlp",
|
90
|
-
github_tag="2025.
|
90
|
+
github_tag="2025.04.07", # Make sure it is aligned with .github/workflows/update-templates-to-examples.yml
|
91
91
|
),
|
92
92
|
llm_finetuning=ZenMLProjectTemplateLocation(
|
93
93
|
github_url="zenml-io/template-llm-finetuning",
|
zenml/cli/integration.py
CHANGED
@@ -13,6 +13,8 @@
|
|
13
13
|
# permissions and limitations under the License.
|
14
14
|
"""Functionality to install or uninstall ZenML integrations via the CLI."""
|
15
15
|
|
16
|
+
import os
|
17
|
+
import subprocess
|
16
18
|
import sys
|
17
19
|
from typing import Optional, Tuple
|
18
20
|
|
@@ -131,12 +133,20 @@ def get_requirements(integration_name: Optional[str] = None) -> None:
|
|
131
133
|
"environment. This can not be specified when also providing explicit "
|
132
134
|
"integrations.",
|
133
135
|
)
|
136
|
+
@click.option(
|
137
|
+
"--poetry",
|
138
|
+
"poetry",
|
139
|
+
is_flag=True,
|
140
|
+
default=False,
|
141
|
+
help="Add the exported requirements to your current Poetry project.",
|
142
|
+
)
|
134
143
|
def export_requirements(
|
135
144
|
integrations: Tuple[str],
|
136
145
|
ignore_integration: Tuple[str],
|
137
146
|
output_file: Optional[str] = None,
|
138
147
|
overwrite: bool = False,
|
139
148
|
installed_only: bool = False,
|
149
|
+
poetry: bool = False,
|
140
150
|
) -> None:
|
141
151
|
"""Exports integration requirements so they can be installed using pip.
|
142
152
|
|
@@ -150,6 +160,7 @@ def export_requirements(
|
|
150
160
|
installed_only: Only export requirements for integrations installed in
|
151
161
|
your current environment. This can not be specified when also
|
152
162
|
providing explicit integrations.
|
163
|
+
poetry: Add the exported requirements to your current Poetry project.
|
153
164
|
"""
|
154
165
|
from zenml.integrations.registry import integration_registry
|
155
166
|
|
@@ -160,6 +171,12 @@ def export_requirements(
|
|
160
171
|
"environment, not both."
|
161
172
|
)
|
162
173
|
|
174
|
+
if poetry and output_file:
|
175
|
+
error(
|
176
|
+
"You can either specify an output file or add the requirements to "
|
177
|
+
"the Poetry project, not both."
|
178
|
+
)
|
179
|
+
|
163
180
|
all_integrations = set(integration_registry.integrations.keys())
|
164
181
|
|
165
182
|
if integrations:
|
@@ -204,6 +221,25 @@ def export_requirements(
|
|
204
221
|
with open(output_file, "w") as f:
|
205
222
|
f.write("\n".join(requirements))
|
206
223
|
declare(f"Requirements exported to {output_file}.")
|
224
|
+
if poetry:
|
225
|
+
res = os.popen("poetry env list").read()
|
226
|
+
envs = [
|
227
|
+
env
|
228
|
+
for env in res.split("\n")
|
229
|
+
if env.lower().find("(activated)") > 0
|
230
|
+
]
|
231
|
+
if len(envs) == 0:
|
232
|
+
error(
|
233
|
+
"No activated Poetry environment found. Please activate one "
|
234
|
+
"and try again."
|
235
|
+
)
|
236
|
+
else:
|
237
|
+
# Use subprocess.run with shell=False to avoid command injection
|
238
|
+
args = ["poetry", "add"] + requirements
|
239
|
+
subprocess.run(args, check=True)
|
240
|
+
declare(
|
241
|
+
f"Requirements added to `{envs[0]}` environment in Poetry."
|
242
|
+
)
|
207
243
|
else:
|
208
244
|
click.echo(" ".join(requirements), nl=False)
|
209
245
|
|
zenml/client.py
CHANGED
@@ -3574,6 +3574,7 @@ class Client(metaclass=ClientMetaClass):
|
|
3574
3574
|
updated: Optional[Union[datetime, str]] = None,
|
3575
3575
|
id: Optional[Union[UUID, str]] = None,
|
3576
3576
|
name: Optional[str] = None,
|
3577
|
+
hidden: Optional[bool] = False,
|
3577
3578
|
tag: Optional[str] = None,
|
3578
3579
|
project: Optional[Union[str, UUID]] = None,
|
3579
3580
|
pipeline_id: Optional[Union[str, UUID]] = None,
|
@@ -3596,6 +3597,7 @@ class Client(metaclass=ClientMetaClass):
|
|
3596
3597
|
updated: Filter by the last updated date.
|
3597
3598
|
id: Filter by run template ID.
|
3598
3599
|
name: Filter by run template name.
|
3600
|
+
hidden: Filter by run template hidden status.
|
3599
3601
|
tag: Filter by run template tags.
|
3600
3602
|
project: Filter by project name/ID.
|
3601
3603
|
pipeline_id: Filter by pipeline ID.
|
@@ -3620,6 +3622,7 @@ class Client(metaclass=ClientMetaClass):
|
|
3620
3622
|
updated=updated,
|
3621
3623
|
id=id,
|
3622
3624
|
name=name,
|
3625
|
+
hidden=hidden,
|
3623
3626
|
tag=tag,
|
3624
3627
|
project=project,
|
3625
3628
|
pipeline_id=pipeline_id,
|
@@ -3640,6 +3643,7 @@ class Client(metaclass=ClientMetaClass):
|
|
3640
3643
|
name_id_or_prefix: Union[str, UUID],
|
3641
3644
|
name: Optional[str] = None,
|
3642
3645
|
description: Optional[str] = None,
|
3646
|
+
hidden: Optional[bool] = None,
|
3643
3647
|
add_tags: Optional[List[str]] = None,
|
3644
3648
|
remove_tags: Optional[List[str]] = None,
|
3645
3649
|
project: Optional[Union[str, UUID]] = None,
|
@@ -3650,6 +3654,7 @@ class Client(metaclass=ClientMetaClass):
|
|
3650
3654
|
name_id_or_prefix: Name/ID/ID prefix of the template to update.
|
3651
3655
|
name: The new name of the run template.
|
3652
3656
|
description: The new description of the run template.
|
3657
|
+
hidden: The new hidden status of the run template.
|
3653
3658
|
add_tags: Tags to add to the run template.
|
3654
3659
|
remove_tags: Tags to remove from the run template.
|
3655
3660
|
project: The project name/ID to filter by.
|
@@ -3675,6 +3680,7 @@ class Client(metaclass=ClientMetaClass):
|
|
3675
3680
|
template_update=RunTemplateUpdate(
|
3676
3681
|
name=name,
|
3677
3682
|
description=description,
|
3683
|
+
hidden=hidden,
|
3678
3684
|
add_tags=add_tags,
|
3679
3685
|
remove_tags=remove_tags,
|
3680
3686
|
),
|
@@ -118,8 +118,9 @@ class ArtifactConfiguration(PartialArtifactConfiguration):
|
|
118
118
|
@field_validator("materializer_source", mode="before")
|
119
119
|
@classmethod
|
120
120
|
def _convert_source(
|
121
|
-
cls,
|
122
|
-
|
121
|
+
cls,
|
122
|
+
value: Union[None, Source, Dict[str, Any], str, Tuple[Source, ...]],
|
123
|
+
) -> Optional[Tuple[Source, ...]]:
|
123
124
|
"""Converts old source strings to tuples of source objects.
|
124
125
|
|
125
126
|
Args:
|
zenml/constants.py
CHANGED
@@ -196,7 +196,7 @@ ENV_ZENML_RUN_SINGLE_STEPS_WITHOUT_STACK = (
|
|
196
196
|
)
|
197
197
|
ENV_ZENML_PREVENT_CLIENT_SIDE_CACHING = "ZENML_PREVENT_CLIENT_SIDE_CACHING"
|
198
198
|
ENV_ZENML_DISABLE_CREDENTIALS_DISK_CACHING = "DISABLE_CREDENTIALS_DISK_CACHING"
|
199
|
-
|
199
|
+
ENV_ZENML_RUNNER_IMAGE_DISABLE_UV = "ZENML_RUNNER_IMAGE_DISABLE_UV"
|
200
200
|
# Logging variables
|
201
201
|
IS_DEBUG_ENV: bool = handle_bool_env_var(ENV_ZENML_DEBUG, default=False)
|
202
202
|
|
@@ -51,7 +51,11 @@ if TYPE_CHECKING:
|
|
51
51
|
DagConfiguration,
|
52
52
|
TaskConfiguration,
|
53
53
|
)
|
54
|
-
from zenml.models import
|
54
|
+
from zenml.models import (
|
55
|
+
PipelineDeploymentResponse,
|
56
|
+
PipelineRunResponse,
|
57
|
+
ScheduleResponse,
|
58
|
+
)
|
55
59
|
from zenml.stack import Stack
|
56
60
|
|
57
61
|
logger = get_logger(__name__)
|
@@ -192,6 +196,7 @@ class AirflowOrchestrator(ContainerizedOrchestrator):
|
|
192
196
|
deployment: "PipelineDeploymentResponse",
|
193
197
|
stack: "Stack",
|
194
198
|
environment: Dict[str, str],
|
199
|
+
placeholder_run: Optional["PipelineRunResponse"] = None,
|
195
200
|
) -> Any:
|
196
201
|
"""Creates and writes an Airflow DAG zip file.
|
197
202
|
|
@@ -200,7 +205,7 @@ class AirflowOrchestrator(ContainerizedOrchestrator):
|
|
200
205
|
stack: The stack the pipeline will run on.
|
201
206
|
environment: Environment variables to set in the orchestration
|
202
207
|
environment.
|
203
|
-
|
208
|
+
placeholder_run: An optional placeholder run for the deployment.
|
204
209
|
"""
|
205
210
|
pipeline_settings = cast(
|
206
211
|
AirflowOrchestratorSettings, self.get_settings(deployment)
|
@@ -267,6 +267,7 @@ class SagemakerOrchestrator(ContainerizedOrchestrator):
|
|
267
267
|
deployment: "PipelineDeploymentResponse",
|
268
268
|
stack: "Stack",
|
269
269
|
environment: Dict[str, str],
|
270
|
+
placeholder_run: Optional["PipelineRunResponse"] = None,
|
270
271
|
) -> Iterator[Dict[str, MetadataType]]:
|
271
272
|
"""Prepares or runs a pipeline on Sagemaker.
|
272
273
|
|
@@ -275,6 +276,7 @@ class SagemakerOrchestrator(ContainerizedOrchestrator):
|
|
275
276
|
stack: The stack to run on.
|
276
277
|
environment: Environment variables to set in the orchestration
|
277
278
|
environment.
|
279
|
+
placeholder_run: An optional placeholder run for the deployment.
|
278
280
|
|
279
281
|
Raises:
|
280
282
|
RuntimeError: If there is an error creating or scheduling the
|
@@ -203,6 +203,7 @@ class AzureMLOrchestrator(ContainerizedOrchestrator):
|
|
203
203
|
deployment: "PipelineDeploymentResponse",
|
204
204
|
stack: "Stack",
|
205
205
|
environment: Dict[str, str],
|
206
|
+
placeholder_run: Optional["PipelineRunResponse"] = None,
|
206
207
|
) -> Iterator[Dict[str, MetadataType]]:
|
207
208
|
"""Prepares or runs a pipeline on AzureML.
|
208
209
|
|
@@ -211,6 +212,7 @@ class AzureMLOrchestrator(ContainerizedOrchestrator):
|
|
211
212
|
stack: The stack to run on.
|
212
213
|
environment: Environment variables to set in the orchestration
|
213
214
|
environment.
|
215
|
+
placeholder_run: An optional placeholder run for the deployment.
|
214
216
|
|
215
217
|
Raises:
|
216
218
|
RuntimeError: If the creation of the schedule fails.
|
@@ -58,7 +58,7 @@ from zenml.utils.pipeline_docker_image_builder import (
|
|
58
58
|
)
|
59
59
|
|
60
60
|
if TYPE_CHECKING:
|
61
|
-
from zenml.models import PipelineDeploymentResponse
|
61
|
+
from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
|
62
62
|
from zenml.stack import Stack
|
63
63
|
|
64
64
|
|
@@ -201,6 +201,7 @@ class DatabricksOrchestrator(WheeledOrchestrator):
|
|
201
201
|
deployment: "PipelineDeploymentResponse",
|
202
202
|
stack: "Stack",
|
203
203
|
environment: Dict[str, str],
|
204
|
+
placeholder_run: Optional["PipelineRunResponse"] = None,
|
204
205
|
) -> Any:
|
205
206
|
"""Creates a wheel and uploads the pipeline to Databricks.
|
206
207
|
|
@@ -225,6 +226,7 @@ class DatabricksOrchestrator(WheeledOrchestrator):
|
|
225
226
|
stack: The stack the pipeline will run on.
|
226
227
|
environment: Environment variables to set in the orchestration
|
227
228
|
environment.
|
229
|
+
placeholder_run: An optional placeholder run for the deployment.
|
228
230
|
|
229
231
|
Raises:
|
230
232
|
ValueError: If the schedule is not set or if the cron expression
|
@@ -357,6 +357,7 @@ class VertexOrchestrator(ContainerizedOrchestrator, GoogleCredentialsMixin):
|
|
357
357
|
deployment: "PipelineDeploymentResponse",
|
358
358
|
stack: "Stack",
|
359
359
|
environment: Dict[str, str],
|
360
|
+
placeholder_run: Optional["PipelineRunResponse"] = None,
|
360
361
|
) -> Iterator[Dict[str, MetadataType]]:
|
361
362
|
"""Creates a KFP JSON pipeline.
|
362
363
|
|
@@ -390,6 +391,7 @@ class VertexOrchestrator(ContainerizedOrchestrator, GoogleCredentialsMixin):
|
|
390
391
|
stack: The stack the pipeline will run on.
|
391
392
|
environment: Environment variables to set in the orchestration
|
392
393
|
environment.
|
394
|
+
placeholder_run: An optional placeholder run for the deployment.
|
393
395
|
|
394
396
|
Raises:
|
395
397
|
ValueError: If the attribute `pipeline_root` is not set, and it
|
@@ -36,7 +36,7 @@ from zenml.orchestrators import (
|
|
36
36
|
from zenml.stack import Stack, StackValidator
|
37
37
|
|
38
38
|
if TYPE_CHECKING:
|
39
|
-
from zenml.models import PipelineDeploymentResponse
|
39
|
+
from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
|
40
40
|
|
41
41
|
logger = get_logger(__name__)
|
42
42
|
|
@@ -164,6 +164,7 @@ class HyperAIOrchestrator(ContainerizedOrchestrator):
|
|
164
164
|
deployment: "PipelineDeploymentResponse",
|
165
165
|
stack: "Stack",
|
166
166
|
environment: Dict[str, str],
|
167
|
+
placeholder_run: Optional["PipelineRunResponse"] = None,
|
167
168
|
) -> Any:
|
168
169
|
"""Sequentially runs all pipeline steps in Docker containers.
|
169
170
|
|
@@ -182,6 +183,7 @@ class HyperAIOrchestrator(ContainerizedOrchestrator):
|
|
182
183
|
stack: The stack the pipeline will run on.
|
183
184
|
environment: Environment variables to set in the orchestration
|
184
185
|
environment.
|
186
|
+
placeholder_run: An optional placeholder run for the deployment.
|
185
187
|
|
186
188
|
Raises:
|
187
189
|
RuntimeError: If a step fails.
|
@@ -75,7 +75,7 @@ from zenml.stack import StackValidator
|
|
75
75
|
from zenml.utils import io_utils, settings_utils, yaml_utils
|
76
76
|
|
77
77
|
if TYPE_CHECKING:
|
78
|
-
from zenml.models import PipelineDeploymentResponse
|
78
|
+
from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
|
79
79
|
from zenml.stack import Stack
|
80
80
|
|
81
81
|
|
@@ -471,6 +471,7 @@ class KubeflowOrchestrator(ContainerizedOrchestrator):
|
|
471
471
|
deployment: "PipelineDeploymentResponse",
|
472
472
|
stack: "Stack",
|
473
473
|
environment: Dict[str, str],
|
474
|
+
placeholder_run: Optional["PipelineRunResponse"] = None,
|
474
475
|
) -> Any:
|
475
476
|
"""Creates a kfp yaml file.
|
476
477
|
|
@@ -501,6 +502,7 @@ class KubeflowOrchestrator(ContainerizedOrchestrator):
|
|
501
502
|
stack: The stack the pipeline will run on.
|
502
503
|
environment: Environment variables to set in the orchestration
|
503
504
|
environment.
|
505
|
+
placeholder_run: An optional placeholder run for the deployment.
|
504
506
|
|
505
507
|
Raises:
|
506
508
|
RuntimeError: If trying to run a pipeline in a notebook
|
@@ -47,6 +47,14 @@ class KubernetesOrchestratorSettings(BaseSettings):
|
|
47
47
|
pod_settings: Pod settings to apply to pods executing the steps.
|
48
48
|
orchestrator_pod_settings: Pod settings to apply to the pod which is
|
49
49
|
launching the actual steps.
|
50
|
+
pod_startup_timeout: The maximum time to wait for a pending step pod to
|
51
|
+
start (in seconds).
|
52
|
+
pod_failure_max_retries: The maximum number of times to retry a step
|
53
|
+
pod if the step Kubernetes pod fails to start
|
54
|
+
pod_failure_retry_delay: The delay in seconds between pod
|
55
|
+
failure retries and pod startup retries (in seconds)
|
56
|
+
pod_failure_backoff: The backoff factor for pod failure retries and
|
57
|
+
pod startup retries.
|
50
58
|
"""
|
51
59
|
|
52
60
|
synchronous: bool = True
|
@@ -56,6 +64,10 @@ class KubernetesOrchestratorSettings(BaseSettings):
|
|
56
64
|
privileged: bool = False
|
57
65
|
pod_settings: Optional[KubernetesPodSettings] = None
|
58
66
|
orchestrator_pod_settings: Optional[KubernetesPodSettings] = None
|
67
|
+
pod_startup_timeout: int = 60 * 10 # Default 10 minutes
|
68
|
+
pod_failure_max_retries: int = 3
|
69
|
+
pod_failure_retry_delay: int = 10
|
70
|
+
pod_failure_backoff: float = 1.0
|
59
71
|
|
60
72
|
|
61
73
|
class KubernetesOrchestratorConfig(
|
@@ -264,6 +264,9 @@ def wait_pod(
|
|
264
264
|
|
265
265
|
resp = get_pod(core_api, pod_name, namespace)
|
266
266
|
|
267
|
+
if resp is None:
|
268
|
+
raise RuntimeError(f"Pod `{namespace}:{pod_name}` not found.")
|
269
|
+
|
267
270
|
# Stream logs to `zenml.logger.info()`.
|
268
271
|
# TODO: can we do this without parsing all logs every time?
|
269
272
|
if stream_logs and pod_is_not_pending(resp):
|
@@ -67,7 +67,7 @@ from zenml.orchestrators.utils import get_orchestrator_run_name
|
|
67
67
|
from zenml.stack import StackValidator
|
68
68
|
|
69
69
|
if TYPE_CHECKING:
|
70
|
-
from zenml.models import PipelineDeploymentResponse
|
70
|
+
from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
|
71
71
|
from zenml.stack import Stack
|
72
72
|
|
73
73
|
logger = get_logger(__name__)
|
@@ -393,6 +393,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
|
|
393
393
|
deployment: "PipelineDeploymentResponse",
|
394
394
|
stack: "Stack",
|
395
395
|
environment: Dict[str, str],
|
396
|
+
placeholder_run: Optional["PipelineRunResponse"] = None,
|
396
397
|
) -> Any:
|
397
398
|
"""Runs the pipeline in Kubernetes.
|
398
399
|
|
@@ -401,6 +402,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
|
|
401
402
|
stack: The stack the pipeline will run on.
|
402
403
|
environment: Environment variables to set in the orchestration
|
403
404
|
environment.
|
405
|
+
placeholder_run: An optional placeholder run for the deployment.
|
404
406
|
|
405
407
|
Raises:
|
406
408
|
RuntimeError: If the Kubernetes orchestrator is not configured.
|
@@ -450,6 +452,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
|
|
450
452
|
run_name=orchestrator_run_name,
|
451
453
|
deployment_id=deployment.id,
|
452
454
|
kubernetes_namespace=self.config.kubernetes_namespace,
|
455
|
+
run_id=placeholder_run.id if placeholder_run else None,
|
453
456
|
)
|
454
457
|
|
455
458
|
settings = cast(
|
@@ -15,6 +15,9 @@
|
|
15
15
|
|
16
16
|
import argparse
|
17
17
|
import socket
|
18
|
+
import time
|
19
|
+
from typing import Any, Dict
|
20
|
+
from uuid import UUID
|
18
21
|
|
19
22
|
from kubernetes import client as k8s_client
|
20
23
|
|
@@ -22,6 +25,8 @@ from zenml.client import Client
|
|
22
25
|
from zenml.entrypoints.step_entrypoint_configuration import (
|
23
26
|
StepEntrypointConfiguration,
|
24
27
|
)
|
28
|
+
from zenml.enums import ExecutionStatus
|
29
|
+
from zenml.exceptions import AuthorizationException
|
25
30
|
from zenml.integrations.kubernetes.flavors.kubernetes_orchestrator_flavor import (
|
26
31
|
KubernetesOrchestratorSettings,
|
27
32
|
)
|
@@ -35,7 +40,8 @@ from zenml.integrations.kubernetes.orchestrators.manifest_utils import (
|
|
35
40
|
build_pod_manifest,
|
36
41
|
)
|
37
42
|
from zenml.logger import get_logger
|
38
|
-
from zenml.orchestrators
|
43
|
+
from zenml.orchestrators import publish_utils
|
44
|
+
from zenml.orchestrators.dag_runner import NodeStatus, ThreadedDagRunner
|
39
45
|
from zenml.orchestrators.utils import get_config_environment_vars
|
40
46
|
|
41
47
|
logger = get_logger(__name__)
|
@@ -51,6 +57,7 @@ def parse_args() -> argparse.Namespace:
|
|
51
57
|
parser.add_argument("--run_name", type=str, required=True)
|
52
58
|
parser.add_argument("--deployment_id", type=str, required=True)
|
53
59
|
parser.add_argument("--kubernetes_namespace", type=str, required=True)
|
60
|
+
parser.add_argument("--run_id", type=str, required=False)
|
54
61
|
return parser.parse_args()
|
55
62
|
|
56
63
|
|
@@ -64,7 +71,9 @@ def main() -> None:
|
|
64
71
|
|
65
72
|
orchestrator_run_id = socket.gethostname()
|
66
73
|
|
67
|
-
|
74
|
+
client = Client()
|
75
|
+
|
76
|
+
deployment_config = client.get_deployment(args.deployment_id)
|
68
77
|
|
69
78
|
pipeline_dag = {
|
70
79
|
step_name: step.spec.upstream_steps
|
@@ -72,7 +81,7 @@ def main() -> None:
|
|
72
81
|
}
|
73
82
|
step_command = StepEntrypointConfiguration.get_entrypoint_command()
|
74
83
|
|
75
|
-
active_stack =
|
84
|
+
active_stack = client.active_stack
|
76
85
|
mount_local_stores = active_stack.orchestrator.config.is_local
|
77
86
|
|
78
87
|
# Get a Kubernetes client from the active Kubernetes orchestrator, but
|
@@ -91,6 +100,11 @@ def main() -> None:
|
|
91
100
|
|
92
101
|
Args:
|
93
102
|
step_name: Name of the step.
|
103
|
+
|
104
|
+
Raises:
|
105
|
+
Exception: If the pod fails to start.
|
106
|
+
TimeoutError: If the pod is still in a pending state after the
|
107
|
+
maximum wait time has elapsed.
|
94
108
|
"""
|
95
109
|
# Define Kubernetes pod name.
|
96
110
|
pod_name = f"{orchestrator_run_id}-{step_name}"
|
@@ -162,24 +176,154 @@ def main() -> None:
|
|
162
176
|
mount_local_stores=mount_local_stores,
|
163
177
|
)
|
164
178
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
179
|
+
retries = 0
|
180
|
+
max_retries = settings.pod_failure_max_retries
|
181
|
+
delay: float = settings.pod_failure_retry_delay
|
182
|
+
backoff = settings.pod_failure_backoff
|
183
|
+
|
184
|
+
while retries < max_retries:
|
185
|
+
try:
|
186
|
+
# Create and run pod.
|
187
|
+
core_api.create_namespaced_pod(
|
188
|
+
namespace=args.kubernetes_namespace,
|
189
|
+
body=pod_manifest,
|
190
|
+
)
|
191
|
+
break
|
192
|
+
except Exception as e:
|
193
|
+
retries += 1
|
194
|
+
if retries < max_retries:
|
195
|
+
logger.debug(
|
196
|
+
f"Pod for step `{step_name}` failed to start: {e}"
|
197
|
+
)
|
198
|
+
logger.error(
|
199
|
+
f"Failed to create pod for step `{step_name}`. "
|
200
|
+
f"Retrying in {delay} seconds..."
|
201
|
+
)
|
202
|
+
time.sleep(delay)
|
203
|
+
delay *= backoff
|
204
|
+
else:
|
205
|
+
logger.error(
|
206
|
+
f"Failed to create pod for step `{step_name}` after "
|
207
|
+
f"{max_retries} retries. Exiting."
|
208
|
+
)
|
209
|
+
raise
|
210
|
+
|
211
|
+
# Wait for pod to start
|
212
|
+
max_wait = settings.pod_startup_timeout
|
213
|
+
total_wait: float = 0
|
214
|
+
delay = settings.pod_failure_retry_delay
|
215
|
+
while True:
|
216
|
+
pod = kube_utils.get_pod(
|
217
|
+
core_api, pod_name, args.kubernetes_namespace
|
218
|
+
)
|
219
|
+
if not pod or kube_utils.pod_is_not_pending(pod):
|
220
|
+
break
|
221
|
+
if total_wait >= max_wait:
|
222
|
+
# Have to delete the pending pod so it doesn't start running
|
223
|
+
# later on.
|
224
|
+
try:
|
225
|
+
core_api.delete_namespaced_pod(
|
226
|
+
name=pod_name,
|
227
|
+
namespace=args.kubernetes_namespace,
|
228
|
+
)
|
229
|
+
except Exception:
|
230
|
+
pass
|
231
|
+
raise TimeoutError(
|
232
|
+
f"Pod for step `{step_name}` is still in a pending state "
|
233
|
+
f"after {total_wait} seconds. Exiting."
|
234
|
+
)
|
235
|
+
|
236
|
+
if total_wait + delay > max_wait:
|
237
|
+
delay = max_wait - total_wait
|
238
|
+
total_wait += delay
|
239
|
+
time.sleep(delay)
|
240
|
+
delay *= backoff
|
170
241
|
|
171
242
|
# Wait for pod to finish.
|
172
|
-
logger.info(f"Waiting for pod of step `{step_name}` to
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
243
|
+
logger.info(f"Waiting for pod of step `{step_name}` to finish...")
|
244
|
+
try:
|
245
|
+
kube_utils.wait_pod(
|
246
|
+
kube_client_fn=lambda: orchestrator.get_kube_client(
|
247
|
+
incluster=True
|
248
|
+
),
|
249
|
+
pod_name=pod_name,
|
250
|
+
namespace=args.kubernetes_namespace,
|
251
|
+
exit_condition_lambda=kube_utils.pod_is_done,
|
252
|
+
stream_logs=True,
|
253
|
+
)
|
254
|
+
|
255
|
+
logger.info(f"Pod for step `{step_name}` completed.")
|
256
|
+
except Exception:
|
257
|
+
logger.error(f"Pod for step `{step_name}` failed.")
|
258
|
+
|
259
|
+
raise
|
260
|
+
|
261
|
+
def finalize_run(node_states: Dict[str, NodeStatus]) -> None:
|
262
|
+
"""Finalize the run.
|
263
|
+
|
264
|
+
Args:
|
265
|
+
node_states: The states of the nodes.
|
266
|
+
"""
|
267
|
+
try:
|
268
|
+
# Some steps may have failed because the pods could not be created.
|
269
|
+
# We need to check for this and mark the step run as failed if so.
|
270
|
+
|
271
|
+
# Fetch the pipeline run using any means possible.
|
272
|
+
list_args: Dict[str, Any] = {}
|
273
|
+
if args.run_id:
|
274
|
+
# For a run triggered outside of a schedule, we can use the
|
275
|
+
# placeholder run ID to find the pipeline run.
|
276
|
+
list_args = dict(id=UUID(args.run_id))
|
277
|
+
else:
|
278
|
+
# For a run triggered by a schedule, we can only use the
|
279
|
+
# orchestrator run ID to find the pipeline run.
|
280
|
+
list_args = dict(orchestrator_run_id=orchestrator_run_id)
|
281
|
+
|
282
|
+
pipeline_runs = client.list_pipeline_runs(
|
283
|
+
hydrate=True,
|
284
|
+
project=deployment_config.project.id,
|
285
|
+
deployment_id=deployment_config.id,
|
286
|
+
**list_args,
|
287
|
+
)
|
288
|
+
if not len(pipeline_runs):
|
289
|
+
# No pipeline run found, so we can't mark any step runs as failed.
|
290
|
+
return
|
291
|
+
|
292
|
+
pipeline_run = pipeline_runs[0]
|
293
|
+
pipeline_failed = False
|
294
|
+
|
295
|
+
for step_name, node_state in node_states.items():
|
296
|
+
if node_state != NodeStatus.FAILED:
|
297
|
+
continue
|
298
|
+
|
299
|
+
pipeline_failed = True
|
300
|
+
|
301
|
+
# If steps failed for any reason, we need to mark the step run as
|
302
|
+
# failed, if it exists and it wasn't already in a final state.
|
303
|
+
|
304
|
+
step_run = pipeline_run.steps.get(step_name)
|
305
|
+
|
306
|
+
# Try to update the step run status, if it exists and is in
|
307
|
+
# a transient state.
|
308
|
+
if step_run and step_run.status in {
|
309
|
+
ExecutionStatus.INITIALIZING,
|
310
|
+
ExecutionStatus.RUNNING,
|
311
|
+
}:
|
312
|
+
publish_utils.publish_failed_step_run(step_run.id)
|
313
|
+
|
314
|
+
# If any steps failed and the pipeline run is still in a transient
|
315
|
+
# state, we need to mark it as failed.
|
316
|
+
if pipeline_failed and pipeline_run.status in {
|
317
|
+
ExecutionStatus.INITIALIZING,
|
318
|
+
ExecutionStatus.RUNNING,
|
319
|
+
}:
|
320
|
+
publish_utils.publish_failed_pipeline_run(pipeline_run.id)
|
321
|
+
except AuthorizationException:
|
322
|
+
# If a step of the pipeline failed or all of them completed
|
323
|
+
# successfully, the pipeline run will be finished and the API token
|
324
|
+
# will be invalidated. We catch this exception and do nothing here,
|
325
|
+
# as the pipeline run status will already have been published.
|
326
|
+
pass
|
183
327
|
|
184
328
|
parallel_node_startup_waiting_period = (
|
185
329
|
orchestrator.config.parallel_step_startup_waiting_period or 0.0
|
@@ -188,6 +332,7 @@ def main() -> None:
|
|
188
332
|
ThreadedDagRunner(
|
189
333
|
dag=pipeline_dag,
|
190
334
|
run_fn=run_step_on_kubernetes,
|
335
|
+
finalize_fn=finalize_run,
|
191
336
|
parallel_node_startup_waiting_period=parallel_node_startup_waiting_period,
|
192
337
|
).run()
|
193
338
|
logger.info("Orchestration pod completed.")
|