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.
Files changed (213) hide show
  1. README.md +30 -9
  2. RELEASE_NOTES.md +240 -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/google_credentials_mixin.py +1 -1
  28. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +266 -58
  29. zenml/integrations/huggingface/__init__.py +1 -0
  30. zenml/integrations/integration.py +24 -0
  31. zenml/integrations/kubeflow/__init__.py +3 -0
  32. zenml/integrations/kubeflow/flavors/kubeflow_orchestrator_flavor.py +1 -1
  33. zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +0 -1
  34. zenml/integrations/kubernetes/__init__.py +3 -1
  35. zenml/integrations/kubernetes/orchestrators/kube_utils.py +4 -1
  36. zenml/integrations/label_studio/annotators/label_studio_annotator.py +1 -0
  37. zenml/integrations/langchain/__init__.py +1 -0
  38. zenml/integrations/mlflow/__init__.py +3 -1
  39. zenml/integrations/neural_prophet/__init__.py +1 -0
  40. zenml/integrations/polars/__init__.py +1 -0
  41. zenml/integrations/prodigy/__init__.py +1 -0
  42. zenml/integrations/pycaret/__init__.py +6 -0
  43. zenml/integrations/registry.py +37 -0
  44. zenml/integrations/s3/artifact_stores/s3_artifact_store.py +17 -6
  45. zenml/integrations/seldon/__init__.py +1 -0
  46. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -0
  47. zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +2 -2
  48. zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +1 -1
  49. zenml/integrations/skypilot/orchestrators/skypilot_orchestrator_entrypoint.py +2 -2
  50. zenml/integrations/skypilot_aws/__init__.py +2 -1
  51. zenml/integrations/skypilot_azure/__init__.py +1 -1
  52. zenml/integrations/skypilot_gcp/__init__.py +1 -1
  53. zenml/integrations/skypilot_lambda/__init__.py +1 -1
  54. zenml/integrations/skypilot_lambda/flavors/skypilot_orchestrator_lambda_vm_flavor.py +1 -1
  55. zenml/integrations/slack/__init__.py +1 -0
  56. zenml/integrations/tekton/__init__.py +1 -0
  57. zenml/integrations/tensorboard/__init__.py +0 -1
  58. zenml/integrations/tensorflow/__init__.py +18 -6
  59. zenml/integrations/wandb/__init__.py +1 -0
  60. zenml/models/__init__.py +9 -0
  61. zenml/models/v2/core/component.py +18 -0
  62. zenml/models/v2/core/model.py +1 -2
  63. zenml/models/v2/core/service_connector.py +17 -0
  64. zenml/models/v2/core/stack.py +31 -0
  65. zenml/models/v2/misc/full_stack.py +97 -0
  66. zenml/models/v2/misc/stack_deployment.py +66 -0
  67. zenml/new/pipelines/pipeline.py +1 -1
  68. zenml/orchestrators/input_utils.py +3 -6
  69. zenml/stack/stack.py +3 -6
  70. zenml/stack_deployments/__init__.py +14 -0
  71. zenml/stack_deployments/aws_stack_deployment.py +289 -0
  72. zenml/stack_deployments/stack_deployment.py +130 -0
  73. zenml/stack_deployments/utils.py +40 -0
  74. zenml/utils/function_utils.py +1 -1
  75. zenml/utils/pagination_utils.py +7 -5
  76. zenml/utils/pipeline_docker_image_builder.py +97 -68
  77. zenml/utils/pydantic_utils.py +6 -5
  78. zenml/zen_server/cloud_utils.py +18 -3
  79. zenml/zen_server/dashboard/assets/{404-CDPQCl4D.js → 404-DpJaNHKF.js} +1 -1
  80. zenml/zen_server/dashboard/assets/@radix-CFOkMR_E.js +85 -0
  81. zenml/zen_server/dashboard/assets/{@react-router-DYovave8.js → @react-router-CO-OsFwI.js} +2 -2
  82. zenml/zen_server/dashboard/assets/{@reactflow-CHBapDaj.js → @reactflow-DJfzkHO1.js} +2 -2
  83. zenml/zen_server/dashboard/assets/@tanstack-DYiOyJUL.js +22 -0
  84. zenml/zen_server/dashboard/assets/AwarenessChannel-BYDLT2xC.js +1 -0
  85. zenml/zen_server/dashboard/assets/{CodeSnippet-BidtnWOi.js → CodeSnippet-BkOuRmyq.js} +2 -2
  86. zenml/zen_server/dashboard/assets/Commands-ZvWR1BRs.js +1 -0
  87. zenml/zen_server/dashboard/assets/CopyButton-DVwLkafa.js +2 -0
  88. zenml/zen_server/dashboard/assets/{CsvVizualization-BOuez-fG.js → CsvVizualization-C2IiqX4I.js} +7 -7
  89. zenml/zen_server/dashboard/assets/DisplayDate-DYgIjlDF.js +1 -0
  90. zenml/zen_server/dashboard/assets/EmptyState-BMLnFVlB.js +1 -0
  91. zenml/zen_server/dashboard/assets/Error-CqX0VqW_.js +1 -0
  92. zenml/zen_server/dashboard/assets/ExecutionStatus-BoLUXR9t.js +1 -0
  93. zenml/zen_server/dashboard/assets/Helpbox-LFydyVwh.js +1 -0
  94. zenml/zen_server/dashboard/assets/Infobox-DnENC0sh.js +1 -0
  95. zenml/zen_server/dashboard/assets/InlineAvatar-CbJtYr0t.js +1 -0
  96. zenml/zen_server/dashboard/assets/{MarkdownVisualization-DsB2QZiK.js → MarkdownVisualization-xp3hhULl.js} +2 -2
  97. zenml/zen_server/dashboard/assets/Pagination-DEbVUupy.js +1 -0
  98. zenml/zen_server/dashboard/assets/PasswordChecker-DUveqlva.js +1 -0
  99. zenml/zen_server/dashboard/assets/SetPassword-BYBdbQDo.js +1 -0
  100. zenml/zen_server/dashboard/assets/SuccessStep-Nx743hll.js +1 -0
  101. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DnM-c11H.js → UpdatePasswordSchemas-DF9gSzE0.js} +1 -1
  102. zenml/zen_server/dashboard/assets/{aws-t0gKCj_R.js → aws-BgKTfTfx.js} +1 -1
  103. zenml/zen_server/dashboard/assets/{check-circle-BVvhm5dy.js → check-circle-i56092KI.js} +1 -1
  104. zenml/zen_server/dashboard/assets/{chevron-down-zcvCWmyP.js → chevron-down-D_ZlKMqH.js} +1 -1
  105. zenml/zen_server/dashboard/assets/{chevron-right-double-CJ50E9Gr.js → chevron-right-double-BiEMg7rd.js} +1 -1
  106. zenml/zen_server/dashboard/assets/cloud-only-DVbIeckv.js +1 -0
  107. zenml/zen_server/dashboard/assets/{copy-BRhQz3j-.js → copy-BXNk6BjL.js} +1 -1
  108. zenml/zen_server/dashboard/assets/{database-CRRnyFWh.js → database-1xWSgZfO.js} +1 -1
  109. zenml/zen_server/dashboard/assets/{docker-BAonhm6G.js → docker-CQMVm_4d.js} +1 -1
  110. zenml/zen_server/dashboard/assets/{file-text-CbVERUON.js → file-text-CqD_iu6l.js} +1 -1
  111. zenml/zen_server/dashboard/assets/{help-B8rqCvqn.js → help-bu_DgLKI.js} +1 -1
  112. zenml/zen_server/dashboard/assets/index-C_CrU4vI.js +1 -0
  113. zenml/zen_server/dashboard/assets/index-DK1ynKjA.js +55 -0
  114. zenml/zen_server/dashboard/assets/index-inApY3KQ.css +1 -0
  115. zenml/zen_server/dashboard/assets/index-rK_Wuy2W.js +1 -0
  116. zenml/zen_server/dashboard/assets/index.esm-Corw4lXQ.js +1 -0
  117. zenml/zen_server/dashboard/assets/{login-mutation-wzzl23C6.js → login-mutation-BUnVASxp.js} +1 -1
  118. zenml/zen_server/dashboard/assets/not-found-B4VnX8gK.js +1 -0
  119. zenml/zen_server/dashboard/assets/package-CsUhPmou.js +1 -0
  120. zenml/zen_server/dashboard/assets/{page-BmkSiYeQ.js → page-3efNCDeb.js} +2 -2
  121. zenml/zen_server/dashboard/assets/page-7zTHbhhI.js +1 -0
  122. zenml/zen_server/dashboard/assets/page-BEs6jK71.js +1 -0
  123. zenml/zen_server/dashboard/assets/page-BpSqIf4B.js +1 -0
  124. zenml/zen_server/dashboard/assets/{page-AQKopn_4.js → page-Bx6o0ARS.js} +1 -1
  125. zenml/zen_server/dashboard/assets/page-C43QGHTt.js +9 -0
  126. zenml/zen_server/dashboard/assets/page-CR0OG7ss.js +1 -0
  127. zenml/zen_server/dashboard/assets/page-CRTJ0UuR.js +1 -0
  128. zenml/zen_server/dashboard/assets/page-CUZIGO-3.js +1 -0
  129. zenml/zen_server/dashboard/assets/page-CaopxiU1.js +1 -0
  130. zenml/zen_server/dashboard/assets/{page-CuT1SUik.js → page-Cx67M0QT.js} +1 -1
  131. zenml/zen_server/dashboard/assets/page-D7Z399xy.js +1 -0
  132. zenml/zen_server/dashboard/assets/page-D93kd7Xj.js +1 -0
  133. zenml/zen_server/dashboard/assets/{page-BzVZGExK.js → page-DKlIdAe5.js} +1 -1
  134. zenml/zen_server/dashboard/assets/{page-Bi5AI0S7.js → page-DMOYZppS.js} +1 -1
  135. zenml/zen_server/dashboard/assets/page-DMsSn3dv.js +2 -0
  136. zenml/zen_server/dashboard/assets/{page-BW6Ket3a.js → page-Dc_7KMQE.js} +1 -1
  137. zenml/zen_server/dashboard/assets/page-DvCvroOM.js +1 -0
  138. zenml/zen_server/dashboard/assets/page-Hus2pr9T.js +1 -0
  139. zenml/zen_server/dashboard/assets/page-JyfeDUfu.js +1 -0
  140. zenml/zen_server/dashboard/assets/{page-yN4rZ-ZS.js → page-Sxn82W-5.js} +1 -1
  141. zenml/zen_server/dashboard/assets/page-TKXERe16.js +1 -0
  142. zenml/zen_server/dashboard/assets/page-Xu8JEjSU.js +1 -0
  143. zenml/zen_server/dashboard/assets/{play-circle-DK5QMJyp.js → play-circle-CNtZKDnW.js} +1 -1
  144. zenml/zen_server/dashboard/assets/plus-DOeLmm7C.js +1 -0
  145. zenml/zen_server/dashboard/assets/{terminal-B2ovgWuz.js → terminal-By9cErXc.js} +1 -1
  146. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-0Wgz8pUE.js → update-server-settings-mutation-CR8e3Sir.js} +1 -1
  147. zenml/zen_server/dashboard/assets/{url-6_xv0WJS.js → url-DuQMeqYA.js} +1 -1
  148. zenml/zen_server/dashboard/assets/{zod-DrZvVLjd.js → zod-BhoGpZ63.js} +1 -1
  149. zenml/zen_server/dashboard/index.html +7 -7
  150. zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
  151. zenml/zen_server/dashboard_legacy/index.html +1 -1
  152. zenml/zen_server/dashboard_legacy/{precache-manifest.f4abc5b7cfa7d90c1caf5521918e29a8.js → precache-manifest.c8c57fb0d2132b1d3c2119e776b7dfb3.js} +4 -4
  153. zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
  154. zenml/zen_server/dashboard_legacy/static/js/{main.ac2f17d0.chunk.js → main.382439a7.chunk.js} +2 -2
  155. zenml/zen_server/dashboard_legacy/static/js/{main.ac2f17d0.chunk.js.map → main.382439a7.chunk.js.map} +1 -1
  156. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  157. zenml/zen_server/deploy/helm/README.md +2 -2
  158. zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +11 -5
  159. zenml/zen_server/pipeline_deployment/utils.py +57 -44
  160. zenml/zen_server/rbac/zenml_cloud_rbac.py +11 -5
  161. zenml/zen_server/routers/stack_deployment_endpoints.py +144 -0
  162. zenml/zen_server/routers/workspaces_endpoints.py +64 -0
  163. zenml/zen_server/zen_server_api.py +2 -0
  164. zenml/zen_stores/migrations/utils.py +1 -1
  165. zenml/zen_stores/migrations/versions/0.60.0_release.py +23 -0
  166. zenml/zen_stores/migrations/versions/0.61.0_release.py +23 -0
  167. zenml/zen_stores/migrations/versions/0d707865f404_adding_labels_to_stacks.py +30 -0
  168. zenml/zen_stores/rest_zen_store.py +117 -0
  169. zenml/zen_stores/schemas/stack_schemas.py +10 -0
  170. zenml/zen_stores/schemas/step_run_schemas.py +27 -11
  171. zenml/zen_stores/sql_zen_store.py +283 -0
  172. zenml/zen_stores/zen_store_interface.py +79 -0
  173. {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/METADATA +32 -10
  174. {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/RECORD +177 -162
  175. zenml/zen_server/dashboard/assets/@radix-C9DBgJhe.js +0 -77
  176. zenml/zen_server/dashboard/assets/@tanstack-CEbkxrhX.js +0 -30
  177. zenml/zen_server/dashboard/assets/AwarenessChannel-nXGpmj_f.js +0 -1
  178. zenml/zen_server/dashboard/assets/Cards-nwsvQLVS.js +0 -1
  179. zenml/zen_server/dashboard/assets/Commands-DuIWKg_Q.js +0 -1
  180. zenml/zen_server/dashboard/assets/CopyButton-B_YSm-Ds.js +0 -2
  181. zenml/zen_server/dashboard/assets/DisplayDate-BdguISQF.js +0 -1
  182. zenml/zen_server/dashboard/assets/EmptyState-BkooiGtL.js +0 -1
  183. zenml/zen_server/dashboard/assets/Error-B6M0dPph.js +0 -1
  184. zenml/zen_server/dashboard/assets/Helpbox-BQoqCm04.js +0 -1
  185. zenml/zen_server/dashboard/assets/Infobox-Ce9mefqU.js +0 -1
  186. zenml/zen_server/dashboard/assets/InlineAvatar-DGf3dVhV.js +0 -1
  187. zenml/zen_server/dashboard/assets/PageHeader-DGaemzjc.js +0 -1
  188. zenml/zen_server/dashboard/assets/Pagination-DVYfBCCc.js +0 -1
  189. zenml/zen_server/dashboard/assets/PasswordChecker-DSLBp7Vl.js +0 -1
  190. zenml/zen_server/dashboard/assets/SetPassword-B5s7DJug.js +0 -1
  191. zenml/zen_server/dashboard/assets/SuccessStep-ZzczaM7g.js +0 -1
  192. zenml/zen_server/dashboard/assets/cloud-only-Ba_ShBR5.js +0 -1
  193. zenml/zen_server/dashboard/assets/index-CWJ3xbIf.css +0 -1
  194. zenml/zen_server/dashboard/assets/index-QORVVTMN.js +0 -55
  195. zenml/zen_server/dashboard/assets/index.esm-F7nqy9zY.js +0 -1
  196. zenml/zen_server/dashboard/assets/not-found-Dh2la7kh.js +0 -1
  197. zenml/zen_server/dashboard/assets/page-B-5jAKoO.js +0 -1
  198. zenml/zen_server/dashboard/assets/page-B-vWk8a6.js +0 -1
  199. zenml/zen_server/dashboard/assets/page-B0BrqfS8.js +0 -1
  200. zenml/zen_server/dashboard/assets/page-BQxVFlUl.js +0 -1
  201. zenml/zen_server/dashboard/assets/page-ByrHy6Ss.js +0 -1
  202. zenml/zen_server/dashboard/assets/page-CPtY4Kv_.js +0 -1
  203. zenml/zen_server/dashboard/assets/page-CmmukLsl.js +0 -1
  204. zenml/zen_server/dashboard/assets/page-D2D-7qyr.js +0 -9
  205. zenml/zen_server/dashboard/assets/page-DAQQyLxT.js +0 -1
  206. zenml/zen_server/dashboard/assets/page-DHkUMl_E.js +0 -1
  207. zenml/zen_server/dashboard/assets/page-DZCbwOEs.js +0 -2
  208. zenml/zen_server/dashboard/assets/page-DdaIt20-.js +0 -1
  209. zenml/zen_server/dashboard/assets/page-LqLs24Ot.js +0 -1
  210. zenml/zen_server/dashboard/assets/page-lebv0c7C.js +0 -1
  211. {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/LICENSE +0 -0
  212. {zenml_nightly-0.58.2.dev20240626.dist-info → zenml_nightly-0.61.0.dev20240710.dist-info}/WHEEL +0 -0
  213. {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
- full_step_config = Step.model_validate(
217
- json.loads(self.deployment.step_configurations)[self.name]
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: