zenml-nightly 0.60.0.dev20240627__py3-none-any.whl → 0.61.0.dev20240711__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.
Files changed (210) hide show
  1. README.md +30 -9
  2. RELEASE_NOTES.md +34 -0
  3. zenml/VERSION +1 -1
  4. zenml/analytics/enums.py +3 -0
  5. zenml/cli/__init__.py +28 -0
  6. zenml/cli/artifact.py +1 -2
  7. zenml/cli/integration.py +9 -8
  8. zenml/cli/server.py +6 -0
  9. zenml/cli/stack.py +797 -39
  10. zenml/cli/stack_components.py +7 -0
  11. zenml/cli/text_utils.py +35 -1
  12. zenml/cli/utils.py +127 -10
  13. zenml/client.py +23 -14
  14. zenml/config/docker_settings.py +8 -5
  15. zenml/constants.py +5 -1
  16. zenml/container_registries/base_container_registry.py +1 -0
  17. zenml/enums.py +6 -0
  18. zenml/event_hub/event_hub.py +5 -8
  19. zenml/integrations/aws/__init__.py +1 -0
  20. zenml/integrations/azure/__init__.py +1 -0
  21. zenml/integrations/deepchecks/__init__.py +1 -0
  22. zenml/integrations/discord/__init__.py +1 -0
  23. zenml/integrations/evidently/__init__.py +1 -0
  24. zenml/integrations/facets/__init__.py +1 -0
  25. zenml/integrations/feast/__init__.py +1 -0
  26. zenml/integrations/gcp/__init__.py +3 -1
  27. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +203 -44
  28. zenml/integrations/huggingface/__init__.py +1 -0
  29. zenml/integrations/integration.py +24 -0
  30. zenml/integrations/kubeflow/__init__.py +3 -0
  31. zenml/integrations/kubeflow/flavors/kubeflow_orchestrator_flavor.py +1 -1
  32. zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +0 -1
  33. zenml/integrations/kubernetes/__init__.py +3 -1
  34. zenml/integrations/kubernetes/orchestrators/kube_utils.py +4 -1
  35. zenml/integrations/label_studio/annotators/label_studio_annotator.py +1 -0
  36. zenml/integrations/langchain/__init__.py +1 -0
  37. zenml/integrations/mlflow/__init__.py +3 -1
  38. zenml/integrations/neural_prophet/__init__.py +1 -0
  39. zenml/integrations/polars/__init__.py +1 -0
  40. zenml/integrations/prodigy/__init__.py +1 -0
  41. zenml/integrations/pycaret/__init__.py +6 -0
  42. zenml/integrations/registry.py +37 -0
  43. zenml/integrations/s3/artifact_stores/s3_artifact_store.py +17 -6
  44. zenml/integrations/seldon/__init__.py +1 -0
  45. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -0
  46. zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +2 -2
  47. zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +1 -1
  48. zenml/integrations/skypilot/orchestrators/skypilot_orchestrator_entrypoint.py +2 -2
  49. zenml/integrations/skypilot_aws/__init__.py +2 -1
  50. zenml/integrations/skypilot_azure/__init__.py +1 -1
  51. zenml/integrations/skypilot_gcp/__init__.py +1 -1
  52. zenml/integrations/skypilot_lambda/__init__.py +1 -1
  53. zenml/integrations/skypilot_lambda/flavors/skypilot_orchestrator_lambda_vm_flavor.py +1 -1
  54. zenml/integrations/slack/__init__.py +1 -0
  55. zenml/integrations/tekton/__init__.py +1 -0
  56. zenml/integrations/tensorboard/__init__.py +0 -1
  57. zenml/integrations/tensorflow/__init__.py +18 -6
  58. zenml/integrations/wandb/__init__.py +1 -0
  59. zenml/models/__init__.py +9 -0
  60. zenml/models/v2/core/component.py +18 -0
  61. zenml/models/v2/core/model.py +1 -2
  62. zenml/models/v2/core/service_connector.py +17 -0
  63. zenml/models/v2/core/stack.py +31 -0
  64. zenml/models/v2/misc/full_stack.py +97 -0
  65. zenml/models/v2/misc/stack_deployment.py +66 -0
  66. zenml/new/pipelines/pipeline.py +1 -1
  67. zenml/orchestrators/input_utils.py +3 -6
  68. zenml/stack/stack.py +3 -6
  69. zenml/stack_deployments/__init__.py +14 -0
  70. zenml/stack_deployments/aws_stack_deployment.py +289 -0
  71. zenml/stack_deployments/stack_deployment.py +130 -0
  72. zenml/stack_deployments/utils.py +40 -0
  73. zenml/utils/function_utils.py +1 -1
  74. zenml/utils/pagination_utils.py +7 -5
  75. zenml/utils/pipeline_docker_image_builder.py +97 -68
  76. zenml/utils/pydantic_utils.py +6 -5
  77. zenml/zen_server/cloud_utils.py +18 -3
  78. zenml/zen_server/dashboard/assets/{404-C1mcUujL.js → 404-DpJaNHKF.js} +1 -1
  79. zenml/zen_server/dashboard/assets/@radix-CFOkMR_E.js +85 -0
  80. zenml/zen_server/dashboard/assets/{@react-router-DYovave8.js → @react-router-CO-OsFwI.js} +2 -2
  81. zenml/zen_server/dashboard/assets/{@reactflow-DYIyhCfd.js → @reactflow-DJfzkHO1.js} +2 -2
  82. zenml/zen_server/dashboard/assets/@tanstack-DYiOyJUL.js +22 -0
  83. zenml/zen_server/dashboard/assets/AwarenessChannel-BYDLT2xC.js +1 -0
  84. zenml/zen_server/dashboard/assets/{CodeSnippet-WEzpO0az.js → CodeSnippet-BkOuRmyq.js} +2 -2
  85. zenml/zen_server/dashboard/assets/Commands-ZvWR1BRs.js +1 -0
  86. zenml/zen_server/dashboard/assets/CopyButton-DVwLkafa.js +2 -0
  87. zenml/zen_server/dashboard/assets/{CsvVizualization-Bx931j4U.js → CsvVizualization-C2IiqX4I.js} +7 -7
  88. zenml/zen_server/dashboard/assets/DisplayDate-DYgIjlDF.js +1 -0
  89. zenml/zen_server/dashboard/assets/EmptyState-BMLnFVlB.js +1 -0
  90. zenml/zen_server/dashboard/assets/Error-CqX0VqW_.js +1 -0
  91. zenml/zen_server/dashboard/assets/ExecutionStatus-BoLUXR9t.js +1 -0
  92. zenml/zen_server/dashboard/assets/Helpbox-LFydyVwh.js +1 -0
  93. zenml/zen_server/dashboard/assets/Infobox-DnENC0sh.js +1 -0
  94. zenml/zen_server/dashboard/assets/InlineAvatar-CbJtYr0t.js +1 -0
  95. zenml/zen_server/dashboard/assets/{MarkdownVisualization-DsB2QZiK.js → MarkdownVisualization-xp3hhULl.js} +2 -2
  96. zenml/zen_server/dashboard/assets/Pagination-DEbVUupy.js +1 -0
  97. zenml/zen_server/dashboard/assets/PasswordChecker-DUveqlva.js +1 -0
  98. zenml/zen_server/dashboard/assets/SetPassword-BYBdbQDo.js +1 -0
  99. zenml/zen_server/dashboard/assets/SuccessStep-Nx743hll.js +1 -0
  100. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-CKrd3UZz.js → UpdatePasswordSchemas-DF9gSzE0.js} +1 -1
  101. zenml/zen_server/dashboard/assets/{aws-t0gKCj_R.js → aws-BgKTfTfx.js} +1 -1
  102. zenml/zen_server/dashboard/assets/{check-circle-BVvhm5dy.js → check-circle-i56092KI.js} +1 -1
  103. zenml/zen_server/dashboard/assets/{chevron-down-zcvCWmyP.js → chevron-down-D_ZlKMqH.js} +1 -1
  104. zenml/zen_server/dashboard/assets/{chevron-right-double-CJ50E9Gr.js → chevron-right-double-BiEMg7rd.js} +1 -1
  105. zenml/zen_server/dashboard/assets/cloud-only-DVbIeckv.js +1 -0
  106. zenml/zen_server/dashboard/assets/{copy-BRhQz3j-.js → copy-BXNk6BjL.js} +1 -1
  107. zenml/zen_server/dashboard/assets/{database-CRRnyFWh.js → database-1xWSgZfO.js} +1 -1
  108. zenml/zen_server/dashboard/assets/{docker-BAonhm6G.js → docker-CQMVm_4d.js} +1 -1
  109. zenml/zen_server/dashboard/assets/{file-text-CbVERUON.js → file-text-CqD_iu6l.js} +1 -1
  110. zenml/zen_server/dashboard/assets/{help-B8rqCvqn.js → help-bu_DgLKI.js} +1 -1
  111. zenml/zen_server/dashboard/assets/index-C_CrU4vI.js +1 -0
  112. zenml/zen_server/dashboard/assets/index-DK1ynKjA.js +55 -0
  113. zenml/zen_server/dashboard/assets/index-inApY3KQ.css +1 -0
  114. zenml/zen_server/dashboard/assets/index-rK_Wuy2W.js +1 -0
  115. zenml/zen_server/dashboard/assets/index.esm-Corw4lXQ.js +1 -0
  116. zenml/zen_server/dashboard/assets/{login-mutation-Bk2tn324.js → login-mutation-BUnVASxp.js} +1 -1
  117. zenml/zen_server/dashboard/assets/not-found-B4VnX8gK.js +1 -0
  118. zenml/zen_server/dashboard/assets/package-CsUhPmou.js +1 -0
  119. zenml/zen_server/dashboard/assets/{page-D12Rvf0j.js → page-3efNCDeb.js} +2 -2
  120. zenml/zen_server/dashboard/assets/page-7zTHbhhI.js +1 -0
  121. zenml/zen_server/dashboard/assets/page-BEs6jK71.js +1 -0
  122. zenml/zen_server/dashboard/assets/page-BpSqIf4B.js +1 -0
  123. zenml/zen_server/dashboard/assets/{page-8vRWJ5b8.js → page-Bx6o0ARS.js} +1 -1
  124. zenml/zen_server/dashboard/assets/page-C43QGHTt.js +9 -0
  125. zenml/zen_server/dashboard/assets/page-CR0OG7ss.js +1 -0
  126. zenml/zen_server/dashboard/assets/{page-CBuSUrE9.js → page-CRTJ0UuR.js} +1 -1
  127. zenml/zen_server/dashboard/assets/page-CUZIGO-3.js +1 -0
  128. zenml/zen_server/dashboard/assets/page-CaopxiU1.js +1 -0
  129. zenml/zen_server/dashboard/assets/{page-CCtCgG-x.js → page-Cx67M0QT.js} +1 -1
  130. zenml/zen_server/dashboard/assets/page-D7Z399xy.js +1 -0
  131. zenml/zen_server/dashboard/assets/page-D93kd7Xj.js +1 -0
  132. zenml/zen_server/dashboard/assets/{page-Dw9-aJV6.js → page-DKlIdAe5.js} +1 -1
  133. zenml/zen_server/dashboard/assets/{page-COafKNbw.js → page-DMOYZppS.js} +1 -1
  134. zenml/zen_server/dashboard/assets/page-DMsSn3dv.js +2 -0
  135. zenml/zen_server/dashboard/assets/{page-C6v3o0Qj.js → page-Dc_7KMQE.js} +1 -1
  136. zenml/zen_server/dashboard/assets/page-DvCvroOM.js +1 -0
  137. zenml/zen_server/dashboard/assets/page-Hus2pr9T.js +1 -0
  138. zenml/zen_server/dashboard/assets/page-JyfeDUfu.js +1 -0
  139. zenml/zen_server/dashboard/assets/{page-CH26py0a.js → page-Sxn82W-5.js} +1 -1
  140. zenml/zen_server/dashboard/assets/page-TKXERe16.js +1 -0
  141. zenml/zen_server/dashboard/assets/page-Xu8JEjSU.js +1 -0
  142. zenml/zen_server/dashboard/assets/{play-circle-DK5QMJyp.js → play-circle-CNtZKDnW.js} +1 -1
  143. zenml/zen_server/dashboard/assets/plus-DOeLmm7C.js +1 -0
  144. zenml/zen_server/dashboard/assets/{terminal-B2ovgWuz.js → terminal-By9cErXc.js} +1 -1
  145. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-bKxf7U9h.js → update-server-settings-mutation-CR8e3Sir.js} +1 -1
  146. zenml/zen_server/dashboard/assets/{url-CgvM-IVM.js → url-DuQMeqYA.js} +1 -1
  147. zenml/zen_server/dashboard/assets/{zod-DrZvVLjd.js → zod-BhoGpZ63.js} +1 -1
  148. zenml/zen_server/dashboard/index.html +7 -7
  149. zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
  150. zenml/zen_server/dashboard_legacy/index.html +1 -1
  151. zenml/zen_server/dashboard_legacy/{precache-manifest.e7c29295aae591541ef59d1734d79387.js → precache-manifest.c8c57fb0d2132b1d3c2119e776b7dfb3.js} +4 -4
  152. zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
  153. zenml/zen_server/dashboard_legacy/static/js/{main.53857d8b.chunk.js → main.382439a7.chunk.js} +2 -2
  154. zenml/zen_server/dashboard_legacy/static/js/{main.53857d8b.chunk.js.map → main.382439a7.chunk.js.map} +1 -1
  155. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  156. zenml/zen_server/deploy/helm/README.md +2 -2
  157. zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +11 -5
  158. zenml/zen_server/pipeline_deployment/utils.py +57 -44
  159. zenml/zen_server/rbac/zenml_cloud_rbac.py +11 -5
  160. zenml/zen_server/routers/stack_deployment_endpoints.py +144 -0
  161. zenml/zen_server/routers/workspaces_endpoints.py +64 -0
  162. zenml/zen_server/zen_server_api.py +2 -0
  163. zenml/zen_stores/migrations/utils.py +1 -1
  164. zenml/zen_stores/migrations/versions/0.61.0_release.py +23 -0
  165. zenml/zen_stores/migrations/versions/0d707865f404_adding_labels_to_stacks.py +30 -0
  166. zenml/zen_stores/rest_zen_store.py +117 -0
  167. zenml/zen_stores/schemas/stack_schemas.py +10 -0
  168. zenml/zen_stores/schemas/step_run_schemas.py +27 -11
  169. zenml/zen_stores/sql_zen_store.py +283 -0
  170. zenml/zen_stores/zen_store_interface.py +79 -0
  171. {zenml_nightly-0.60.0.dev20240627.dist-info → zenml_nightly-0.61.0.dev20240711.dist-info}/METADATA +32 -10
  172. {zenml_nightly-0.60.0.dev20240627.dist-info → zenml_nightly-0.61.0.dev20240711.dist-info}/RECORD +175 -161
  173. zenml/zen_server/dashboard/assets/@radix-C9DBgJhe.js +0 -77
  174. zenml/zen_server/dashboard/assets/@tanstack-CEbkxrhX.js +0 -30
  175. zenml/zen_server/dashboard/assets/AwarenessChannel-B2KR83Tr.js +0 -1
  176. zenml/zen_server/dashboard/assets/Cards-DSEdjsk8.js +0 -1
  177. zenml/zen_server/dashboard/assets/Commands-CTlhyic5.js +0 -1
  178. zenml/zen_server/dashboard/assets/CopyButton-CTrzKmUO.js +0 -2
  179. zenml/zen_server/dashboard/assets/DisplayDate-BdguISQF.js +0 -1
  180. zenml/zen_server/dashboard/assets/EmptyState-BkooiGtL.js +0 -1
  181. zenml/zen_server/dashboard/assets/Error-4sKxHad4.js +0 -1
  182. zenml/zen_server/dashboard/assets/Helpbox-DW21i5LD.js +0 -1
  183. zenml/zen_server/dashboard/assets/Infobox-C7bf70VS.js +0 -1
  184. zenml/zen_server/dashboard/assets/InlineAvatar-Dxrtafpg.js +0 -1
  185. zenml/zen_server/dashboard/assets/PageHeader-B0pUife2.js +0 -1
  186. zenml/zen_server/dashboard/assets/Pagination-B9WG_9cJ.js +0 -1
  187. zenml/zen_server/dashboard/assets/PasswordChecker-DSLBp7Vl.js +0 -1
  188. zenml/zen_server/dashboard/assets/SetPassword-CiNhT15a.js +0 -1
  189. zenml/zen_server/dashboard/assets/SuccessStep-CykrFndS.js +0 -1
  190. zenml/zen_server/dashboard/assets/cloud-only-Bkawp7CJ.js +0 -1
  191. zenml/zen_server/dashboard/assets/index-BawkpTlr.js +0 -55
  192. zenml/zen_server/dashboard/assets/index-CRmm7QhS.css +0 -1
  193. zenml/zen_server/dashboard/assets/index.esm-F7nqy9zY.js +0 -1
  194. zenml/zen_server/dashboard/assets/not-found-BAuhP4Jb.js +0 -1
  195. zenml/zen_server/dashboard/assets/page--5YvAHg3.js +0 -1
  196. zenml/zen_server/dashboard/assets/page-B0RAq4s_.js +0 -1
  197. zenml/zen_server/dashboard/assets/page-BePtEPHl.js +0 -1
  198. zenml/zen_server/dashboard/assets/page-C1pra1Bc.js +0 -9
  199. zenml/zen_server/dashboard/assets/page-CSs4C9jL.js +0 -1
  200. zenml/zen_server/dashboard/assets/page-Cf2XSej0.js +0 -1
  201. zenml/zen_server/dashboard/assets/page-ClPUAE_f.js +0 -1
  202. zenml/zen_server/dashboard/assets/page-D8pf2vis.js +0 -1
  203. zenml/zen_server/dashboard/assets/page-DHKMmIQH.js +0 -1
  204. zenml/zen_server/dashboard/assets/page-DMZ0VOda.js +0 -1
  205. zenml/zen_server/dashboard/assets/page-Dcg-yQv_.js +0 -1
  206. zenml/zen_server/dashboard/assets/page-DoAK5FSB.js +0 -1
  207. zenml/zen_server/dashboard/assets/page-iXiDqE0J.js +0 -2
  208. {zenml_nightly-0.60.0.dev20240627.dist-info → zenml_nightly-0.61.0.dev20240711.dist-info}/LICENSE +0 -0
  209. {zenml_nightly-0.60.0.dev20240627.dist-info → zenml_nightly-0.61.0.dev20240711.dist-info}/WHEEL +0 -0
  210. {zenml_nightly-0.60.0.dev20240627.dist-info → zenml_nightly-0.61.0.dev20240711.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  apiVersion: v2
2
2
  name: zenml
3
- version: "0.60.0"
3
+ version: "0.61.0"
4
4
  description: Open source MLOps framework for portable production ready ML pipelines
5
5
  keywords:
6
6
  - mlops
@@ -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.60.0
24
- helm install my-zenml oci://public.ecr.aws/zenml/zenml --version 0.60.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 ZenMLCloudSession
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, ZenMLCloudSession):
63
- """Feature Gate interface definition."""
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._get(
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._post(endpoint=USAGE_EVENT_ENDPOINT, data=data)
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
- def _task() -> None:
129
- pypi_requirements, apt_packages = get_requirements_for_stack(
130
- stack=stack
131
- )
127
+ placeholder_run = create_placeholder_run(deployment=new_deployment)
128
+ assert placeholder_run
132
129
 
133
- if build.python_version:
134
- version_info = version.parse(build.python_version)
135
- python_version = f"{version_info.major}.{version_info.minor}"
136
- else:
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
- dockerfile = generate_dockerfile(
142
- pypi_requirements=pypi_requirements,
143
- apt_packages=apt_packages,
144
- zenml_version=zenml_version,
145
- python_version=python_version,
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
- image_hash = generate_image_hash(dockerfile=dockerfile)
151
+ image_hash = generate_image_hash(dockerfile=dockerfile)
149
152
 
150
- runner_image = workload_manager().build_and_push_image(
151
- workload_id=new_deployment.id,
152
- dockerfile=dockerfile,
153
- image_name=f"{RUNNER_IMAGE_REPOSITORY}:{image_hash}",
154
- sync=True,
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
- workload_manager().log(
158
- workload_id=new_deployment.id,
159
- message="Starting pipeline deployment.",
160
- )
161
- workload_manager().run(
162
- workload_id=new_deployment.id,
163
- image=runner_image,
164
- command=command,
165
- arguments=args,
166
- environment=environment,
167
- timeout_in_seconds=30,
168
- sync=True,
169
- )
170
- workload_manager().log(
171
- workload_id=new_deployment.id,
172
- message="Pipeline deployed successfully.",
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=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 ZenMLCloudSession
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, ZenMLCloudSession):
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._get(endpoint=PERMISSIONS_ENDPOINT, params=params)
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._get(
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._post(endpoint=RESOURCE_MEMBERSHIP_ENDPOINT, data=data)
186
+ self._connection.post(endpoint=RESOURCE_MEMBERSHIP_ENDPOINT, data=data)
@@ -0,0 +1,144 @@
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, Tuple
18
+
19
+ from fastapi import APIRouter, Request, Security
20
+
21
+ from zenml.constants import API, INFO, STACK, STACK_DEPLOYMENT, URL, VERSION_1
22
+ from zenml.enums import StackDeploymentProvider
23
+ from zenml.models import DeployedStack, StackDeploymentInfo
24
+ from zenml.stack_deployments.utils import get_stack_deployment_class
25
+ from zenml.zen_server.auth import AuthContext, authorize
26
+ from zenml.zen_server.exceptions import error_response
27
+ from zenml.zen_server.rbac.models import Action, ResourceType
28
+ from zenml.zen_server.rbac.utils import verify_permission
29
+ from zenml.zen_server.utils import (
30
+ handle_exceptions,
31
+ )
32
+
33
+ router = APIRouter(
34
+ prefix=API + VERSION_1 + STACK_DEPLOYMENT,
35
+ tags=["stacks"],
36
+ responses={401: error_response, 403: error_response},
37
+ )
38
+
39
+
40
+ @router.get(
41
+ INFO,
42
+ )
43
+ @handle_exceptions
44
+ def get_stack_deployment_info(
45
+ provider: StackDeploymentProvider,
46
+ _: AuthContext = Security(authorize),
47
+ ) -> StackDeploymentInfo:
48
+ """Get information about a stack deployment provider.
49
+
50
+ Args:
51
+ provider: The stack deployment provider.
52
+
53
+ Returns:
54
+ Information about the stack deployment provider.
55
+ """
56
+ stack_deployment_class = get_stack_deployment_class(provider)
57
+ return StackDeploymentInfo(
58
+ provider=provider,
59
+ description=stack_deployment_class.description(),
60
+ instructions=stack_deployment_class.instructions(),
61
+ post_deploy_instructions=stack_deployment_class.post_deploy_instructions(),
62
+ permissions=stack_deployment_class.permissions(),
63
+ locations=stack_deployment_class.locations(),
64
+ )
65
+
66
+
67
+ @router.get(
68
+ URL,
69
+ )
70
+ @handle_exceptions
71
+ def get_stack_deployment_url(
72
+ request: Request,
73
+ provider: StackDeploymentProvider,
74
+ stack_name: str,
75
+ location: Optional[str] = None,
76
+ auth_context: AuthContext = Security(authorize),
77
+ ) -> Tuple[str, str]:
78
+ """Return the URL to deploy the ZenML stack to the specified cloud provider.
79
+
80
+ Args:
81
+ request: The FastAPI request object.
82
+ provider: The stack deployment provider.
83
+ stack_name: The name of the stack.
84
+ location: The location where the stack should be deployed.
85
+ auth_context: The authentication context.
86
+
87
+ Returns:
88
+ The URL to deploy the ZenML stack to the specified cloud provider
89
+ and a text description of the URL.
90
+ """
91
+ verify_permission(
92
+ resource_type=ResourceType.SERVICE_CONNECTOR, action=Action.CREATE
93
+ )
94
+ verify_permission(
95
+ resource_type=ResourceType.STACK_COMPONENT,
96
+ action=Action.CREATE,
97
+ )
98
+ verify_permission(resource_type=ResourceType.STACK, action=Action.CREATE)
99
+
100
+ stack_deployment_class = get_stack_deployment_class(provider)
101
+ # Get the base server URL used to call this FastAPI endpoint
102
+ url = request.url.replace(path="").replace(query="")
103
+ # Use HTTPS for the URL
104
+ url = url.replace(scheme="https")
105
+
106
+ token = auth_context.access_token
107
+ assert token is not None
108
+
109
+ # A new API token is generated for the stack deployment
110
+ expires = datetime.datetime.utcnow() + datetime.timedelta(minutes=60)
111
+ api_token = token.encode(expires=expires)
112
+
113
+ return stack_deployment_class(
114
+ stack_name=stack_name, location=location
115
+ ).deploy_url(zenml_server_url=str(url), zenml_server_api_token=api_token)
116
+
117
+
118
+ @router.get(
119
+ STACK,
120
+ )
121
+ @handle_exceptions
122
+ def get_deployed_stack(
123
+ provider: StackDeploymentProvider,
124
+ stack_name: str,
125
+ location: Optional[str] = None,
126
+ date_start: Optional[datetime.datetime] = None,
127
+ _: AuthContext = Security(authorize),
128
+ ) -> Optional[DeployedStack]:
129
+ """Return a matching ZenML stack that was deployed and registered.
130
+
131
+ Args:
132
+ provider: The stack deployment provider.
133
+ stack_name: The name of the stack.
134
+ location: The location where the stack should be deployed.
135
+ date_start: The date when the deployment started.
136
+
137
+ Returns:
138
+ The ZenML stack that was deployed and registered or None if the stack
139
+ was not found.
140
+ """
141
+ stack_deployment_class = get_stack_deployment_class(provider)
142
+ return stack_deployment_class(
143
+ stack_name=stack_name, location=location
144
+ ).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 == bytes and isinstance(
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.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")