zenml-nightly 0.83.0.dev20250623__py3-none-any.whl → 0.83.1.dev20250625__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/login.py +21 -3
- zenml/config/__init__.py +13 -2
- zenml/constants.py +0 -1
- zenml/exceptions.py +16 -0
- zenml/integrations/airflow/orchestrators/airflow_orchestrator.py +15 -6
- zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +54 -58
- zenml/integrations/azure/orchestrators/azureml_orchestrator.py +28 -19
- zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +19 -63
- zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +36 -61
- zenml/integrations/hyperai/orchestrators/hyperai_orchestrator.py +19 -22
- zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +28 -31
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +33 -20
- zenml/integrations/lightning/orchestrators/lightning_orchestrator.py +25 -100
- zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +19 -8
- zenml/integrations/skypilot/utils.py +17 -13
- zenml/integrations/tekton/orchestrators/tekton_orchestrator.py +28 -12
- zenml/models/v2/core/step_run.py +1 -0
- zenml/orchestrators/__init__.py +2 -0
- zenml/orchestrators/base_orchestrator.py +137 -66
- zenml/orchestrators/input_utils.py +5 -13
- zenml/orchestrators/local/local_orchestrator.py +19 -9
- zenml/orchestrators/local_docker/local_docker_orchestrator.py +15 -5
- zenml/orchestrators/publish_utils.py +24 -0
- zenml/orchestrators/step_run_utils.py +1 -2
- zenml/pipelines/run_utils.py +12 -7
- zenml/step_operators/step_operator_entrypoint_configuration.py +1 -1
- zenml/zen_server/dashboard/assets/{404-DmJUgorp.js → 404-B5eko6XL.js} +1 -1
- zenml/zen_server/dashboard/assets/{@reactflow-8OCk19Fi.js → @reactflow-B_iCtR7X.js} +1 -1
- zenml/zen_server/dashboard/assets/{AlertDialogDropdownItem-CZW4QyWn.js → AlertDialogDropdownItem-DsOmO1FH.js} +1 -1
- zenml/zen_server/dashboard/assets/{ButtonGroup-DFWWFGUE.js → ButtonGroup-4sPZDv70.js} +1 -1
- zenml/zen_server/dashboard/assets/{CodeSnippet-D2HkkAGr.js → CodeSnippet-Ctplhzdc.js} +1 -1
- zenml/zen_server/dashboard/assets/{CollapsibleCard-CnS09ljw.js → CollapsibleCard-CBKenz9f.js} +1 -1
- zenml/zen_server/dashboard/assets/{ComponentBadge-CDgdd0Ks.js → ComponentBadge-Cnecw3qz.js} +1 -1
- zenml/zen_server/dashboard/assets/{ComponentIcon-CbbOc7lb.js → ComponentIcon-CMiVW-O6.js} +1 -1
- zenml/zen_server/dashboard/assets/{DeleteAlertDialog-VIOMDLmx.js → DeleteAlertDialog-DEI0YDzP.js} +1 -1
- zenml/zen_server/dashboard/assets/{DialogItem-ClFCqxEp.js → DialogItem-CRCDpYU6.js} +1 -1
- zenml/zen_server/dashboard/assets/{Error-CQzjbDcN.js → Error-BG6f_WRd.js} +1 -1
- zenml/zen_server/dashboard/assets/{ExecutionStatus-CWreILP0.js → ExecutionStatus-BuhNAE9w.js} +1 -1
- zenml/zen_server/dashboard/assets/{Helpbox-CiKxG5_X.js → Helpbox-DtUG2Bf_.js} +1 -1
- zenml/zen_server/dashboard/assets/{Infobox-CGxFvqzi.js → Infobox-CSBRrM6r.js} +1 -1
- zenml/zen_server/dashboard/assets/{LeftSideMenu-DCsKdIjC.js → LeftSideMenu-DPsCCK3z.js} +1 -1
- zenml/zen_server/dashboard/assets/{NestedCollapsible-3M4llYtH.js → NestedCollapsible-CMuDIJlp.js} +1 -1
- zenml/zen_server/dashboard/assets/{NumberBox-C0mQktmV.js → NumberBox-DtCv7jh3.js} +1 -1
- zenml/zen_server/dashboard/assets/Pagination-CWnEpSpN.js +1 -0
- zenml/zen_server/dashboard/assets/{Partials-DSjkttlz.js → Partials-CfHD6OH5.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProCta-Dm5cWKpS.js → ProCta-CNyp04C8.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProviderIcon-DPwMR6nF.js → ProviderIcon-DHejyg7C.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProviderRadio-DEDNRgAb.js → ProviderRadio-tGtie8Gc.js} +1 -1
- zenml/zen_server/dashboard/assets/RunsBody-mYwMcWWj.js +1 -0
- zenml/zen_server/dashboard/assets/SearchField-BtUi6cYl.js +1 -0
- zenml/zen_server/dashboard/assets/{SecretTooltip-CZTRnaCV.js → SecretTooltip-B5u1UsQ9.js} +1 -1
- zenml/zen_server/dashboard/assets/{SetPassword-BjNGDC5e.js → SetPassword-BmbgL_ed.js} +1 -1
- zenml/zen_server/dashboard/assets/{SheetHeader-CASpN2Lz.js → SheetHeader-DkH7aG9K.js} +1 -1
- zenml/zen_server/dashboard/assets/StackComponentList-Bi8BKqCu.js +1 -0
- zenml/zen_server/dashboard/assets/StackList-Cvxapo0p.js +1 -0
- zenml/zen_server/dashboard/assets/{StackName-ojLC6xdl.js → StackName-CFSZL8ec.js} +1 -1
- zenml/zen_server/dashboard/assets/Tabs-D4dv48ry.js +1 -0
- zenml/zen_server/dashboard/assets/{Tick-BPrWnNlN.js → Tick-Qquvr4P3.js} +1 -1
- zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-CNfKDo2Q.js → UpdatePasswordSchemas-D_DCETSO.js} +1 -1
- zenml/zen_server/dashboard/assets/{UsageReason-Cb-mpV8M.js → UsageReason-DhiUV1bu.js} +1 -1
- zenml/zen_server/dashboard/assets/{Wizard-Dg8Pmn5A.js → Wizard-BHvY75u_.js} +1 -1
- zenml/zen_server/dashboard/assets/{WizardFooter-BcNDIvlQ.js → WizardFooter-FQm8y-jP.js} +1 -1
- zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-DCdax7I5.js → all-pipeline-runs-query-DpKw9WL9.js} +1 -1
- zenml/zen_server/dashboard/assets/{bulk-delete-C_kpIB9A.js → bulk-delete-CzYA--cC.js} +1 -1
- zenml/zen_server/dashboard/assets/{configuration-form-B2hmKGnF.js → configuration-form-DSoMMiPE.js} +1 -1
- zenml/zen_server/dashboard/assets/{constants-1EZZxtay.js → constants-DTfsIqHy.js} +1 -1
- zenml/zen_server/dashboard/assets/{create-stack-TKmMtrkQ.js → create-stack-BpZrmKDu.js} +1 -1
- zenml/zen_server/dashboard/assets/{delete-run-CCR9md_s.js → delete-run-BkyDsKQc.js} +1 -1
- zenml/zen_server/dashboard/assets/elk-worker.min-BdOC9sib.js +6263 -0
- zenml/zen_server/dashboard/assets/expand-full-BPiXpch2.js +1 -0
- zenml/zen_server/dashboard/assets/{form-DFJkaFDX.js → form-BgtamtJm.js} +1 -1
- zenml/zen_server/dashboard/assets/{form-schemas-CrznJVzA.js → form-schemas-dyDkAxXP.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-BjUu1mP4.js → index-BBt0LDtR.js} +1 -1
- zenml/zen_server/dashboard/assets/index-BfNISy0X.css +1 -0
- zenml/zen_server/dashboard/assets/{index-BFqbGSck.js → index-BgEfQ3_G.js} +4 -4
- zenml/zen_server/dashboard/assets/{index-U992soPJ.js → index-eoDB_1XX.js} +1 -1
- zenml/zen_server/dashboard/assets/{layout-Do9YI4QX.js → layout-o1x87a3q.js} +1 -1
- zenml/zen_server/dashboard/assets/{login-mutation-D3tFP6Wm.js → login-mutation-C1hvP_cX.js} +1 -1
- zenml/zen_server/dashboard/assets/page-4xUZpMN0.js +31 -0
- zenml/zen_server/dashboard/assets/page-4zc4xPv2.js +2 -0
- zenml/zen_server/dashboard/assets/page-B0104V6C.js +1 -0
- zenml/zen_server/dashboard/assets/page-BNJsjvof.js +1 -0
- zenml/zen_server/dashboard/assets/{page-sJjNT9xA.js → page-BPQ66vR-.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-CAJ8B0vb.js → page-BQgSZ2nH.js} +1 -1
- zenml/zen_server/dashboard/assets/page-BXl2ZX6J.js +1 -0
- zenml/zen_server/dashboard/assets/{page-CtiuMP_r.js → page-BxeZrG_t.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-Cal6XQ4U.js → page-C2A-2Cj_.js} +1 -1
- zenml/zen_server/dashboard/assets/page-C2i-C7jv.js +1 -0
- zenml/zen_server/dashboard/assets/{page-DJIGaUQ9.js → page-C3JfJxuR.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-ChGcZI_6.js → page-CESEqC2L.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DCcuPZ8P.js → page-CF8cTZ7l.js} +1 -1
- zenml/zen_server/dashboard/assets/page-CKjsimVu.js +1 -0
- zenml/zen_server/dashboard/assets/{page-DNjKHjnH.js → page-COLzBwff.js} +1 -1
- zenml/zen_server/dashboard/assets/page-COifg5fa.js +1 -0
- zenml/zen_server/dashboard/assets/{page-CnbIYE80.js → page-CQeJuA8T.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DKK6ulgy.js → page-CcjWEjre.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-9RjCitFH.js → page-CefGLeWy.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DUKbOhaD.js → page-CfxpV3j4.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-D9Hfx6GV.js → page-ClcUzawe.js} +1 -1
- zenml/zen_server/dashboard/assets/page-Ct_LB3zo.js +1 -0
- zenml/zen_server/dashboard/assets/page-D-ZWUMYY.js +1 -0
- zenml/zen_server/dashboard/assets/{page-CUaMMoPG.js → page-D-tJ_Y0a.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-CdZCmszX.js → page-DHrvih9u.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DUK0Nd_1.js → page-DMhaHZDw.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-CAUYrfui.js → page-DOCOmmKn.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-akLcPcKw.js → page-DcQmxKLp.js} +1 -1
- zenml/zen_server/dashboard/assets/page-Dh4GRWw5.js +1 -0
- zenml/zen_server/dashboard/assets/{page-DwVPpCFg.js → page-DiHZK-1w.js} +1 -1
- zenml/zen_server/dashboard/assets/page-Dn7ZNapg.js +1 -0
- zenml/zen_server/dashboard/assets/page-Dy4vSQY7.js +1 -0
- zenml/zen_server/dashboard/assets/{page-CN7lkvXr.js → page-QrvWQwZb.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BrT0_zSJ.js → page-RF3Fup0q.js} +1 -1
- zenml/zen_server/dashboard/assets/page-WuvCrN47.js +1 -0
- zenml/zen_server/dashboard/assets/{page-Be3R2uYn.js → page-_WnHBI1F.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-C210HcBA.js → page-ghjVNgVE.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BCrKmYIZ.js → page-iDsDiDXw.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-ClvmVesa.js → page-rVhXI5ZO.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DEohTSz6.js → page-uxjMX8Iq.js} +1 -1
- zenml/zen_server/dashboard/assets/{persist-Dec_w7aB.js → persist-BsdEtCkd.js} +1 -1
- zenml/zen_server/dashboard/assets/{persist-DWMWVP-y.js → persist-CFPbMcJX.js} +1 -1
- zenml/zen_server/dashboard/assets/{resource-tyes-list-o2LXiMay.js → resource-tyes-list-79FqS3LY.js} +1 -1
- zenml/zen_server/dashboard/assets/{resource-type-tooltip-DwHrJstL.js → resource-type-tooltip-BL9ZTRKi.js} +1 -1
- zenml/zen_server/dashboard/assets/{service-connectors-DSEMwJ5A.js → service-connectors-Q8h7-_rG.js} +1 -1
- zenml/zen_server/dashboard/assets/{service-jxtvgks0.js → service-k-9Vsb30.js} +1 -1
- zenml/zen_server/dashboard/assets/{sharedSchema-BXzg0EZz.js → sharedSchema-C_HkejsG.js} +1 -1
- zenml/zen_server/dashboard/assets/{stack-detail-query-Cm0fsgo-.js → stack-detail-query-CNmVZ0Bo.js} +1 -1
- zenml/zen_server/dashboard/assets/{update-current-user-mutation-D5MjcQ6F.js → update-current-user-mutation-Ca-Lmwuj.js} +1 -1
- zenml/zen_server/dashboard/assets/{update-server-settings-mutation-CmnxdxiK.js → update-server-settings-mutation-Bwe3gUt4.js} +1 -1
- zenml/zen_server/dashboard/index.html +4 -4
- zenml/zen_stores/migrations/versions/0.83.1_release.py +23 -0
- zenml/zen_stores/rest_zen_store.py +147 -128
- zenml/zen_stores/sql_zen_store.py +27 -17
- {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/METADATA +5 -9
- {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/RECORD +138 -134
- zenml/zen_server/dashboard/assets/RunsBody-BRBn1e2O.js +0 -1
- zenml/zen_server/dashboard/assets/SearchField-DY6-UbRT.js +0 -1
- zenml/zen_server/dashboard/assets/StackComponentList-Be1pQt9m.js +0 -1
- zenml/zen_server/dashboard/assets/StackList-BdiR5DvR.js +0 -1
- zenml/zen_server/dashboard/assets/Tabs-DNSKblCM.js +0 -1
- zenml/zen_server/dashboard/assets/index-DuhuqTCI.css +0 -1
- zenml/zen_server/dashboard/assets/page-B0PsXWiT.js +0 -1
- zenml/zen_server/dashboard/assets/page-BcRI3-aR.js +0 -29
- zenml/zen_server/dashboard/assets/page-BgknnddT.js +0 -1
- zenml/zen_server/dashboard/assets/page-Bs3W2FDi.js +0 -1
- zenml/zen_server/dashboard/assets/page-C6KaiZ_W.js +0 -1
- zenml/zen_server/dashboard/assets/page-CHxVhF3x.js +0 -1
- zenml/zen_server/dashboard/assets/page-CktmtZ8Z.js +0 -1
- zenml/zen_server/dashboard/assets/page-CoXzjeEY.js +0 -1
- zenml/zen_server/dashboard/assets/page-D9iuB88h.js +0 -1
- zenml/zen_server/dashboard/assets/page-DYOucPtA.js +0 -1
- zenml/zen_server/dashboard/assets/page-DpqRelAy.js +0 -1
- zenml/zen_server/dashboard/assets/page-XURWnYZP.js +0 -1
- zenml/zen_server/dashboard/assets/page-abw-2oeW.js +0 -1
- zenml/zen_server/dashboard/assets/page-n9ejQ2V3.js +0 -2
- {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/entry_points.txt +0 -0
@@ -33,7 +33,6 @@
|
|
33
33
|
import os
|
34
34
|
from typing import (
|
35
35
|
TYPE_CHECKING,
|
36
|
-
Any,
|
37
36
|
Dict,
|
38
37
|
List,
|
39
38
|
Optional,
|
@@ -62,7 +61,7 @@ from zenml.integrations.kubernetes.orchestrators.manifest_utils import (
|
|
62
61
|
)
|
63
62
|
from zenml.integrations.kubernetes.pod_settings import KubernetesPodSettings
|
64
63
|
from zenml.logger import get_logger
|
65
|
-
from zenml.orchestrators import ContainerizedOrchestrator
|
64
|
+
from zenml.orchestrators import ContainerizedOrchestrator, SubmissionResult
|
66
65
|
from zenml.orchestrators.utils import get_orchestrator_run_name
|
67
66
|
from zenml.stack import StackValidator
|
68
67
|
|
@@ -388,24 +387,32 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
|
|
388
387
|
"""
|
389
388
|
return f"zenml-token-{deployment_id}"
|
390
389
|
|
391
|
-
def
|
390
|
+
def submit_pipeline(
|
392
391
|
self,
|
393
392
|
deployment: "PipelineDeploymentResponse",
|
394
393
|
stack: "Stack",
|
395
394
|
environment: Dict[str, str],
|
396
395
|
placeholder_run: Optional["PipelineRunResponse"] = None,
|
397
|
-
) ->
|
398
|
-
"""
|
396
|
+
) -> Optional[SubmissionResult]:
|
397
|
+
"""Submits a pipeline to the orchestrator.
|
398
|
+
|
399
|
+
This method should only submit the pipeline and not wait for it to
|
400
|
+
complete. If the orchestrator is configured to wait for the pipeline run
|
401
|
+
to complete, a function that waits for the pipeline run to complete can
|
402
|
+
be passed as part of the submission result.
|
399
403
|
|
400
404
|
Args:
|
401
|
-
deployment: The pipeline deployment to
|
405
|
+
deployment: The pipeline deployment to submit.
|
402
406
|
stack: The stack the pipeline will run on.
|
403
407
|
environment: Environment variables to set in the orchestration
|
404
|
-
environment.
|
408
|
+
environment. These don't need to be set if running locally.
|
405
409
|
placeholder_run: An optional placeholder run for the deployment.
|
406
410
|
|
407
411
|
Raises:
|
408
|
-
RuntimeError: If
|
412
|
+
RuntimeError: If a schedule without cron expression is given.
|
413
|
+
|
414
|
+
Returns:
|
415
|
+
Optional submission result.
|
409
416
|
"""
|
410
417
|
for step_name, step in deployment.step_configurations.items():
|
411
418
|
if self.requires_resources_in_orchestration_environment(step):
|
@@ -536,7 +543,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
|
|
536
543
|
f"Scheduling Kubernetes run `{pod_name}` with CRON expression "
|
537
544
|
f'`"{cron_expression}"`.'
|
538
545
|
)
|
539
|
-
return
|
546
|
+
return None
|
540
547
|
else:
|
541
548
|
# Create and run the orchestrator pod.
|
542
549
|
pod_manifest = build_pod_manifest(
|
@@ -565,18 +572,23 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
|
|
565
572
|
startup_timeout=settings.pod_startup_timeout,
|
566
573
|
)
|
567
574
|
|
568
|
-
# Wait for the orchestrator pod to finish and stream logs.
|
569
575
|
if settings.synchronous:
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
576
|
+
|
577
|
+
def _wait_for_run_to_finish() -> None:
|
578
|
+
logger.info(
|
579
|
+
"Waiting for Kubernetes orchestrator pod to finish..."
|
580
|
+
)
|
581
|
+
kube_utils.wait_pod(
|
582
|
+
kube_client_fn=self.get_kube_client,
|
583
|
+
pod_name=pod_name,
|
584
|
+
namespace=self.config.kubernetes_namespace,
|
585
|
+
exit_condition_lambda=kube_utils.pod_is_done,
|
586
|
+
timeout_sec=settings.timeout,
|
587
|
+
stream_logs=True,
|
588
|
+
)
|
589
|
+
|
590
|
+
return SubmissionResult(
|
591
|
+
wait_for_completion=_wait_for_run_to_finish
|
580
592
|
)
|
581
593
|
else:
|
582
594
|
logger.info(
|
@@ -585,6 +597,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
|
|
585
597
|
f"Run the following command to inspect the logs: "
|
586
598
|
f"`kubectl logs {pod_name} -n {self.config.kubernetes_namespace}`."
|
587
599
|
)
|
600
|
+
return None
|
588
601
|
|
589
602
|
def _get_service_account_name(
|
590
603
|
self, settings: KubernetesOrchestratorSettings
|
@@ -16,14 +16,14 @@
|
|
16
16
|
import os
|
17
17
|
import tempfile
|
18
18
|
import time
|
19
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional,
|
19
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, cast
|
20
20
|
from uuid import uuid4
|
21
21
|
|
22
22
|
from lightning_sdk import Machine, Studio
|
23
23
|
|
24
|
+
from zenml import __version__
|
24
25
|
from zenml.constants import (
|
25
26
|
ENV_ZENML_CUSTOM_SOURCE_ROOT,
|
26
|
-
ENV_ZENML_WHEEL_PACKAGE_NAME,
|
27
27
|
)
|
28
28
|
from zenml.entrypoints.step_entrypoint_configuration import (
|
29
29
|
StepEntrypointConfiguration,
|
@@ -40,9 +40,8 @@ from zenml.integrations.lightning.orchestrators.utils import (
|
|
40
40
|
sanitize_studio_name,
|
41
41
|
)
|
42
42
|
from zenml.logger import get_logger
|
43
|
+
from zenml.orchestrators import BaseOrchestrator, SubmissionResult
|
43
44
|
from zenml.orchestrators.utils import get_orchestrator_run_name
|
44
|
-
from zenml.orchestrators.wheeled_orchestrator import WheeledOrchestrator
|
45
|
-
from zenml.stack import StackValidator
|
46
45
|
from zenml.utils import code_utils, io_utils, source_utils
|
47
46
|
|
48
47
|
if TYPE_CHECKING:
|
@@ -52,48 +51,11 @@ if TYPE_CHECKING:
|
|
52
51
|
|
53
52
|
logger = get_logger(__name__)
|
54
53
|
ENV_ZENML_LIGHTNING_ORCHESTRATOR_RUN_ID = "ZENML_LIGHTNING_ORCHESTRATOR_RUN_ID"
|
55
|
-
ZENML_STEP_DEFAULT_ENTRYPOINT_COMMAND = "zenml.entrypoints.entrypoint"
|
56
54
|
LIGHTNING_ZENML_DEFAULT_CUSTOM_REPOSITORY_PATH = "."
|
57
55
|
|
58
56
|
|
59
|
-
class LightningOrchestrator(
|
60
|
-
"""
|
61
|
-
|
62
|
-
This orchestrator does not support running on a schedule.
|
63
|
-
"""
|
64
|
-
|
65
|
-
@property
|
66
|
-
def validator(self) -> Optional[StackValidator]:
|
67
|
-
"""Validates the stack.
|
68
|
-
|
69
|
-
In the remote case, checks that the stack contains a container registry,
|
70
|
-
image builder and only remote components.
|
71
|
-
|
72
|
-
Returns:
|
73
|
-
A `StackValidator` instance.
|
74
|
-
"""
|
75
|
-
|
76
|
-
def _validate_remote_components(
|
77
|
-
stack: "Stack",
|
78
|
-
) -> Tuple[bool, str]:
|
79
|
-
for component in stack.components.values():
|
80
|
-
if not component.config.is_local:
|
81
|
-
continue
|
82
|
-
|
83
|
-
# return False, (
|
84
|
-
# f"The Lightning orchestrator runs pipelines remotely, "
|
85
|
-
# f"but the '{component.name}' {component.type.value} is "
|
86
|
-
# "a local stack component and will not be available in "
|
87
|
-
# "the Lightning step.\nPlease ensure that you always "
|
88
|
-
# "use non-local stack components with the Lightning "
|
89
|
-
# "orchestrator."
|
90
|
-
# )
|
91
|
-
|
92
|
-
return True, ""
|
93
|
-
|
94
|
-
return StackValidator(
|
95
|
-
custom_validation_function=_validate_remote_components,
|
96
|
-
)
|
57
|
+
class LightningOrchestrator(BaseOrchestrator):
|
58
|
+
"""Lightning orchestrator."""
|
97
59
|
|
98
60
|
def _set_lightning_env_vars(
|
99
61
|
self,
|
@@ -194,67 +156,39 @@ class LightningOrchestrator(WheeledOrchestrator):
|
|
194
156
|
assert connector is not None
|
195
157
|
connector.configure_local_client()
|
196
158
|
|
197
|
-
def
|
159
|
+
def submit_pipeline(
|
198
160
|
self,
|
199
161
|
deployment: "PipelineDeploymentResponse",
|
200
162
|
stack: "Stack",
|
201
163
|
environment: Dict[str, str],
|
202
164
|
placeholder_run: Optional["PipelineRunResponse"] = None,
|
203
|
-
) ->
|
204
|
-
"""
|
165
|
+
) -> Optional[SubmissionResult]:
|
166
|
+
"""Submits a pipeline to the orchestrator.
|
205
167
|
|
206
|
-
This
|
207
|
-
is
|
208
|
-
|
209
|
-
|
210
|
-
-------------
|
211
|
-
Before this method is called the `prepare_pipeline_deployment()`
|
212
|
-
method builds a docker image that contains the code for the
|
213
|
-
pipeline, all steps the context around these files.
|
214
|
-
|
215
|
-
Based on this docker image a callable is created which builds
|
216
|
-
task for each step (`_construct_lightning_pipeline`).
|
217
|
-
To do this the entrypoint of the docker image is configured to
|
218
|
-
run the correct step within the docker image. The dependencies
|
219
|
-
between these task are then also configured onto each
|
220
|
-
task by pointing at the downstream steps.
|
168
|
+
This method should only submit the pipeline and not wait for it to
|
169
|
+
complete. If the orchestrator is configured to wait for the pipeline run
|
170
|
+
to complete, a function that waits for the pipeline run to complete can
|
171
|
+
be passed as part of the submission result.
|
221
172
|
|
222
173
|
Args:
|
223
|
-
deployment: The pipeline deployment to
|
174
|
+
deployment: The pipeline deployment to submit.
|
224
175
|
stack: The stack the pipeline will run on.
|
225
176
|
environment: Environment variables to set in the orchestration
|
226
|
-
environment.
|
177
|
+
environment. These don't need to be set if running locally.
|
227
178
|
placeholder_run: An optional placeholder run for the deployment.
|
228
179
|
|
229
|
-
|
230
|
-
|
231
|
-
is not set.
|
180
|
+
Returns:
|
181
|
+
Optional submission result.
|
232
182
|
"""
|
233
183
|
settings = cast(
|
234
184
|
LightningOrchestratorSettings, self.get_settings(deployment)
|
235
185
|
)
|
236
186
|
if deployment.schedule:
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
"Lightning orchestrator only uses schedules with the "
|
243
|
-
"`cron_expression` property, with optional `start_time` and/or `end_time`. "
|
244
|
-
"All other properties are ignored."
|
245
|
-
)
|
246
|
-
if deployment.schedule.cron_expression is None:
|
247
|
-
raise ValueError(
|
248
|
-
"Property `cron_expression` must be set when passing "
|
249
|
-
"schedule to a Lightning orchestrator."
|
250
|
-
)
|
251
|
-
if deployment.schedule.cron_expression:
|
252
|
-
raise ValueError(
|
253
|
-
"Property `schedule_timezone` must be set when passing "
|
254
|
-
"`cron_expression` to a Lightning orchestrator."
|
255
|
-
"Lightning orchestrator requires a Java Timezone ID to run the pipeline on schedule."
|
256
|
-
"Please refer to https://docs.oracle.com/middleware/1221/wcs/tag-ref/MISC/TimeZones.html for more information."
|
257
|
-
)
|
187
|
+
logger.warning(
|
188
|
+
"Lightning Orchestrator currently does not support the "
|
189
|
+
"use of schedules. The `schedule` will be ignored "
|
190
|
+
"and the pipeline will be run immediately."
|
191
|
+
)
|
258
192
|
|
259
193
|
# Get deployment id
|
260
194
|
deployment_id = deployment.id
|
@@ -262,13 +196,6 @@ class LightningOrchestrator(WheeledOrchestrator):
|
|
262
196
|
pipeline_name = deployment.pipeline_configuration.name
|
263
197
|
orchestrator_run_name = get_orchestrator_run_name(pipeline_name)
|
264
198
|
|
265
|
-
# Copy the repository to a temporary directory and add a setup.py file
|
266
|
-
# repository_temp_dir = (
|
267
|
-
# self.copy_repository_to_temp_dir_and_add_setup_py()
|
268
|
-
# )
|
269
|
-
|
270
|
-
# Create a wheel for the package in the temporary directory
|
271
|
-
# wheel_path = self.create_wheel(temp_dir=repository_temp_dir)
|
272
199
|
code_archive = code_utils.CodeArchive(
|
273
200
|
root=source_utils.get_source_root()
|
274
201
|
)
|
@@ -287,7 +214,6 @@ class LightningOrchestrator(WheeledOrchestrator):
|
|
287
214
|
env_vars[ENV_ZENML_CUSTOM_SOURCE_ROOT] = (
|
288
215
|
LIGHTNING_ZENML_DEFAULT_CUSTOM_REPOSITORY_PATH
|
289
216
|
)
|
290
|
-
env_vars[ENV_ZENML_WHEEL_PACKAGE_NAME] = self.package_name
|
291
217
|
|
292
218
|
# Create a line-by-line export of environment variables
|
293
219
|
env_exports = "\n".join(
|
@@ -410,7 +336,7 @@ class LightningOrchestrator(WheeledOrchestrator):
|
|
410
336
|
studio.run(
|
411
337
|
f"cd /teamspace/studios/this_studio/zenml_codes/{filename.rsplit('.', 2)[0]} && {custom_command}"
|
412
338
|
)
|
413
|
-
|
339
|
+
|
414
340
|
logger.info("Running pipeline in async mode")
|
415
341
|
studio.run(
|
416
342
|
f"nohup bash -c 'cd /teamspace/studios/this_studio/zenml_codes/{filename.rsplit('.', 2)[0]} && {entrypoint_string}' > log_{filename.rsplit('.', 2)[0]}.txt 2>&1 &"
|
@@ -430,6 +356,7 @@ class LightningOrchestrator(WheeledOrchestrator):
|
|
430
356
|
env_file_path,
|
431
357
|
)
|
432
358
|
os.unlink(env_file_path)
|
359
|
+
return None
|
433
360
|
|
434
361
|
def _upload_and_run_pipeline(
|
435
362
|
self,
|
@@ -507,8 +434,7 @@ class LightningOrchestrator(WheeledOrchestrator):
|
|
507
434
|
|
508
435
|
studio.run("pip install uv")
|
509
436
|
studio.run(f"uv pip install {requirements}")
|
510
|
-
studio.run("pip install zenml")
|
511
|
-
# studio.run(f"pip install {wheel_path.rsplit('/', 1)[-1]}")
|
437
|
+
studio.run(f"uv pip install zenml=={__version__}")
|
512
438
|
for command in settings.custom_commands or []:
|
513
439
|
output = studio.run(
|
514
440
|
f"cd /teamspace/studios/this_studio/zenml_codes/{filename.rsplit('.', 2)[0]} && {command}"
|
@@ -588,8 +514,7 @@ class LightningOrchestrator(WheeledOrchestrator):
|
|
588
514
|
|
589
515
|
studio.run("pip install uv")
|
590
516
|
studio.run(f"uv pip install {details['requirements']}")
|
591
|
-
studio.run("pip install zenml")
|
592
|
-
# studio.run(f"pip install {wheel_path.rsplit('/', 1)[-1]}")
|
517
|
+
studio.run(f"uv pip install zenml=={__version__}")
|
593
518
|
for command in custom_commands or []:
|
594
519
|
output = studio.run(
|
595
520
|
f"cd /teamspace/studios/this_studio/zenml_codes/{filename.rsplit('.', 2)[0]} && {command}"
|
@@ -15,7 +15,7 @@
|
|
15
15
|
|
16
16
|
import os
|
17
17
|
from abc import abstractmethod
|
18
|
-
from typing import TYPE_CHECKING,
|
18
|
+
from typing import TYPE_CHECKING, Dict, Optional, Tuple, cast
|
19
19
|
from uuid import uuid4
|
20
20
|
|
21
21
|
import sky
|
@@ -43,6 +43,7 @@ from zenml.integrations.skypilot.utils import (
|
|
43
43
|
from zenml.logger import get_logger
|
44
44
|
from zenml.orchestrators import (
|
45
45
|
ContainerizedOrchestrator,
|
46
|
+
SubmissionResult,
|
46
47
|
)
|
47
48
|
from zenml.orchestrators.utils import get_orchestrator_run_name
|
48
49
|
from zenml.stack import StackValidator
|
@@ -153,25 +154,33 @@ class SkypilotBaseOrchestrator(ContainerizedOrchestrator):
|
|
153
154
|
set: Whether to set the environment variables or not.
|
154
155
|
"""
|
155
156
|
|
156
|
-
def
|
157
|
+
def submit_pipeline(
|
157
158
|
self,
|
158
159
|
deployment: "PipelineDeploymentResponse",
|
159
160
|
stack: "Stack",
|
160
161
|
environment: Dict[str, str],
|
161
162
|
placeholder_run: Optional["PipelineRunResponse"] = None,
|
162
|
-
) ->
|
163
|
-
"""
|
163
|
+
) -> Optional[SubmissionResult]:
|
164
|
+
"""Submits a pipeline to the orchestrator.
|
165
|
+
|
166
|
+
This method should only submit the pipeline and not wait for it to
|
167
|
+
complete. If the orchestrator is configured to wait for the pipeline run
|
168
|
+
to complete, a function that waits for the pipeline run to complete can
|
169
|
+
be passed as part of the submission result.
|
164
170
|
|
165
171
|
Args:
|
166
|
-
deployment: The pipeline deployment to
|
172
|
+
deployment: The pipeline deployment to submit.
|
167
173
|
stack: The stack the pipeline will run on.
|
168
174
|
environment: Environment variables to set in the orchestration
|
169
|
-
environment.
|
175
|
+
environment. These don't need to be set if running locally.
|
170
176
|
placeholder_run: An optional placeholder run for the deployment.
|
171
177
|
|
172
178
|
Raises:
|
173
179
|
Exception: If the pipeline run fails.
|
174
180
|
RuntimeError: If the code is running in a notebook.
|
181
|
+
|
182
|
+
Returns:
|
183
|
+
Optional submission result.
|
175
184
|
"""
|
176
185
|
# First check whether the code is running in a notebook.
|
177
186
|
if Environment.in_notebook():
|
@@ -366,7 +375,9 @@ class SkypilotBaseOrchestrator(ContainerizedOrchestrator):
|
|
366
375
|
cluster_name,
|
367
376
|
**launch_kwargs,
|
368
377
|
)
|
369
|
-
sky_job_get(
|
378
|
+
return sky_job_get(
|
379
|
+
launch_job_id, settings.stream_logs, cluster_name
|
380
|
+
)
|
370
381
|
|
371
382
|
else:
|
372
383
|
# Prepare exec parameters with additional launch settings
|
@@ -399,7 +410,7 @@ class SkypilotBaseOrchestrator(ContainerizedOrchestrator):
|
|
399
410
|
**exec_kwargs,
|
400
411
|
)
|
401
412
|
assert settings.cluster_name is not None
|
402
|
-
sky_job_get(
|
413
|
+
return sky_job_get(
|
403
414
|
exec_job_id, settings.stream_logs, settings.cluster_name
|
404
415
|
)
|
405
416
|
|
@@ -9,6 +9,7 @@ from zenml.integrations.skypilot.flavors.skypilot_orchestrator_base_vm_config im
|
|
9
9
|
SkypilotBaseOrchestratorSettings,
|
10
10
|
)
|
11
11
|
from zenml.logger import get_logger
|
12
|
+
from zenml.orchestrators import SubmissionResult
|
12
13
|
|
13
14
|
logger = get_logger(__name__)
|
14
15
|
|
@@ -235,7 +236,9 @@ def prepare_launch_kwargs(
|
|
235
236
|
return {k: v for k, v in launch_kwargs.items() if v is not None}
|
236
237
|
|
237
238
|
|
238
|
-
def sky_job_get(
|
239
|
+
def sky_job_get(
|
240
|
+
request_id: str, stream_logs: bool, cluster_name: str
|
241
|
+
) -> Optional[SubmissionResult]:
|
239
242
|
"""Handle SkyPilot request results based on stream_logs setting.
|
240
243
|
|
241
244
|
SkyPilot API exec and launch methods are asynchronous and return a request ID.
|
@@ -249,10 +252,7 @@ def sky_job_get(request_id: str, stream_logs: bool, cluster_name: str) -> Any:
|
|
249
252
|
cluster_name: The name of the cluster to tail logs for.
|
250
253
|
|
251
254
|
Returns:
|
252
|
-
|
253
|
-
|
254
|
-
Raises:
|
255
|
-
Exception: If the SkyPilot job fails.
|
255
|
+
Optional submission result.
|
256
256
|
"""
|
257
257
|
if stream_logs:
|
258
258
|
# Stream logs and wait for completion
|
@@ -261,13 +261,17 @@ def sky_job_get(request_id: str, stream_logs: bool, cluster_name: str) -> Any:
|
|
261
261
|
# Just wait for completion without streaming logs
|
262
262
|
job_id, _ = sky.get(request_id)
|
263
263
|
|
264
|
-
|
264
|
+
_wait_for_completion = None
|
265
265
|
if stream_logs:
|
266
|
-
status = sky.tail_logs(
|
267
|
-
cluster_name=cluster_name, job_id=job_id, follow=True
|
268
|
-
)
|
269
|
-
|
270
|
-
if status != 0:
|
271
|
-
raise Exception(f"SkyPilot job {job_id} failed with status {status}")
|
272
266
|
|
273
|
-
|
267
|
+
def _wait_for_completion() -> None:
|
268
|
+
status = 0 # 0=Successful, 100=Failed
|
269
|
+
status = sky.tail_logs(
|
270
|
+
cluster_name=cluster_name, job_id=job_id, follow=True
|
271
|
+
)
|
272
|
+
if status != 0:
|
273
|
+
raise Exception(
|
274
|
+
f"SkyPilot job {job_id} failed with status {status}"
|
275
|
+
)
|
276
|
+
|
277
|
+
return SubmissionResult(wait_for_completion=_wait_for_completion)
|
@@ -46,7 +46,7 @@ from zenml.integrations.tekton.flavors.tekton_orchestrator_flavor import (
|
|
46
46
|
)
|
47
47
|
from zenml.io import fileio
|
48
48
|
from zenml.logger import get_logger
|
49
|
-
from zenml.orchestrators import ContainerizedOrchestrator
|
49
|
+
from zenml.orchestrators import ContainerizedOrchestrator, SubmissionResult
|
50
50
|
from zenml.orchestrators.utils import get_orchestrator_run_name
|
51
51
|
from zenml.stack import StackValidator
|
52
52
|
from zenml.utils import io_utils, yaml_utils
|
@@ -455,28 +455,33 @@ class TektonOrchestrator(ContainerizedOrchestrator):
|
|
455
455
|
|
456
456
|
return dsl.container_component(dynamic_func)
|
457
457
|
|
458
|
-
def
|
458
|
+
def submit_pipeline(
|
459
459
|
self,
|
460
460
|
deployment: "PipelineDeploymentResponse",
|
461
461
|
stack: "Stack",
|
462
462
|
environment: Dict[str, str],
|
463
463
|
placeholder_run: Optional["PipelineRunResponse"] = None,
|
464
|
-
) ->
|
465
|
-
"""
|
464
|
+
) -> Optional[SubmissionResult]:
|
465
|
+
"""Submits a pipeline to the orchestrator.
|
466
466
|
|
467
|
-
This
|
468
|
-
|
467
|
+
This method should only submit the pipeline and not wait for it to
|
468
|
+
complete. If the orchestrator is configured to wait for the pipeline run
|
469
|
+
to complete, a function that waits for the pipeline run to complete can
|
470
|
+
be passed as part of the submission result.
|
469
471
|
|
470
472
|
Args:
|
471
|
-
deployment: The pipeline deployment to
|
473
|
+
deployment: The pipeline deployment to submit.
|
472
474
|
stack: The stack the pipeline will run on.
|
473
475
|
environment: Environment variables to set in the orchestration
|
474
|
-
environment.
|
476
|
+
environment. These don't need to be set if running locally.
|
475
477
|
placeholder_run: An optional placeholder run for the deployment.
|
476
478
|
|
477
479
|
Raises:
|
478
480
|
RuntimeError: If you try to run the pipelines in a notebook
|
479
481
|
environment.
|
482
|
+
|
483
|
+
Returns:
|
484
|
+
Optional submission result.
|
480
485
|
"""
|
481
486
|
# First check whether the code running in a notebook
|
482
487
|
if Environment.in_notebook():
|
@@ -640,7 +645,7 @@ class TektonOrchestrator(ContainerizedOrchestrator):
|
|
640
645
|
|
641
646
|
# using the kfp client uploads the pipeline to Tekton pipelines and
|
642
647
|
# runs it there
|
643
|
-
self._upload_and_run_pipeline(
|
648
|
+
return self._upload_and_run_pipeline(
|
644
649
|
deployment=deployment,
|
645
650
|
pipeline_file_path=pipeline_file_path,
|
646
651
|
run_name=orchestrator_run_name,
|
@@ -651,7 +656,7 @@ class TektonOrchestrator(ContainerizedOrchestrator):
|
|
651
656
|
deployment: "PipelineDeploymentResponse",
|
652
657
|
pipeline_file_path: str,
|
653
658
|
run_name: str,
|
654
|
-
) ->
|
659
|
+
) -> Optional[SubmissionResult]:
|
655
660
|
"""Tries to upload and run a KFP pipeline.
|
656
661
|
|
657
662
|
Args:
|
@@ -661,6 +666,9 @@ class TektonOrchestrator(ContainerizedOrchestrator):
|
|
661
666
|
|
662
667
|
Raises:
|
663
668
|
RuntimeError: If Tekton API returns an error.
|
669
|
+
|
670
|
+
Returns:
|
671
|
+
Optional submission result.
|
664
672
|
"""
|
665
673
|
pipeline_name = deployment.pipeline_configuration.name
|
666
674
|
settings = cast(
|
@@ -756,8 +764,14 @@ class TektonOrchestrator(ContainerizedOrchestrator):
|
|
756
764
|
)
|
757
765
|
|
758
766
|
if settings.synchronous:
|
759
|
-
|
760
|
-
|
767
|
+
|
768
|
+
def _wait_for_completion() -> None:
|
769
|
+
client.wait_for_run_completion(
|
770
|
+
run_id=result.run_id, timeout=settings.timeout
|
771
|
+
)
|
772
|
+
|
773
|
+
return SubmissionResult(
|
774
|
+
wait_for_completion=_wait_for_completion
|
761
775
|
)
|
762
776
|
except urllib3.exceptions.HTTPError as error:
|
763
777
|
if kubernetes_context:
|
@@ -779,6 +793,8 @@ class TektonOrchestrator(ContainerizedOrchestrator):
|
|
779
793
|
f"Failed to upload Tekton pipeline: {error}. {msg}",
|
780
794
|
)
|
781
795
|
|
796
|
+
return None
|
797
|
+
|
782
798
|
def get_orchestrator_run_id(self) -> str:
|
783
799
|
"""Returns the active orchestrator run id.
|
784
800
|
|
zenml/models/v2/core/step_run.py
CHANGED
@@ -129,6 +129,7 @@ class StepRunRequest(ProjectScopedRequest):
|
|
129
129
|
parent_step_ids: List[UUID] = Field(
|
130
130
|
title="The IDs of the parent steps of this step run.",
|
131
131
|
default_factory=list,
|
132
|
+
deprecated=True,
|
132
133
|
)
|
133
134
|
inputs: Dict[str, List[UUID]] = Field(
|
134
135
|
title="The IDs of the input artifact versions of the step run.",
|
zenml/orchestrators/__init__.py
CHANGED
@@ -26,6 +26,7 @@ from zenml.orchestrators.base_orchestrator import (
|
|
26
26
|
BaseOrchestrator,
|
27
27
|
BaseOrchestratorConfig,
|
28
28
|
BaseOrchestratorFlavor,
|
29
|
+
SubmissionResult,
|
29
30
|
)
|
30
31
|
from zenml.orchestrators.containerized_orchestrator import (
|
31
32
|
ContainerizedOrchestrator,
|
@@ -52,4 +53,5 @@ __all__ = [
|
|
52
53
|
"LocalOrchestratorFlavor",
|
53
54
|
"LocalDockerOrchestrator",
|
54
55
|
"LocalDockerOrchestratorFlavor",
|
56
|
+
"SubmissionResult",
|
55
57
|
]
|