zenml-nightly 0.58.2.dev20240626__py3-none-any.whl → 0.61.0.dev20240710__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.
- README.md +30 -9
- RELEASE_NOTES.md +240 -0
- zenml/VERSION +1 -1
- zenml/analytics/enums.py +3 -0
- zenml/cli/__init__.py +28 -0
- zenml/cli/artifact.py +1 -2
- zenml/cli/integration.py +9 -8
- zenml/cli/server.py +6 -0
- zenml/cli/stack.py +797 -39
- zenml/cli/stack_components.py +7 -0
- zenml/cli/text_utils.py +35 -1
- zenml/cli/utils.py +127 -10
- zenml/client.py +23 -14
- zenml/config/docker_settings.py +8 -5
- zenml/constants.py +5 -1
- zenml/container_registries/base_container_registry.py +1 -0
- zenml/enums.py +6 -0
- zenml/event_hub/event_hub.py +5 -8
- zenml/integrations/aws/__init__.py +1 -0
- zenml/integrations/azure/__init__.py +1 -0
- zenml/integrations/deepchecks/__init__.py +1 -0
- zenml/integrations/discord/__init__.py +1 -0
- zenml/integrations/evidently/__init__.py +1 -0
- zenml/integrations/facets/__init__.py +1 -0
- zenml/integrations/feast/__init__.py +1 -0
- zenml/integrations/gcp/__init__.py +3 -1
- zenml/integrations/gcp/google_credentials_mixin.py +1 -1
- zenml/integrations/gcp/service_connectors/gcp_service_connector.py +266 -58
- zenml/integrations/huggingface/__init__.py +1 -0
- zenml/integrations/integration.py +24 -0
- zenml/integrations/kubeflow/__init__.py +3 -0
- zenml/integrations/kubeflow/flavors/kubeflow_orchestrator_flavor.py +1 -1
- zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +0 -1
- zenml/integrations/kubernetes/__init__.py +3 -1
- zenml/integrations/kubernetes/orchestrators/kube_utils.py +4 -1
- zenml/integrations/label_studio/annotators/label_studio_annotator.py +1 -0
- zenml/integrations/langchain/__init__.py +1 -0
- zenml/integrations/mlflow/__init__.py +3 -1
- zenml/integrations/neural_prophet/__init__.py +1 -0
- zenml/integrations/polars/__init__.py +1 -0
- zenml/integrations/prodigy/__init__.py +1 -0
- zenml/integrations/pycaret/__init__.py +6 -0
- zenml/integrations/registry.py +37 -0
- zenml/integrations/s3/artifact_stores/s3_artifact_store.py +17 -6
- zenml/integrations/seldon/__init__.py +1 -0
- zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -0
- zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +2 -2
- zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +1 -1
- zenml/integrations/skypilot/orchestrators/skypilot_orchestrator_entrypoint.py +2 -2
- zenml/integrations/skypilot_aws/__init__.py +2 -1
- zenml/integrations/skypilot_azure/__init__.py +1 -1
- zenml/integrations/skypilot_gcp/__init__.py +1 -1
- zenml/integrations/skypilot_lambda/__init__.py +1 -1
- zenml/integrations/skypilot_lambda/flavors/skypilot_orchestrator_lambda_vm_flavor.py +1 -1
- zenml/integrations/slack/__init__.py +1 -0
- zenml/integrations/tekton/__init__.py +1 -0
- zenml/integrations/tensorboard/__init__.py +0 -1
- zenml/integrations/tensorflow/__init__.py +18 -6
- zenml/integrations/wandb/__init__.py +1 -0
- zenml/models/__init__.py +9 -0
- zenml/models/v2/core/component.py +18 -0
- zenml/models/v2/core/model.py +1 -2
- zenml/models/v2/core/service_connector.py +17 -0
- zenml/models/v2/core/stack.py +31 -0
- zenml/models/v2/misc/full_stack.py +97 -0
- zenml/models/v2/misc/stack_deployment.py +66 -0
- zenml/new/pipelines/pipeline.py +1 -1
- zenml/orchestrators/input_utils.py +3 -6
- zenml/stack/stack.py +3 -6
- zenml/stack_deployments/__init__.py +14 -0
- zenml/stack_deployments/aws_stack_deployment.py +289 -0
- zenml/stack_deployments/stack_deployment.py +130 -0
- zenml/stack_deployments/utils.py +40 -0
- zenml/utils/function_utils.py +1 -1
- zenml/utils/pagination_utils.py +7 -5
- zenml/utils/pipeline_docker_image_builder.py +97 -68
- zenml/utils/pydantic_utils.py +6 -5
- zenml/zen_server/cloud_utils.py +18 -3
- zenml/zen_server/dashboard/assets/{404-CDPQCl4D.js → 404-DpJaNHKF.js} +1 -1
- zenml/zen_server/dashboard/assets/@radix-CFOkMR_E.js +85 -0
- zenml/zen_server/dashboard/assets/{@react-router-DYovave8.js → @react-router-CO-OsFwI.js} +2 -2
- zenml/zen_server/dashboard/assets/{@reactflow-CHBapDaj.js → @reactflow-DJfzkHO1.js} +2 -2
- zenml/zen_server/dashboard/assets/@tanstack-DYiOyJUL.js +22 -0
- zenml/zen_server/dashboard/assets/AwarenessChannel-BYDLT2xC.js +1 -0
- zenml/zen_server/dashboard/assets/{CodeSnippet-BidtnWOi.js → CodeSnippet-BkOuRmyq.js} +2 -2
- zenml/zen_server/dashboard/assets/Commands-ZvWR1BRs.js +1 -0
- zenml/zen_server/dashboard/assets/CopyButton-DVwLkafa.js +2 -0
- zenml/zen_server/dashboard/assets/{CsvVizualization-BOuez-fG.js → CsvVizualization-C2IiqX4I.js} +7 -7
- zenml/zen_server/dashboard/assets/DisplayDate-DYgIjlDF.js +1 -0
- zenml/zen_server/dashboard/assets/EmptyState-BMLnFVlB.js +1 -0
- zenml/zen_server/dashboard/assets/Error-CqX0VqW_.js +1 -0
- zenml/zen_server/dashboard/assets/ExecutionStatus-BoLUXR9t.js +1 -0
- zenml/zen_server/dashboard/assets/Helpbox-LFydyVwh.js +1 -0
- zenml/zen_server/dashboard/assets/Infobox-DnENC0sh.js +1 -0
- zenml/zen_server/dashboard/assets/InlineAvatar-CbJtYr0t.js +1 -0
- zenml/zen_server/dashboard/assets/{MarkdownVisualization-DsB2QZiK.js → MarkdownVisualization-xp3hhULl.js} +2 -2
- zenml/zen_server/dashboard/assets/Pagination-DEbVUupy.js +1 -0
- zenml/zen_server/dashboard/assets/PasswordChecker-DUveqlva.js +1 -0
- zenml/zen_server/dashboard/assets/SetPassword-BYBdbQDo.js +1 -0
- zenml/zen_server/dashboard/assets/SuccessStep-Nx743hll.js +1 -0
- zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DnM-c11H.js → UpdatePasswordSchemas-DF9gSzE0.js} +1 -1
- zenml/zen_server/dashboard/assets/{aws-t0gKCj_R.js → aws-BgKTfTfx.js} +1 -1
- zenml/zen_server/dashboard/assets/{check-circle-BVvhm5dy.js → check-circle-i56092KI.js} +1 -1
- zenml/zen_server/dashboard/assets/{chevron-down-zcvCWmyP.js → chevron-down-D_ZlKMqH.js} +1 -1
- zenml/zen_server/dashboard/assets/{chevron-right-double-CJ50E9Gr.js → chevron-right-double-BiEMg7rd.js} +1 -1
- zenml/zen_server/dashboard/assets/cloud-only-DVbIeckv.js +1 -0
- zenml/zen_server/dashboard/assets/{copy-BRhQz3j-.js → copy-BXNk6BjL.js} +1 -1
- zenml/zen_server/dashboard/assets/{database-CRRnyFWh.js → database-1xWSgZfO.js} +1 -1
- zenml/zen_server/dashboard/assets/{docker-BAonhm6G.js → docker-CQMVm_4d.js} +1 -1
- zenml/zen_server/dashboard/assets/{file-text-CbVERUON.js → file-text-CqD_iu6l.js} +1 -1
- zenml/zen_server/dashboard/assets/{help-B8rqCvqn.js → help-bu_DgLKI.js} +1 -1
- zenml/zen_server/dashboard/assets/index-C_CrU4vI.js +1 -0
- zenml/zen_server/dashboard/assets/index-DK1ynKjA.js +55 -0
- zenml/zen_server/dashboard/assets/index-inApY3KQ.css +1 -0
- zenml/zen_server/dashboard/assets/index-rK_Wuy2W.js +1 -0
- zenml/zen_server/dashboard/assets/index.esm-Corw4lXQ.js +1 -0
- zenml/zen_server/dashboard/assets/{login-mutation-wzzl23C6.js → login-mutation-BUnVASxp.js} +1 -1
- zenml/zen_server/dashboard/assets/not-found-B4VnX8gK.js +1 -0
- zenml/zen_server/dashboard/assets/package-CsUhPmou.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BmkSiYeQ.js → page-3efNCDeb.js} +2 -2
- zenml/zen_server/dashboard/assets/page-7zTHbhhI.js +1 -0
- zenml/zen_server/dashboard/assets/page-BEs6jK71.js +1 -0
- zenml/zen_server/dashboard/assets/page-BpSqIf4B.js +1 -0
- zenml/zen_server/dashboard/assets/{page-AQKopn_4.js → page-Bx6o0ARS.js} +1 -1
- zenml/zen_server/dashboard/assets/page-C43QGHTt.js +9 -0
- zenml/zen_server/dashboard/assets/page-CR0OG7ss.js +1 -0
- zenml/zen_server/dashboard/assets/page-CRTJ0UuR.js +1 -0
- zenml/zen_server/dashboard/assets/page-CUZIGO-3.js +1 -0
- zenml/zen_server/dashboard/assets/page-CaopxiU1.js +1 -0
- zenml/zen_server/dashboard/assets/{page-CuT1SUik.js → page-Cx67M0QT.js} +1 -1
- zenml/zen_server/dashboard/assets/page-D7Z399xy.js +1 -0
- zenml/zen_server/dashboard/assets/page-D93kd7Xj.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BzVZGExK.js → page-DKlIdAe5.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-Bi5AI0S7.js → page-DMOYZppS.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DMsSn3dv.js +2 -0
- zenml/zen_server/dashboard/assets/{page-BW6Ket3a.js → page-Dc_7KMQE.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DvCvroOM.js +1 -0
- zenml/zen_server/dashboard/assets/page-Hus2pr9T.js +1 -0
- zenml/zen_server/dashboard/assets/page-JyfeDUfu.js +1 -0
- zenml/zen_server/dashboard/assets/{page-yN4rZ-ZS.js → page-Sxn82W-5.js} +1 -1
- zenml/zen_server/dashboard/assets/page-TKXERe16.js +1 -0
- zenml/zen_server/dashboard/assets/page-Xu8JEjSU.js +1 -0
- zenml/zen_server/dashboard/assets/{play-circle-DK5QMJyp.js → play-circle-CNtZKDnW.js} +1 -1
- zenml/zen_server/dashboard/assets/plus-DOeLmm7C.js +1 -0
- zenml/zen_server/dashboard/assets/{terminal-B2ovgWuz.js → terminal-By9cErXc.js} +1 -1
- zenml/zen_server/dashboard/assets/{update-server-settings-mutation-0Wgz8pUE.js → update-server-settings-mutation-CR8e3Sir.js} +1 -1
- zenml/zen_server/dashboard/assets/{url-6_xv0WJS.js → url-DuQMeqYA.js} +1 -1
- zenml/zen_server/dashboard/assets/{zod-DrZvVLjd.js → zod-BhoGpZ63.js} +1 -1
- zenml/zen_server/dashboard/index.html +7 -7
- zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
- zenml/zen_server/dashboard_legacy/index.html +1 -1
- zenml/zen_server/dashboard_legacy/{precache-manifest.f4abc5b7cfa7d90c1caf5521918e29a8.js → precache-manifest.c8c57fb0d2132b1d3c2119e776b7dfb3.js} +4 -4
- zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
- zenml/zen_server/dashboard_legacy/static/js/{main.ac2f17d0.chunk.js → main.382439a7.chunk.js} +2 -2
- zenml/zen_server/dashboard_legacy/static/js/{main.ac2f17d0.chunk.js.map → main.382439a7.chunk.js.map} +1 -1
- zenml/zen_server/deploy/helm/Chart.yaml +1 -1
- zenml/zen_server/deploy/helm/README.md +2 -2
- zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +11 -5
- zenml/zen_server/pipeline_deployment/utils.py +57 -44
- zenml/zen_server/rbac/zenml_cloud_rbac.py +11 -5
- zenml/zen_server/routers/stack_deployment_endpoints.py +144 -0
- zenml/zen_server/routers/workspaces_endpoints.py +64 -0
- zenml/zen_server/zen_server_api.py +2 -0
- zenml/zen_stores/migrations/utils.py +1 -1
- zenml/zen_stores/migrations/versions/0.60.0_release.py +23 -0
- zenml/zen_stores/migrations/versions/0.61.0_release.py +23 -0
- zenml/zen_stores/migrations/versions/0d707865f404_adding_labels_to_stacks.py +30 -0
- zenml/zen_stores/rest_zen_store.py +117 -0
- zenml/zen_stores/schemas/stack_schemas.py +10 -0
- zenml/zen_stores/schemas/step_run_schemas.py +27 -11
- zenml/zen_stores/sql_zen_store.py +283 -0
- zenml/zen_stores/zen_store_interface.py +79 -0
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/METADATA +32 -10
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/RECORD +177 -162
- zenml/zen_server/dashboard/assets/@radix-C9DBgJhe.js +0 -77
- zenml/zen_server/dashboard/assets/@tanstack-CEbkxrhX.js +0 -30
- zenml/zen_server/dashboard/assets/AwarenessChannel-nXGpmj_f.js +0 -1
- zenml/zen_server/dashboard/assets/Cards-nwsvQLVS.js +0 -1
- zenml/zen_server/dashboard/assets/Commands-DuIWKg_Q.js +0 -1
- zenml/zen_server/dashboard/assets/CopyButton-B_YSm-Ds.js +0 -2
- zenml/zen_server/dashboard/assets/DisplayDate-BdguISQF.js +0 -1
- zenml/zen_server/dashboard/assets/EmptyState-BkooiGtL.js +0 -1
- zenml/zen_server/dashboard/assets/Error-B6M0dPph.js +0 -1
- zenml/zen_server/dashboard/assets/Helpbox-BQoqCm04.js +0 -1
- zenml/zen_server/dashboard/assets/Infobox-Ce9mefqU.js +0 -1
- zenml/zen_server/dashboard/assets/InlineAvatar-DGf3dVhV.js +0 -1
- zenml/zen_server/dashboard/assets/PageHeader-DGaemzjc.js +0 -1
- zenml/zen_server/dashboard/assets/Pagination-DVYfBCCc.js +0 -1
- zenml/zen_server/dashboard/assets/PasswordChecker-DSLBp7Vl.js +0 -1
- zenml/zen_server/dashboard/assets/SetPassword-B5s7DJug.js +0 -1
- zenml/zen_server/dashboard/assets/SuccessStep-ZzczaM7g.js +0 -1
- zenml/zen_server/dashboard/assets/cloud-only-Ba_ShBR5.js +0 -1
- zenml/zen_server/dashboard/assets/index-CWJ3xbIf.css +0 -1
- zenml/zen_server/dashboard/assets/index-QORVVTMN.js +0 -55
- zenml/zen_server/dashboard/assets/index.esm-F7nqy9zY.js +0 -1
- zenml/zen_server/dashboard/assets/not-found-Dh2la7kh.js +0 -1
- zenml/zen_server/dashboard/assets/page-B-5jAKoO.js +0 -1
- zenml/zen_server/dashboard/assets/page-B-vWk8a6.js +0 -1
- zenml/zen_server/dashboard/assets/page-B0BrqfS8.js +0 -1
- zenml/zen_server/dashboard/assets/page-BQxVFlUl.js +0 -1
- zenml/zen_server/dashboard/assets/page-ByrHy6Ss.js +0 -1
- zenml/zen_server/dashboard/assets/page-CPtY4Kv_.js +0 -1
- zenml/zen_server/dashboard/assets/page-CmmukLsl.js +0 -1
- zenml/zen_server/dashboard/assets/page-D2D-7qyr.js +0 -9
- zenml/zen_server/dashboard/assets/page-DAQQyLxT.js +0 -1
- zenml/zen_server/dashboard/assets/page-DHkUMl_E.js +0 -1
- zenml/zen_server/dashboard/assets/page-DZCbwOEs.js +0 -2
- zenml/zen_server/dashboard/assets/page-DdaIt20-.js +0 -1
- zenml/zen_server/dashboard/assets/page-LqLs24Ot.js +0 -1
- zenml/zen_server/dashboard/assets/page-lebv0c7C.js +0 -1
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/entry_points.txt +0 -0
@@ -15,6 +15,7 @@
|
|
15
15
|
|
16
16
|
import os
|
17
17
|
import re
|
18
|
+
from datetime import datetime
|
18
19
|
from pathlib import Path
|
19
20
|
from typing import (
|
20
21
|
Any,
|
@@ -65,6 +66,7 @@ from zenml.constants import (
|
|
65
66
|
ENV_ZENML_DISABLE_CLIENT_SERVER_MISMATCH_WARNING,
|
66
67
|
EVENT_SOURCES,
|
67
68
|
FLAVORS,
|
69
|
+
FULL_STACK,
|
68
70
|
GET_OR_CREATE,
|
69
71
|
INFO,
|
70
72
|
LOGIN,
|
@@ -91,18 +93,22 @@ from zenml.constants import (
|
|
91
93
|
SERVICE_CONNECTOR_VERIFY,
|
92
94
|
SERVICE_CONNECTORS,
|
93
95
|
SERVICES,
|
96
|
+
STACK,
|
94
97
|
STACK_COMPONENTS,
|
98
|
+
STACK_DEPLOYMENT,
|
95
99
|
STACKS,
|
96
100
|
STEPS,
|
97
101
|
TAGS,
|
98
102
|
TRIGGER_EXECUTIONS,
|
99
103
|
TRIGGERS,
|
104
|
+
URL,
|
100
105
|
USERS,
|
101
106
|
VERSION_1,
|
102
107
|
WORKSPACES,
|
103
108
|
)
|
104
109
|
from zenml.enums import (
|
105
110
|
OAuthGrantTypes,
|
111
|
+
StackDeploymentProvider,
|
106
112
|
StoreType,
|
107
113
|
)
|
108
114
|
from zenml.exceptions import AuthorizationException, MethodNotAllowedError
|
@@ -139,6 +145,7 @@ from zenml.models import (
|
|
139
145
|
ComponentRequest,
|
140
146
|
ComponentResponse,
|
141
147
|
ComponentUpdate,
|
148
|
+
DeployedStack,
|
142
149
|
EventSourceFilter,
|
143
150
|
EventSourceRequest,
|
144
151
|
EventSourceResponse,
|
@@ -147,6 +154,7 @@ from zenml.models import (
|
|
147
154
|
FlavorRequest,
|
148
155
|
FlavorResponse,
|
149
156
|
FlavorUpdate,
|
157
|
+
FullStackRequest,
|
150
158
|
LogsResponse,
|
151
159
|
ModelFilter,
|
152
160
|
ModelRequest,
|
@@ -208,6 +216,7 @@ from zenml.models import (
|
|
208
216
|
ServiceRequest,
|
209
217
|
ServiceResponse,
|
210
218
|
ServiceUpdate,
|
219
|
+
StackDeploymentInfo,
|
211
220
|
StackFilter,
|
212
221
|
StackRequest,
|
213
222
|
StackResponse,
|
@@ -2744,6 +2753,23 @@ class RestZenStore(BaseZenStore):
|
|
2744
2753
|
response_model=StackResponse,
|
2745
2754
|
)
|
2746
2755
|
|
2756
|
+
def create_full_stack(self, full_stack: FullStackRequest) -> StackResponse:
|
2757
|
+
"""Register a full-stack.
|
2758
|
+
|
2759
|
+
Args:
|
2760
|
+
full_stack: The full stack configuration.
|
2761
|
+
|
2762
|
+
Returns:
|
2763
|
+
The registered stack.
|
2764
|
+
"""
|
2765
|
+
assert full_stack.workspace is not None
|
2766
|
+
|
2767
|
+
return self._create_resource(
|
2768
|
+
resource=full_stack,
|
2769
|
+
response_model=StackResponse,
|
2770
|
+
route=f"{WORKSPACES}/{str(full_stack.workspace)}{FULL_STACK}",
|
2771
|
+
)
|
2772
|
+
|
2747
2773
|
def get_stack(self, stack_id: UUID, hydrate: bool = True) -> StackResponse:
|
2748
2774
|
"""Get a stack by its unique ID.
|
2749
2775
|
|
@@ -2813,6 +2839,97 @@ class RestZenStore(BaseZenStore):
|
|
2813
2839
|
route=STACKS,
|
2814
2840
|
)
|
2815
2841
|
|
2842
|
+
# ---------------- Stack deployments-----------------
|
2843
|
+
|
2844
|
+
def get_stack_deployment_info(
|
2845
|
+
self,
|
2846
|
+
provider: StackDeploymentProvider,
|
2847
|
+
) -> StackDeploymentInfo:
|
2848
|
+
"""Get information about a stack deployment provider.
|
2849
|
+
|
2850
|
+
Args:
|
2851
|
+
provider: The stack deployment provider.
|
2852
|
+
|
2853
|
+
Returns:
|
2854
|
+
Information about the stack deployment provider.
|
2855
|
+
"""
|
2856
|
+
body = self.get(
|
2857
|
+
f"{STACK_DEPLOYMENT}{INFO}",
|
2858
|
+
params={"provider": provider.value},
|
2859
|
+
)
|
2860
|
+
return StackDeploymentInfo.model_validate(body)
|
2861
|
+
|
2862
|
+
def get_stack_deployment_url(
|
2863
|
+
self,
|
2864
|
+
provider: StackDeploymentProvider,
|
2865
|
+
stack_name: str,
|
2866
|
+
location: Optional[str] = None,
|
2867
|
+
) -> Tuple[str, str]:
|
2868
|
+
"""Return the URL to deploy the ZenML stack to the specified cloud provider.
|
2869
|
+
|
2870
|
+
Args:
|
2871
|
+
provider: The stack deployment provider.
|
2872
|
+
stack_name: The name of the stack.
|
2873
|
+
location: The location where the stack should be deployed.
|
2874
|
+
|
2875
|
+
Returns:
|
2876
|
+
The URL to deploy the ZenML stack to the specified cloud provider
|
2877
|
+
and a text description of the URL.
|
2878
|
+
|
2879
|
+
Raises:
|
2880
|
+
ValueError: If the response body is not as expected.
|
2881
|
+
"""
|
2882
|
+
params = {
|
2883
|
+
"provider": provider.value,
|
2884
|
+
"stack_name": stack_name,
|
2885
|
+
}
|
2886
|
+
if location:
|
2887
|
+
params["location"] = location
|
2888
|
+
body = self.get(f"{STACK_DEPLOYMENT}{URL}", params=params)
|
2889
|
+
|
2890
|
+
if not isinstance(body, list) or len(body) != 2:
|
2891
|
+
raise ValueError(
|
2892
|
+
"Bad response body received from the stack deployment URL "
|
2893
|
+
"endpoint."
|
2894
|
+
)
|
2895
|
+
return body[0], body[1]
|
2896
|
+
|
2897
|
+
def get_stack_deployment_stack(
|
2898
|
+
self,
|
2899
|
+
provider: StackDeploymentProvider,
|
2900
|
+
stack_name: str,
|
2901
|
+
location: Optional[str] = None,
|
2902
|
+
date_start: Optional[datetime] = None,
|
2903
|
+
) -> Optional[DeployedStack]:
|
2904
|
+
"""Return a matching ZenML stack that was deployed and registered.
|
2905
|
+
|
2906
|
+
Args:
|
2907
|
+
provider: The stack deployment provider.
|
2908
|
+
stack_name: The name of the stack.
|
2909
|
+
location: The location where the stack should be deployed.
|
2910
|
+
date_start: The date when the deployment started.
|
2911
|
+
|
2912
|
+
Returns:
|
2913
|
+
The ZenML stack that was deployed and registered or None if the
|
2914
|
+
stack was not found.
|
2915
|
+
"""
|
2916
|
+
params = {
|
2917
|
+
"provider": provider.value,
|
2918
|
+
"stack_name": stack_name,
|
2919
|
+
}
|
2920
|
+
if location:
|
2921
|
+
params["location"] = location
|
2922
|
+
if date_start:
|
2923
|
+
params["date_start"] = str(date_start)
|
2924
|
+
body = self.get(
|
2925
|
+
f"{STACK_DEPLOYMENT}{STACK}",
|
2926
|
+
params=params,
|
2927
|
+
)
|
2928
|
+
if body:
|
2929
|
+
return DeployedStack.model_validate(body)
|
2930
|
+
|
2931
|
+
return None
|
2932
|
+
|
2816
2933
|
# ----------------------------- Step runs -----------------------------
|
2817
2934
|
|
2818
2935
|
def create_run_step(self, step_run: StepRunRequest) -> StepRunResponse:
|
@@ -13,6 +13,8 @@
|
|
13
13
|
# permissions and limitations under the License.
|
14
14
|
"""SQL Model Implementations for Stacks."""
|
15
15
|
|
16
|
+
import base64
|
17
|
+
import json
|
16
18
|
from datetime import datetime
|
17
19
|
from typing import TYPE_CHECKING, Any, List, Optional
|
18
20
|
from uuid import UUID
|
@@ -75,6 +77,7 @@ class StackSchema(NamedSchema, table=True):
|
|
75
77
|
|
76
78
|
__tablename__ = "stack"
|
77
79
|
stack_spec_path: Optional[str]
|
80
|
+
labels: Optional[bytes]
|
78
81
|
|
79
82
|
workspace_id: UUID = build_foreign_key_field(
|
80
83
|
source=__tablename__,
|
@@ -124,6 +127,10 @@ class StackSchema(NamedSchema, table=True):
|
|
124
127
|
).items():
|
125
128
|
if field == "components":
|
126
129
|
self.components = components
|
130
|
+
elif field == "labels":
|
131
|
+
self.labels = base64.b64encode(
|
132
|
+
json.dumps(stack_update.labels).encode("utf-8")
|
133
|
+
)
|
127
134
|
else:
|
128
135
|
setattr(self, field, value)
|
129
136
|
|
@@ -158,6 +165,9 @@ class StackSchema(NamedSchema, table=True):
|
|
158
165
|
workspace=self.workspace.to_model(),
|
159
166
|
components={c.type: [c.to_model()] for c in self.components},
|
160
167
|
stack_spec_path=self.stack_spec_path,
|
168
|
+
labels=json.loads(base64.b64decode(self.labels).decode())
|
169
|
+
if self.labels
|
170
|
+
else None,
|
161
171
|
)
|
162
172
|
|
163
173
|
return StackResponse(
|
@@ -192,6 +192,7 @@ class StepRunSchema(NamedSchema, table=True):
|
|
192
192
|
The created StepRunResponse.
|
193
193
|
|
194
194
|
Raises:
|
195
|
+
ValueError: In case the step run configuration can not be loaded.
|
195
196
|
RuntimeError: If the step run schema does not have a deployment_id
|
196
197
|
or a step_configuration.
|
197
198
|
"""
|
@@ -212,19 +213,34 @@ class StepRunSchema(NamedSchema, table=True):
|
|
212
213
|
for artifact in self.output_artifacts
|
213
214
|
}
|
214
215
|
|
216
|
+
full_step_config = None
|
215
217
|
if self.deployment is not None:
|
216
|
-
|
217
|
-
|
218
|
-
)
|
219
|
-
elif self.step_configuration is not None:
|
220
|
-
full_step_config = Step.model_validate_json(
|
221
|
-
self.step_configuration
|
222
|
-
)
|
223
|
-
else:
|
224
|
-
raise RuntimeError(
|
225
|
-
"Step run model creation has failed. Each step run entry "
|
226
|
-
"should either have a deployment_id or step_configuration."
|
218
|
+
step_configuration = json.loads(
|
219
|
+
self.deployment.step_configurations
|
227
220
|
)
|
221
|
+
if self.name in step_configuration:
|
222
|
+
full_step_config = Step.model_validate(
|
223
|
+
step_configuration[self.name]
|
224
|
+
)
|
225
|
+
elif not self.step_configuration:
|
226
|
+
raise ValueError(
|
227
|
+
f"Unable to load the configuration for step `{self.name}` from the"
|
228
|
+
f"database. To solve this please delete the pipeline run that this"
|
229
|
+
f"step run belongs to. Pipeline Run ID: `{self.pipeline_run_id}`."
|
230
|
+
)
|
231
|
+
|
232
|
+
# the step configuration moved into the deployment - the following case is to ensure
|
233
|
+
# backwards compatibility
|
234
|
+
if full_step_config is None:
|
235
|
+
if self.step_configuration:
|
236
|
+
full_step_config = Step.model_validate_json(
|
237
|
+
self.step_configuration
|
238
|
+
)
|
239
|
+
else:
|
240
|
+
raise RuntimeError(
|
241
|
+
"Step run model creation has failed. Each step run entry "
|
242
|
+
"should either have a deployment_id or step_configuration."
|
243
|
+
)
|
228
244
|
|
229
245
|
body = StepRunResponseBody(
|
230
246
|
user=self.user.to_model() if self.user else None,
|
@@ -111,6 +111,7 @@ from zenml.enums import (
|
|
111
111
|
SecretsStoreType,
|
112
112
|
SorterOps,
|
113
113
|
StackComponentType,
|
114
|
+
StackDeploymentProvider,
|
114
115
|
StepRunInputArtifactType,
|
115
116
|
StepRunOutputArtifactType,
|
116
117
|
StoreType,
|
@@ -164,6 +165,7 @@ from zenml.models import (
|
|
164
165
|
ComponentRequest,
|
165
166
|
ComponentResponse,
|
166
167
|
ComponentUpdate,
|
168
|
+
DeployedStack,
|
167
169
|
EventSourceFilter,
|
168
170
|
EventSourceRequest,
|
169
171
|
EventSourceResponse,
|
@@ -172,6 +174,7 @@ from zenml.models import (
|
|
172
174
|
FlavorRequest,
|
173
175
|
FlavorResponse,
|
174
176
|
FlavorUpdate,
|
177
|
+
FullStackRequest,
|
175
178
|
LogsResponse,
|
176
179
|
ModelFilter,
|
177
180
|
ModelRequest,
|
@@ -242,6 +245,7 @@ from zenml.models import (
|
|
242
245
|
ServiceRequest,
|
243
246
|
ServiceResponse,
|
244
247
|
ServiceUpdate,
|
248
|
+
StackDeploymentInfo,
|
245
249
|
StackFilter,
|
246
250
|
StackRequest,
|
247
251
|
StackResponse,
|
@@ -6911,6 +6915,9 @@ class SqlZenStore(BaseZenStore):
|
|
6911
6915
|
name=stack.name,
|
6912
6916
|
description=stack.description,
|
6913
6917
|
components=defined_components,
|
6918
|
+
labels=base64.b64encode(
|
6919
|
+
json.dumps(stack.labels).encode("utf-8")
|
6920
|
+
),
|
6914
6921
|
)
|
6915
6922
|
|
6916
6923
|
session.add(new_stack_schema)
|
@@ -6919,6 +6926,219 @@ class SqlZenStore(BaseZenStore):
|
|
6919
6926
|
|
6920
6927
|
return new_stack_schema.to_model(include_metadata=True)
|
6921
6928
|
|
6929
|
+
def create_full_stack(self, full_stack: FullStackRequest) -> StackResponse:
|
6930
|
+
"""Register a full stack.
|
6931
|
+
|
6932
|
+
Args:
|
6933
|
+
full_stack: The full stack configuration.
|
6934
|
+
|
6935
|
+
Returns:
|
6936
|
+
The registered stack.
|
6937
|
+
|
6938
|
+
Raises:
|
6939
|
+
ValueError: If the full stack creation fails, due to the corrupted
|
6940
|
+
input.
|
6941
|
+
RuntimeError: If the full stack creation fails, due to unforeseen
|
6942
|
+
errors.
|
6943
|
+
"""
|
6944
|
+
# For clean-up purposes, each created entity is tracked here
|
6945
|
+
service_connectors_created_ids: List[UUID] = []
|
6946
|
+
components_created_ids: List[UUID] = []
|
6947
|
+
|
6948
|
+
try:
|
6949
|
+
# Validate the name of the new stack
|
6950
|
+
validate_name(full_stack)
|
6951
|
+
|
6952
|
+
if full_stack.labels is None:
|
6953
|
+
full_stack.labels = {}
|
6954
|
+
|
6955
|
+
full_stack.labels.update({"zenml:full_stack": True})
|
6956
|
+
|
6957
|
+
# Service Connectors
|
6958
|
+
service_connectors: List[ServiceConnectorResponse] = []
|
6959
|
+
|
6960
|
+
for connector_id_or_info in full_stack.service_connectors:
|
6961
|
+
# Fetch an existing service connector
|
6962
|
+
if isinstance(connector_id_or_info, UUID):
|
6963
|
+
service_connectors.append(
|
6964
|
+
self.get_service_connector(connector_id_or_info)
|
6965
|
+
)
|
6966
|
+
# Create a new service connector
|
6967
|
+
else:
|
6968
|
+
connector_name = full_stack.name
|
6969
|
+
while True:
|
6970
|
+
try:
|
6971
|
+
service_connector_request = ServiceConnectorRequest(
|
6972
|
+
name=connector_name,
|
6973
|
+
connector_type=connector_id_or_info.type,
|
6974
|
+
auth_method=connector_id_or_info.auth_method,
|
6975
|
+
configuration=connector_id_or_info.configuration,
|
6976
|
+
user=full_stack.user,
|
6977
|
+
workspace=full_stack.workspace,
|
6978
|
+
labels={
|
6979
|
+
k: str(v)
|
6980
|
+
for k, v in full_stack.labels.items()
|
6981
|
+
},
|
6982
|
+
)
|
6983
|
+
service_connector_response = (
|
6984
|
+
self.create_service_connector(
|
6985
|
+
service_connector=service_connector_request
|
6986
|
+
)
|
6987
|
+
)
|
6988
|
+
service_connectors.append(
|
6989
|
+
service_connector_response
|
6990
|
+
)
|
6991
|
+
service_connectors_created_ids.append(
|
6992
|
+
service_connector_response.id
|
6993
|
+
)
|
6994
|
+
break
|
6995
|
+
except EntityExistsError:
|
6996
|
+
connector_name = (
|
6997
|
+
f"{full_stack.name}-{random_str(4)}".lower()
|
6998
|
+
)
|
6999
|
+
continue
|
7000
|
+
|
7001
|
+
# Stack Components
|
7002
|
+
components_mapping: Dict[StackComponentType, List[UUID]] = {}
|
7003
|
+
|
7004
|
+
for (
|
7005
|
+
component_type,
|
7006
|
+
component_info,
|
7007
|
+
) in full_stack.components.items():
|
7008
|
+
# Fetch an existing component
|
7009
|
+
if isinstance(component_info, UUID):
|
7010
|
+
component = self.get_stack_component(
|
7011
|
+
component_id=component_info
|
7012
|
+
)
|
7013
|
+
# Create a new component
|
7014
|
+
else:
|
7015
|
+
component_name = full_stack.name
|
7016
|
+
while True:
|
7017
|
+
try:
|
7018
|
+
component_request = ComponentRequest(
|
7019
|
+
name=component_name,
|
7020
|
+
type=component_type,
|
7021
|
+
flavor=component_info.flavor,
|
7022
|
+
configuration=component_info.configuration,
|
7023
|
+
user=full_stack.user,
|
7024
|
+
workspace=full_stack.workspace,
|
7025
|
+
labels=full_stack.labels,
|
7026
|
+
)
|
7027
|
+
component = self.create_stack_component(
|
7028
|
+
component=component_request
|
7029
|
+
)
|
7030
|
+
components_created_ids.append(component.id)
|
7031
|
+
break
|
7032
|
+
except EntityExistsError:
|
7033
|
+
component_name = (
|
7034
|
+
f"{full_stack.name}-{random_str(4)}".lower()
|
7035
|
+
)
|
7036
|
+
continue
|
7037
|
+
|
7038
|
+
if component_info.service_connector_index is not None:
|
7039
|
+
service_connector = service_connectors[
|
7040
|
+
component_info.service_connector_index
|
7041
|
+
]
|
7042
|
+
flavor_list = self.list_flavors(
|
7043
|
+
flavor_filter_model=FlavorFilter(
|
7044
|
+
name=component_info.flavor,
|
7045
|
+
type=component_type,
|
7046
|
+
)
|
7047
|
+
)
|
7048
|
+
assert len(flavor_list) == 1
|
7049
|
+
|
7050
|
+
flavor_model = flavor_list[0]
|
7051
|
+
|
7052
|
+
requirements = flavor_model.connector_requirements
|
7053
|
+
|
7054
|
+
if not requirements:
|
7055
|
+
raise ValueError(
|
7056
|
+
f"The '{flavor_model.name}' implementation "
|
7057
|
+
"does not support using a service connector to "
|
7058
|
+
"connect to resources."
|
7059
|
+
)
|
7060
|
+
|
7061
|
+
if component_info.service_connector_resource_id:
|
7062
|
+
resource_id = (
|
7063
|
+
component_info.service_connector_resource_id
|
7064
|
+
)
|
7065
|
+
else:
|
7066
|
+
resource_id = None
|
7067
|
+
resource_type = requirements.resource_type
|
7068
|
+
if requirements.resource_id_attr is not None:
|
7069
|
+
resource_id = component_info.configuration.get(
|
7070
|
+
requirements.resource_id_attr
|
7071
|
+
)
|
7072
|
+
|
7073
|
+
satisfied, msg = requirements.is_satisfied_by(
|
7074
|
+
connector=service_connector,
|
7075
|
+
component=component,
|
7076
|
+
)
|
7077
|
+
|
7078
|
+
if not satisfied:
|
7079
|
+
raise ValueError(
|
7080
|
+
"Please pick a connector that is "
|
7081
|
+
"compatible with the component flavor and "
|
7082
|
+
"try again.."
|
7083
|
+
)
|
7084
|
+
|
7085
|
+
if not resource_id:
|
7086
|
+
if service_connector.resource_id:
|
7087
|
+
resource_id = service_connector.resource_id
|
7088
|
+
elif service_connector.supports_instances:
|
7089
|
+
raise ValueError(
|
7090
|
+
f"Multiple {resource_type} resources "
|
7091
|
+
"are available for the selected "
|
7092
|
+
"connector. Please use a `resource_id` "
|
7093
|
+
"to configure a "
|
7094
|
+
f"{resource_type} resource."
|
7095
|
+
)
|
7096
|
+
|
7097
|
+
component_update = ComponentUpdate(
|
7098
|
+
connector=service_connector.id,
|
7099
|
+
connector_resource_id=resource_id,
|
7100
|
+
)
|
7101
|
+
self.update_stack_component(
|
7102
|
+
component_id=component.id,
|
7103
|
+
component_update=component_update,
|
7104
|
+
)
|
7105
|
+
|
7106
|
+
components_mapping[component_type] = [
|
7107
|
+
component.id,
|
7108
|
+
]
|
7109
|
+
|
7110
|
+
# Stack
|
7111
|
+
stack_name = full_stack.name
|
7112
|
+
while True:
|
7113
|
+
try:
|
7114
|
+
stack_request = StackRequest(
|
7115
|
+
user=full_stack.user,
|
7116
|
+
workspace=full_stack.workspace,
|
7117
|
+
name=stack_name,
|
7118
|
+
description=full_stack.description,
|
7119
|
+
components=components_mapping,
|
7120
|
+
labels=full_stack.labels,
|
7121
|
+
)
|
7122
|
+
stack_response = self.create_stack(stack_request)
|
7123
|
+
|
7124
|
+
break
|
7125
|
+
except EntityExistsError:
|
7126
|
+
stack_name = f"{full_stack.name}-{random_str(4)}".lower()
|
7127
|
+
|
7128
|
+
return stack_response
|
7129
|
+
|
7130
|
+
except Exception as e:
|
7131
|
+
for component_id in components_created_ids:
|
7132
|
+
self.delete_stack_component(component_id=component_id)
|
7133
|
+
for service_connector_id in service_connectors_created_ids:
|
7134
|
+
self.delete_service_connector(
|
7135
|
+
service_connector_id=service_connector_id
|
7136
|
+
)
|
7137
|
+
raise RuntimeError(
|
7138
|
+
f"Full Stack creation has failed {e}. Cleaning up the "
|
7139
|
+
f"created entities."
|
7140
|
+
) from e
|
7141
|
+
|
6922
7142
|
def get_stack(self, stack_id: UUID, hydrate: bool = True) -> StackResponse:
|
6923
7143
|
"""Get a stack by its unique ID.
|
6924
7144
|
|
@@ -7195,6 +7415,69 @@ class SqlZenStore(BaseZenStore):
|
|
7195
7415
|
workspace_id=workspace.id,
|
7196
7416
|
)
|
7197
7417
|
|
7418
|
+
# ---------------- Stack deployments-----------------
|
7419
|
+
|
7420
|
+
def get_stack_deployment_info(
|
7421
|
+
self,
|
7422
|
+
provider: StackDeploymentProvider,
|
7423
|
+
) -> StackDeploymentInfo:
|
7424
|
+
"""Get information about a stack deployment provider.
|
7425
|
+
|
7426
|
+
Args:
|
7427
|
+
provider: The stack deployment provider.
|
7428
|
+
|
7429
|
+
Raises:
|
7430
|
+
NotImplementedError: Stack deployments are not supported by the
|
7431
|
+
local ZenML deployment.
|
7432
|
+
"""
|
7433
|
+
raise NotImplementedError(
|
7434
|
+
"Stack deployments are not supported by local ZenML deployments."
|
7435
|
+
)
|
7436
|
+
|
7437
|
+
def get_stack_deployment_url(
|
7438
|
+
self,
|
7439
|
+
provider: StackDeploymentProvider,
|
7440
|
+
stack_name: str,
|
7441
|
+
location: Optional[str] = None,
|
7442
|
+
) -> Tuple[str, str]:
|
7443
|
+
"""Return the URL to deploy the ZenML stack to the specified cloud provider.
|
7444
|
+
|
7445
|
+
Args:
|
7446
|
+
provider: The stack deployment provider.
|
7447
|
+
stack_name: The name of the stack.
|
7448
|
+
location: The location where the stack should be deployed.
|
7449
|
+
|
7450
|
+
Raises:
|
7451
|
+
NotImplementedError: Stack deployments are not supported by the
|
7452
|
+
local ZenML deployment.
|
7453
|
+
"""
|
7454
|
+
raise NotImplementedError(
|
7455
|
+
"Stack deployments are not supported by local ZenML deployments."
|
7456
|
+
)
|
7457
|
+
|
7458
|
+
def get_stack_deployment_stack(
|
7459
|
+
self,
|
7460
|
+
provider: StackDeploymentProvider,
|
7461
|
+
stack_name: str,
|
7462
|
+
location: Optional[str] = None,
|
7463
|
+
date_start: Optional[datetime] = None,
|
7464
|
+
) -> Optional[DeployedStack]:
|
7465
|
+
"""Return a matching ZenML stack that was deployed and registered.
|
7466
|
+
|
7467
|
+
Args:
|
7468
|
+
provider: The stack deployment provider.
|
7469
|
+
stack_name: The name of the stack.
|
7470
|
+
location: The location where the stack should be deployed.
|
7471
|
+
date_start: The date when the deployment started.
|
7472
|
+
|
7473
|
+
Raises:
|
7474
|
+
NotImplementedError: Stack deployments are not supported by the
|
7475
|
+
local ZenML deployment.
|
7476
|
+
"""
|
7477
|
+
raise NotImplementedError(
|
7478
|
+
"Stack deployments are not supported by local ZenML deployments."
|
7479
|
+
)
|
7480
|
+
|
7198
7481
|
# ----------------------------- Step runs -----------------------------
|
7199
7482
|
|
7200
7483
|
def create_run_step(self, step_run: StepRunRequest) -> StepRunResponse:
|