zenml-nightly 0.58.2.dev20240626__py3-none-any.whl → 0.61.0.dev20240712__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 +946 -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 +10 -1
- zenml/container_registries/base_container_registry.py +1 -0
- zenml/enums.py +7 -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 +320 -64
- 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 +11 -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 +86 -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 +254 -0
- zenml/stack_deployments/gcp_stack_deployment.py +260 -0
- zenml/stack_deployments/stack_deployment.py +208 -0
- zenml/stack_deployments/utils.py +44 -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 +158 -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 +145 -4
- 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 +300 -6
- zenml/zen_stores/zen_store_interface.py +80 -0
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/METADATA +32 -10
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/RECORD +178 -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.dev20240712.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/entry_points.txt +0 -0
@@ -20,8 +20,8 @@ ZenML is an open-source MLOps framework designed to help you create robust, main
|
|
20
20
|
To install the ZenML chart directly from Amazon ECR, use the following command:
|
21
21
|
|
22
22
|
```bash
|
23
|
-
# example command for version 0.
|
24
|
-
helm install my-zenml oci://public.ecr.aws/zenml/zenml --version 0.
|
23
|
+
# example command for version 0.61.0
|
24
|
+
helm install my-zenml oci://public.ecr.aws/zenml/zenml --version 0.61.0
|
25
25
|
```
|
26
26
|
|
27
27
|
Note: Ensure you have OCI support enabled in your Helm client and that you are authenticated with Amazon ECR.
|
@@ -21,7 +21,7 @@ from pydantic import BaseModel, Field
|
|
21
21
|
from zenml.config.server_config import ServerConfiguration
|
22
22
|
from zenml.exceptions import SubscriptionUpgradeRequiredError
|
23
23
|
from zenml.logger import get_logger
|
24
|
-
from zenml.zen_server.cloud_utils import
|
24
|
+
from zenml.zen_server.cloud_utils import cloud_connection
|
25
25
|
from zenml.zen_server.feature_gate.feature_gate_interface import (
|
26
26
|
FeatureGateInterface,
|
27
27
|
)
|
@@ -59,8 +59,12 @@ class RawUsageEvent(BaseModel):
|
|
59
59
|
)
|
60
60
|
|
61
61
|
|
62
|
-
class ZenMLCloudFeatureGateInterface(FeatureGateInterface
|
63
|
-
"""Feature Gate
|
62
|
+
class ZenMLCloudFeatureGateInterface(FeatureGateInterface):
|
63
|
+
"""ZenML Cloud Feature Gate implementation."""
|
64
|
+
|
65
|
+
def __init__(self) -> None:
|
66
|
+
"""Initialize the object."""
|
67
|
+
self._connection = cloud_connection()
|
64
68
|
|
65
69
|
def check_entitlement(self, resource: ResourceType) -> None:
|
66
70
|
"""Checks if a user is entitled to create a resource.
|
@@ -72,7 +76,7 @@ class ZenMLCloudFeatureGateInterface(FeatureGateInterface, ZenMLCloudSession):
|
|
72
76
|
SubscriptionUpgradeRequiredError: in case a subscription limit is reached
|
73
77
|
"""
|
74
78
|
try:
|
75
|
-
response = self.
|
79
|
+
response = self._connection.get(
|
76
80
|
endpoint=ENTITLEMENT_ENDPOINT + "/" + resource, params=None
|
77
81
|
)
|
78
82
|
except SubscriptionUpgradeRequiredError:
|
@@ -110,7 +114,9 @@ class ZenMLCloudFeatureGateInterface(FeatureGateInterface, ZenMLCloudSession):
|
|
110
114
|
"resource_id": str(resource_id),
|
111
115
|
},
|
112
116
|
).model_dump()
|
113
|
-
response = self.
|
117
|
+
response = self._connection.post(
|
118
|
+
endpoint=USAGE_EVENT_ENDPOINT, data=data
|
119
|
+
)
|
114
120
|
if response.status_code != 200:
|
115
121
|
logger.error(
|
116
122
|
"Usage report not accepted by upstream backend. "
|
@@ -17,7 +17,7 @@ from zenml.constants import (
|
|
17
17
|
ENV_ZENML_ACTIVE_STACK_ID,
|
18
18
|
ENV_ZENML_ACTIVE_WORKSPACE_ID,
|
19
19
|
)
|
20
|
-
from zenml.enums import StackComponentType, StoreType
|
20
|
+
from zenml.enums import ExecutionStatus, StackComponentType, StoreType
|
21
21
|
from zenml.integrations.utils import get_integration_for_module
|
22
22
|
from zenml.models import (
|
23
23
|
CodeReferenceRequest,
|
@@ -26,6 +26,7 @@ from zenml.models import (
|
|
26
26
|
PipelineDeploymentRequest,
|
27
27
|
PipelineDeploymentResponse,
|
28
28
|
PipelineRunResponse,
|
29
|
+
PipelineRunUpdate,
|
29
30
|
StackResponse,
|
30
31
|
)
|
31
32
|
from zenml.new.pipelines.run_utils import (
|
@@ -88,8 +89,6 @@ def run_pipeline(
|
|
88
89
|
ensure_async_orchestrator(deployment=deployment_request, stack=stack)
|
89
90
|
|
90
91
|
new_deployment = zen_store().create_deployment(deployment_request)
|
91
|
-
placeholder_run = create_placeholder_run(deployment=new_deployment)
|
92
|
-
assert placeholder_run
|
93
92
|
|
94
93
|
if auth_context.access_token:
|
95
94
|
token = auth_context.access_token
|
@@ -125,52 +124,62 @@ def run_pipeline(
|
|
125
124
|
deployment_id=new_deployment.id
|
126
125
|
)
|
127
126
|
|
128
|
-
|
129
|
-
|
130
|
-
stack=stack
|
131
|
-
)
|
127
|
+
placeholder_run = create_placeholder_run(deployment=new_deployment)
|
128
|
+
assert placeholder_run
|
132
129
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
python_version = (
|
138
|
-
f"{sys.version_info.major}.{sys.version_info.minor}"
|
130
|
+
def _task() -> None:
|
131
|
+
try:
|
132
|
+
pypi_requirements, apt_packages = get_requirements_for_stack(
|
133
|
+
stack=stack
|
139
134
|
)
|
140
135
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
136
|
+
if build.python_version:
|
137
|
+
version_info = version.parse(build.python_version)
|
138
|
+
python_version = f"{version_info.major}.{version_info.minor}"
|
139
|
+
else:
|
140
|
+
python_version = (
|
141
|
+
f"{sys.version_info.major}.{sys.version_info.minor}"
|
142
|
+
)
|
143
|
+
|
144
|
+
dockerfile = generate_dockerfile(
|
145
|
+
pypi_requirements=pypi_requirements,
|
146
|
+
apt_packages=apt_packages,
|
147
|
+
zenml_version=zenml_version,
|
148
|
+
python_version=python_version,
|
149
|
+
)
|
147
150
|
|
148
|
-
|
151
|
+
image_hash = generate_image_hash(dockerfile=dockerfile)
|
149
152
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
153
|
+
runner_image = workload_manager().build_and_push_image(
|
154
|
+
workload_id=new_deployment.id,
|
155
|
+
dockerfile=dockerfile,
|
156
|
+
image_name=f"{RUNNER_IMAGE_REPOSITORY}:{image_hash}",
|
157
|
+
sync=True,
|
158
|
+
)
|
156
159
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
160
|
+
workload_manager().log(
|
161
|
+
workload_id=new_deployment.id,
|
162
|
+
message="Starting pipeline deployment.",
|
163
|
+
)
|
164
|
+
workload_manager().run(
|
165
|
+
workload_id=new_deployment.id,
|
166
|
+
image=runner_image,
|
167
|
+
command=command,
|
168
|
+
arguments=args,
|
169
|
+
environment=environment,
|
170
|
+
timeout_in_seconds=30,
|
171
|
+
sync=True,
|
172
|
+
)
|
173
|
+
workload_manager().log(
|
174
|
+
workload_id=new_deployment.id,
|
175
|
+
message="Pipeline deployed successfully.",
|
176
|
+
)
|
177
|
+
except Exception:
|
178
|
+
zen_store().update_run(
|
179
|
+
run_id=placeholder_run.id,
|
180
|
+
run_update=PipelineRunUpdate(status=ExecutionStatus.FAILED),
|
181
|
+
)
|
182
|
+
raise
|
174
183
|
|
175
184
|
if background_tasks:
|
176
185
|
background_tasks.add_task(_task)
|
@@ -357,8 +366,12 @@ def apply_run_config(
|
|
357
366
|
step_config = StepConfiguration.model_validate(step_config_dict)
|
358
367
|
|
359
368
|
if update := run_config.steps.get(invocation_id):
|
369
|
+
update_dict = update.model_dump()
|
370
|
+
# Get rid of deprecated name to prevent overriding the step name
|
371
|
+
# with `None`.
|
372
|
+
update_dict.pop("name", None)
|
360
373
|
step_config = pydantic_utils.update_model(
|
361
|
-
step_config, update=
|
374
|
+
step_config, update=update_dict
|
362
375
|
)
|
363
376
|
steps[invocation_id] = Step(spec=step.spec, config=step_config)
|
364
377
|
|
@@ -15,7 +15,7 @@
|
|
15
15
|
|
16
16
|
from typing import TYPE_CHECKING, Dict, List, Set, Tuple
|
17
17
|
|
18
|
-
from zenml.zen_server.cloud_utils import
|
18
|
+
from zenml.zen_server.cloud_utils import cloud_connection
|
19
19
|
from zenml.zen_server.rbac.models import Action, Resource
|
20
20
|
from zenml.zen_server.rbac.rbac_interface import RBACInterface
|
21
21
|
from zenml.zen_server.utils import server_config
|
@@ -74,9 +74,13 @@ def _convert_from_cloud_resource(cloud_resource: str) -> Resource:
|
|
74
74
|
return Resource(type=resource_type_and_id)
|
75
75
|
|
76
76
|
|
77
|
-
class ZenMLCloudRBAC(RBACInterface
|
77
|
+
class ZenMLCloudRBAC(RBACInterface):
|
78
78
|
"""RBAC implementation that uses the ZenML Pro Management Plane as a backend."""
|
79
79
|
|
80
|
+
def __init__(self) -> None:
|
81
|
+
"""Initialize the object."""
|
82
|
+
self._connection = cloud_connection()
|
83
|
+
|
80
84
|
def check_permissions(
|
81
85
|
self, user: "UserResponse", resources: Set[Resource], action: Action
|
82
86
|
) -> Dict[Resource, bool]:
|
@@ -110,7 +114,9 @@ class ZenMLCloudRBAC(RBACInterface, ZenMLCloudSession):
|
|
110
114
|
],
|
111
115
|
"action": str(action),
|
112
116
|
}
|
113
|
-
response = self.
|
117
|
+
response = self._connection.get(
|
118
|
+
endpoint=PERMISSIONS_ENDPOINT, params=params
|
119
|
+
)
|
114
120
|
value = response.json()
|
115
121
|
|
116
122
|
assert isinstance(value, dict)
|
@@ -147,7 +153,7 @@ class ZenMLCloudRBAC(RBACInterface, ZenMLCloudSession):
|
|
147
153
|
"resource": _convert_to_cloud_resource(resource),
|
148
154
|
"action": str(action),
|
149
155
|
}
|
150
|
-
response = self.
|
156
|
+
response = self._connection.get(
|
151
157
|
endpoint=ALLOWED_RESOURCE_IDS_ENDPOINT, params=params
|
152
158
|
)
|
153
159
|
response_json = response.json()
|
@@ -177,4 +183,4 @@ class ZenMLCloudRBAC(RBACInterface, ZenMLCloudSession):
|
|
177
183
|
"resource": _convert_to_cloud_resource(resource),
|
178
184
|
"actions": [str(action) for action in actions],
|
179
185
|
}
|
180
|
-
self.
|
186
|
+
self._connection.post(endpoint=RESOURCE_MEMBERSHIP_ENDPOINT, data=data)
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# Copyright (c) ZenML GmbH 2024. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at:
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
12
|
+
# or implied. See the License for the specific language governing
|
13
|
+
# permissions and limitations under the License.
|
14
|
+
"""Endpoint definitions for stack deployments."""
|
15
|
+
|
16
|
+
import datetime
|
17
|
+
from typing import Optional
|
18
|
+
|
19
|
+
from fastapi import APIRouter, Request, Security
|
20
|
+
|
21
|
+
from zenml.constants import (
|
22
|
+
API,
|
23
|
+
CONFIG,
|
24
|
+
INFO,
|
25
|
+
STACK,
|
26
|
+
STACK_DEPLOYMENT,
|
27
|
+
STACK_DEPLOYMENT_API_TOKEN_EXPIRATION,
|
28
|
+
VERSION_1,
|
29
|
+
)
|
30
|
+
from zenml.enums import StackDeploymentProvider
|
31
|
+
from zenml.models import (
|
32
|
+
DeployedStack,
|
33
|
+
StackDeploymentConfig,
|
34
|
+
StackDeploymentInfo,
|
35
|
+
)
|
36
|
+
from zenml.stack_deployments.utils import get_stack_deployment_class
|
37
|
+
from zenml.zen_server.auth import AuthContext, authorize
|
38
|
+
from zenml.zen_server.exceptions import error_response
|
39
|
+
from zenml.zen_server.rbac.models import Action, ResourceType
|
40
|
+
from zenml.zen_server.rbac.utils import verify_permission
|
41
|
+
from zenml.zen_server.utils import (
|
42
|
+
handle_exceptions,
|
43
|
+
)
|
44
|
+
|
45
|
+
router = APIRouter(
|
46
|
+
prefix=API + VERSION_1 + STACK_DEPLOYMENT,
|
47
|
+
tags=["stacks"],
|
48
|
+
responses={401: error_response, 403: error_response},
|
49
|
+
)
|
50
|
+
|
51
|
+
|
52
|
+
@router.get(
|
53
|
+
INFO,
|
54
|
+
)
|
55
|
+
@handle_exceptions
|
56
|
+
def get_stack_deployment_info(
|
57
|
+
provider: StackDeploymentProvider,
|
58
|
+
_: AuthContext = Security(authorize),
|
59
|
+
) -> StackDeploymentInfo:
|
60
|
+
"""Get information about a stack deployment provider.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
provider: The stack deployment provider.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
Information about the stack deployment provider.
|
67
|
+
"""
|
68
|
+
stack_deployment_class = get_stack_deployment_class(provider)
|
69
|
+
return stack_deployment_class.get_deployment_info()
|
70
|
+
|
71
|
+
|
72
|
+
@router.get(
|
73
|
+
CONFIG,
|
74
|
+
)
|
75
|
+
@handle_exceptions
|
76
|
+
def get_stack_deployment_config(
|
77
|
+
request: Request,
|
78
|
+
provider: StackDeploymentProvider,
|
79
|
+
stack_name: str,
|
80
|
+
location: Optional[str] = None,
|
81
|
+
auth_context: AuthContext = Security(authorize),
|
82
|
+
) -> StackDeploymentConfig:
|
83
|
+
"""Return the URL to deploy the ZenML stack to the specified cloud provider.
|
84
|
+
|
85
|
+
Args:
|
86
|
+
request: The FastAPI request object.
|
87
|
+
provider: The stack deployment provider.
|
88
|
+
stack_name: The name of the stack.
|
89
|
+
location: The location where the stack should be deployed.
|
90
|
+
auth_context: The authentication context.
|
91
|
+
|
92
|
+
Returns:
|
93
|
+
The cloud provider console URL where the stack will be deployed and
|
94
|
+
the configuration for the stack deployment.
|
95
|
+
"""
|
96
|
+
verify_permission(
|
97
|
+
resource_type=ResourceType.SERVICE_CONNECTOR, action=Action.CREATE
|
98
|
+
)
|
99
|
+
verify_permission(
|
100
|
+
resource_type=ResourceType.STACK_COMPONENT,
|
101
|
+
action=Action.CREATE,
|
102
|
+
)
|
103
|
+
verify_permission(resource_type=ResourceType.STACK, action=Action.CREATE)
|
104
|
+
|
105
|
+
stack_deployment_class = get_stack_deployment_class(provider)
|
106
|
+
# Get the base server URL used to call this FastAPI endpoint
|
107
|
+
url = request.url.replace(path="").replace(query="")
|
108
|
+
# Use HTTPS for the URL
|
109
|
+
url = url.replace(scheme="https")
|
110
|
+
|
111
|
+
token = auth_context.access_token
|
112
|
+
assert token is not None
|
113
|
+
|
114
|
+
# A new API token is generated for the stack deployment
|
115
|
+
expires = datetime.datetime.utcnow() + datetime.timedelta(
|
116
|
+
minutes=STACK_DEPLOYMENT_API_TOKEN_EXPIRATION
|
117
|
+
)
|
118
|
+
api_token = token.encode(expires=expires)
|
119
|
+
|
120
|
+
return stack_deployment_class(
|
121
|
+
stack_name=stack_name,
|
122
|
+
location=location,
|
123
|
+
zenml_server_url=str(url),
|
124
|
+
zenml_server_api_token=api_token,
|
125
|
+
).get_deployment_config()
|
126
|
+
|
127
|
+
|
128
|
+
@router.get(
|
129
|
+
STACK,
|
130
|
+
)
|
131
|
+
@handle_exceptions
|
132
|
+
def get_deployed_stack(
|
133
|
+
provider: StackDeploymentProvider,
|
134
|
+
stack_name: str,
|
135
|
+
location: Optional[str] = None,
|
136
|
+
date_start: Optional[datetime.datetime] = None,
|
137
|
+
_: AuthContext = Security(authorize),
|
138
|
+
) -> Optional[DeployedStack]:
|
139
|
+
"""Return a matching ZenML stack that was deployed and registered.
|
140
|
+
|
141
|
+
Args:
|
142
|
+
provider: The stack deployment provider.
|
143
|
+
stack_name: The name of the stack.
|
144
|
+
location: The location where the stack should be deployed.
|
145
|
+
date_start: The date when the deployment started.
|
146
|
+
|
147
|
+
Returns:
|
148
|
+
The ZenML stack that was deployed and registered or None if the stack
|
149
|
+
was not found.
|
150
|
+
"""
|
151
|
+
stack_deployment_class = get_stack_deployment_class(provider)
|
152
|
+
return stack_deployment_class(
|
153
|
+
stack_name=stack_name,
|
154
|
+
location=location,
|
155
|
+
# These fields are not needed for this operation
|
156
|
+
zenml_server_url="",
|
157
|
+
zenml_server_api_token="",
|
158
|
+
).get_stack(date_start=date_start)
|
@@ -22,6 +22,7 @@ from zenml.constants import (
|
|
22
22
|
API,
|
23
23
|
ARTIFACTS,
|
24
24
|
CODE_REPOSITORIES,
|
25
|
+
FULL_STACK,
|
25
26
|
GET_OR_CREATE,
|
26
27
|
MODEL_VERSIONS,
|
27
28
|
MODELS,
|
@@ -51,6 +52,7 @@ from zenml.models import (
|
|
51
52
|
ComponentFilter,
|
52
53
|
ComponentRequest,
|
53
54
|
ComponentResponse,
|
55
|
+
FullStackRequest,
|
54
56
|
ModelRequest,
|
55
57
|
ModelResponse,
|
56
58
|
ModelVersionArtifactRequest,
|
@@ -349,6 +351,68 @@ def create_stack(
|
|
349
351
|
)
|
350
352
|
|
351
353
|
|
354
|
+
@router.post(
|
355
|
+
WORKSPACES + "/{workspace_name_or_id}" + FULL_STACK,
|
356
|
+
response_model=StackResponse,
|
357
|
+
responses={401: error_response, 409: error_response, 422: error_response},
|
358
|
+
)
|
359
|
+
@handle_exceptions
|
360
|
+
def create_full_stack(
|
361
|
+
workspace_name_or_id: Union[str, UUID],
|
362
|
+
full_stack: FullStackRequest,
|
363
|
+
auth_context: AuthContext = Security(authorize),
|
364
|
+
) -> StackResponse:
|
365
|
+
"""Creates a stack for a particular workspace.
|
366
|
+
|
367
|
+
Args:
|
368
|
+
workspace_name_or_id: Name or ID of the workspace.
|
369
|
+
full_stack: Stack to register.
|
370
|
+
auth_context: Authentication context.
|
371
|
+
|
372
|
+
Returns:
|
373
|
+
The created stack.
|
374
|
+
"""
|
375
|
+
workspace = zen_store().get_workspace(workspace_name_or_id)
|
376
|
+
|
377
|
+
is_connector_create_needed = False
|
378
|
+
for connector_id_or_info in full_stack.service_connectors:
|
379
|
+
if isinstance(connector_id_or_info, UUID):
|
380
|
+
service_connector = zen_store().get_service_connector(
|
381
|
+
connector_id_or_info, hydrate=False
|
382
|
+
)
|
383
|
+
verify_permission_for_model(
|
384
|
+
model=service_connector, action=Action.READ
|
385
|
+
)
|
386
|
+
else:
|
387
|
+
is_connector_create_needed = True
|
388
|
+
if is_connector_create_needed:
|
389
|
+
verify_permission(
|
390
|
+
resource_type=ResourceType.SERVICE_CONNECTOR, action=Action.CREATE
|
391
|
+
)
|
392
|
+
|
393
|
+
is_component_create_needed = False
|
394
|
+
for component_id_or_info in full_stack.components.values():
|
395
|
+
if isinstance(component_id_or_info, UUID):
|
396
|
+
component = zen_store().get_stack_component(
|
397
|
+
component_id_or_info, hydrate=False
|
398
|
+
)
|
399
|
+
verify_permission_for_model(model=component, action=Action.READ)
|
400
|
+
else:
|
401
|
+
is_component_create_needed = True
|
402
|
+
if is_component_create_needed:
|
403
|
+
verify_permission(
|
404
|
+
resource_type=ResourceType.STACK_COMPONENT,
|
405
|
+
action=Action.CREATE,
|
406
|
+
)
|
407
|
+
|
408
|
+
verify_permission(resource_type=ResourceType.STACK, action=Action.CREATE)
|
409
|
+
|
410
|
+
full_stack.user = auth_context.user.id
|
411
|
+
full_stack.workspace = workspace.id
|
412
|
+
|
413
|
+
return zen_store().create_full_stack(full_stack)
|
414
|
+
|
415
|
+
|
352
416
|
@router.get(
|
353
417
|
WORKSPACES + "/{workspace_name_or_id}" + STACK_COMPONENTS,
|
354
418
|
response_model=Page[ComponentResponse],
|
@@ -63,6 +63,7 @@ from zenml.zen_server.routers import (
|
|
63
63
|
service_connectors_endpoints,
|
64
64
|
service_endpoints,
|
65
65
|
stack_components_endpoints,
|
66
|
+
stack_deployment_endpoints,
|
66
67
|
stacks_endpoints,
|
67
68
|
steps_endpoints,
|
68
69
|
tags_endpoints,
|
@@ -290,6 +291,7 @@ app.include_router(service_accounts_endpoints.router)
|
|
290
291
|
app.include_router(service_connectors_endpoints.router)
|
291
292
|
app.include_router(service_connectors_endpoints.types_router)
|
292
293
|
app.include_router(service_endpoints.router)
|
294
|
+
app.include_router(stack_deployment_endpoints.router)
|
293
295
|
app.include_router(stacks_endpoints.router)
|
294
296
|
app.include_router(stack_components_endpoints.router)
|
295
297
|
app.include_router(stack_components_endpoints.types_router)
|
@@ -364,7 +364,7 @@ class MigrationUtils(BaseModel):
|
|
364
364
|
# Convert column values to the correct type
|
365
365
|
for column in table.columns:
|
366
366
|
# Blob columns are stored as binary strings
|
367
|
-
if column.type.python_type
|
367
|
+
if column.type.python_type is bytes and isinstance(
|
368
368
|
row[column.name], str
|
369
369
|
):
|
370
370
|
# Convert the string to bytes
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""Release [0.60.0].
|
2
|
+
|
3
|
+
Revision ID: 0.60.0
|
4
|
+
Revises: 25155145c545
|
5
|
+
Create Date: 2024-06-25 14:26:48.867005
|
6
|
+
|
7
|
+
"""
|
8
|
+
|
9
|
+
# revision identifiers, used by Alembic.
|
10
|
+
revision = "0.60.0"
|
11
|
+
down_revision = "25155145c545"
|
12
|
+
branch_labels = None
|
13
|
+
depends_on = None
|
14
|
+
|
15
|
+
|
16
|
+
def upgrade() -> None:
|
17
|
+
"""Upgrade database schema and/or data, creating a new revision."""
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
def downgrade() -> None:
|
22
|
+
"""Downgrade database schema and/or data back to the previous revision."""
|
23
|
+
pass
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""Release [0.61.0].
|
2
|
+
|
3
|
+
Revision ID: 0.61.0
|
4
|
+
Revises: 0d707865f404
|
5
|
+
Create Date: 2024-07-08 15:52:54.765307
|
6
|
+
|
7
|
+
"""
|
8
|
+
|
9
|
+
# revision identifiers, used by Alembic.
|
10
|
+
revision = "0.61.0"
|
11
|
+
down_revision = "0d707865f404"
|
12
|
+
branch_labels = None
|
13
|
+
depends_on = None
|
14
|
+
|
15
|
+
|
16
|
+
def upgrade() -> None:
|
17
|
+
"""Upgrade database schema and/or data, creating a new revision."""
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
def downgrade() -> None:
|
22
|
+
"""Downgrade database schema and/or data back to the previous revision."""
|
23
|
+
pass
|
@@ -0,0 +1,30 @@
|
|
1
|
+
"""adding labels to stacks [0d707865f404].
|
2
|
+
|
3
|
+
Revision ID: 0d707865f404
|
4
|
+
Revises: 0.60.0
|
5
|
+
Create Date: 2024-07-04 16:10:07.709184
|
6
|
+
|
7
|
+
"""
|
8
|
+
|
9
|
+
import sqlalchemy as sa
|
10
|
+
from alembic import op
|
11
|
+
|
12
|
+
# revision identifiers, used by Alembic.
|
13
|
+
revision = "0d707865f404"
|
14
|
+
down_revision = "0.60.0"
|
15
|
+
branch_labels = None
|
16
|
+
depends_on = None
|
17
|
+
|
18
|
+
|
19
|
+
def upgrade() -> None:
|
20
|
+
"""Upgrade database schema and/or data, creating a new revision."""
|
21
|
+
with op.batch_alter_table("stack", schema=None) as batch_op:
|
22
|
+
batch_op.add_column(
|
23
|
+
sa.Column("labels", sa.LargeBinary(), nullable=True)
|
24
|
+
)
|
25
|
+
|
26
|
+
|
27
|
+
def downgrade() -> None:
|
28
|
+
"""Downgrade database schema and/or data back to the previous revision."""
|
29
|
+
with op.batch_alter_table("stack", schema=None) as batch_op:
|
30
|
+
batch_op.drop_column("labels")
|