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
@@ -0,0 +1,66 @@
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
+ """Models related to cloud stack deployments."""
15
+
16
+ from typing import Dict, List, Optional
17
+
18
+ from pydantic import BaseModel, Field
19
+
20
+ from zenml.enums import StackDeploymentProvider
21
+ from zenml.models.v2.core.service_connector import ServiceConnectorResponse
22
+ from zenml.models.v2.core.stack import StackResponse
23
+
24
+
25
+ class StackDeploymentInfo(BaseModel):
26
+ """Information about a stack deployment."""
27
+
28
+ provider: StackDeploymentProvider = Field(
29
+ title="The provider of the stack deployment."
30
+ )
31
+ description: str = Field(
32
+ title="The description of the stack deployment.",
33
+ description="The description of the stack deployment.",
34
+ )
35
+ instructions: str = Field(
36
+ title="The instructions for deploying the stack.",
37
+ description="The instructions for deploying the stack.",
38
+ )
39
+ post_deploy_instructions: str = Field(
40
+ title="The instructions for post-deployment.",
41
+ description="The instructions for post-deployment.",
42
+ )
43
+ permissions: Dict[str, List[str]] = Field(
44
+ title="The permissions granted to ZenML to access the cloud resources.",
45
+ description="The permissions granted to ZenML to access the cloud "
46
+ "resources, as a dictionary grouping permissions by resource.",
47
+ )
48
+ locations: Dict[str, str] = Field(
49
+ title="The locations where the stack can be deployed.",
50
+ description="The locations where the stack can be deployed, as a "
51
+ "dictionary mapping location names to descriptions.",
52
+ )
53
+
54
+
55
+ class DeployedStack(BaseModel):
56
+ """Information about a deployed stack."""
57
+
58
+ stack: StackResponse = Field(
59
+ title="The stack that was deployed.",
60
+ description="The stack that was deployed.",
61
+ )
62
+ service_connector: Optional[ServiceConnectorResponse] = Field(
63
+ default=None,
64
+ title="The service connector for the deployed stack.",
65
+ description="The service connector for the deployed stack.",
66
+ )
@@ -281,7 +281,7 @@ class Pipeline:
281
281
  raise RuntimeError(
282
282
  f"Cannot get the model of pipeline '{self.name}' because it has "
283
283
  f"not been registered yet. Please ensure that the pipeline has "
284
- f"been run and that at least one step has been executed."
284
+ f"been run or built and try again."
285
285
  )
286
286
 
287
287
  @contextmanager
@@ -13,7 +13,6 @@
13
13
  # permissions and limitations under the License.
14
14
  """Utilities for inputs."""
15
15
 
16
- import functools
17
16
  from typing import TYPE_CHECKING, Dict, List, Tuple
18
17
  from uuid import UUID
19
18
 
@@ -48,13 +47,11 @@ def resolve_step_inputs(
48
47
  """
49
48
  from zenml.models import ArtifactVersionResponse, RunMetadataResponse
50
49
 
51
- list_run_steps = functools.partial(
52
- Client().list_run_steps, pipeline_run_id=run_id
53
- )
54
-
55
50
  current_run_steps = {
56
51
  run_step.name: run_step
57
- for run_step in pagination_utils.depaginate(list_run_steps)
52
+ for run_step in pagination_utils.depaginate(
53
+ Client().list_run_steps, pipeline_run_id=run_id
54
+ )
58
55
  }
59
56
 
60
57
  input_artifacts: Dict[str, "ArtifactVersionResponse"] = {}
zenml/stack/stack.py CHANGED
@@ -13,7 +13,6 @@
13
13
  # permissions and limitations under the License.
14
14
  """Implementation of the ZenML Stack class."""
15
15
 
16
- import functools
17
16
  import itertools
18
17
  import json
19
18
  import os
@@ -155,11 +154,9 @@ class Stack:
155
154
 
156
155
  # Run a hydrated list call once to avoid one request per component
157
156
  component_models = pagination_utils.depaginate(
158
- list_method=functools.partial(
159
- Client().list_stack_components,
160
- stack_id=stack_model.id,
161
- hydrate=True,
162
- )
157
+ Client().list_stack_components,
158
+ stack_id=stack_model.id,
159
+ hydrate=True,
163
160
  )
164
161
 
165
162
  stack_components = {
@@ -0,0 +1,14 @@
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
+ """ZenML Stack Deployments."""
@@ -0,0 +1,289 @@
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
+ """Functionality to deploy a ZenML stack to a cloud provider."""
15
+
16
+ import datetime
17
+ from typing import ClassVar, Dict, List, Optional, Tuple
18
+
19
+ from zenml.client import Client
20
+ from zenml.enums import StackComponentType, StackDeploymentProvider
21
+ from zenml.models import (
22
+ DeployedStack,
23
+ )
24
+ from zenml.stack_deployments.stack_deployment import ZenMLCloudStackDeployment
25
+ from zenml.utils.string_utils import random_str
26
+
27
+ AWS_DEPLOYMENT_TYPE = "cloud-formation"
28
+
29
+
30
+ class AWSZenMLCloudStackDeployment(ZenMLCloudStackDeployment):
31
+ """AWS ZenML Cloud Stack Deployment."""
32
+
33
+ provider: ClassVar[StackDeploymentProvider] = StackDeploymentProvider.AWS
34
+
35
+ @classmethod
36
+ def description(cls) -> str:
37
+ """Return a description of the ZenML Cloud Stack Deployment.
38
+
39
+ This will be displayed when the user is prompted to deploy
40
+ the ZenML stack.
41
+
42
+ Returns:
43
+ A MarkDown description of the ZenML Cloud Stack Deployment.
44
+ """
45
+ return """
46
+ Provision and register a basic AWS ZenML stack authenticated and connected to
47
+ all the necessary cloud infrastructure resources required to run pipelines in
48
+ AWS.
49
+ """
50
+
51
+ @classmethod
52
+ def instructions(cls) -> str:
53
+ """Return instructions on how to deploy the ZenML stack to the specified cloud provider.
54
+
55
+ This will be displayed before the user is prompted to deploy the ZenML
56
+ stack.
57
+
58
+ Returns:
59
+ MarkDown instructions on how to deploy the ZenML stack to the
60
+ specified cloud provider.
61
+ """
62
+ return """
63
+ You will be redirected to the AWS console in your browser where you'll be asked
64
+ to log into your AWS account and create a CloudFormation ZenML stack. The stack
65
+ parameters will be pre-filled with the necessary information to connect ZenML to
66
+ your AWS account, so you should only need to review and confirm the stack.
67
+
68
+ After the CloudFormation stack is deployed, you can return to the CLI to view
69
+ details about the associated ZenML stack automatically registered with ZenML.
70
+
71
+ **NOTE**: The CloudFormation stack will create the following new resources in
72
+ your AWS account. Please ensure you have the necessary permissions and are aware
73
+ of any potential costs:
74
+
75
+ - An S3 bucket registered as a [ZenML artifact store](https://docs.zenml.io/stack-components/artifact-stores/s3).
76
+ - An ECR repository registered as a [ZenML container registry](https://docs.zenml.io/stack-components/container-registries/aws).
77
+ - Sagemaker registered as a [ZenML orchestrator](https://docs.zenml.io/stack-components/orchestrators/sagemaker).
78
+ - An IAM user and IAM role with the minimum necessary permissions to access the
79
+ above resources.
80
+ - An AWS access key used to give access to ZenML to connect to the above
81
+ resources through a [ZenML service connector](https://docs.zenml.io/how-to/auth-management/aws-service-connector).
82
+
83
+ The CloudFormation stack will automatically create an AWS secret key and
84
+ will share it with ZenML to give it permission to access the resources created
85
+ by the stack. You can revoke these permissions at any time by deleting the
86
+ CloudFormation stack.
87
+ """
88
+
89
+ @classmethod
90
+ def post_deploy_instructions(cls) -> str:
91
+ """Return instructions on what to do after the deployment is complete.
92
+
93
+ This will be displayed after the deployment is complete.
94
+
95
+ Returns:
96
+ MarkDown instructions on what to do after the deployment is
97
+ complete.
98
+ """
99
+ return """
100
+ The ZenML stack has been successfully deployed and registered. You can delete
101
+ the CloudFormation at any time to revoke ZenML's access to your AWS account and
102
+ to clean up the resources created by the stack by using the AWS CloudFormation
103
+ console.
104
+ """
105
+
106
+ @classmethod
107
+ def permissions(cls) -> Dict[str, List[str]]:
108
+ """Return the permissions granted to ZenML to access the cloud resources.
109
+
110
+ Returns:
111
+ The permissions granted to ZenML to access the cloud resources, as
112
+ a dictionary grouping permissions by resource.
113
+ """
114
+ return {
115
+ "S3 Bucket": [
116
+ "s3:ListBucket",
117
+ "s3:GetObject",
118
+ "s3:PutObject",
119
+ "s3:DeleteObject",
120
+ ],
121
+ "ECR Repository": [
122
+ "ecr:DescribeRepositories",
123
+ "ecr:ListRepositories",
124
+ "ecr:DescribeRegistry",
125
+ "ecr:BatchGetImage",
126
+ "ecr:DescribeImages",
127
+ "ecr:BatchCheckLayerAvailability",
128
+ "ecr:GetDownloadUrlForLayer",
129
+ "ecr:InitiateLayerUpload",
130
+ "ecr:UploadLayerPart",
131
+ "ecr:CompleteLayerUpload",
132
+ "ecr:PutImage",
133
+ "ecr:GetAuthorizationToken",
134
+ ],
135
+ "SageMaker (Client)": [
136
+ "sagemaker:CreatePipeline",
137
+ "sagemaker:StartPipelineExecution",
138
+ "sagemaker:DescribePipeline",
139
+ "sagemaker:DescribePipelineExecution",
140
+ ],
141
+ "SageMaker (Jobs)": [
142
+ "AmazonSageMakerFullAccess",
143
+ ],
144
+ }
145
+
146
+ @classmethod
147
+ def locations(cls) -> Dict[str, str]:
148
+ """Return the locations where the ZenML stack can be deployed.
149
+
150
+ Returns:
151
+ The regions where the ZenML stack can be deployed as a map of region
152
+ names to region descriptions.
153
+ """
154
+ # Return a list of all possible AWS regions
155
+
156
+ # Based on the AWS regions listed at
157
+ # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html
158
+ return {
159
+ "US East (Ohio)": "us-east-2",
160
+ "US East (N. Virginia)": "us-east-1",
161
+ "US West (N. California)": "us-west-1",
162
+ "US West (Oregon)": "us-west-2",
163
+ "Africa (Cape Town)": "af-south-1",
164
+ "Asia Pacific (Hong Kong)": "ap-east-1",
165
+ "Asia Pacific (Hyderabad)": "ap-south-2",
166
+ "Asia Pacific (Jakarta)": "ap-southeast-3",
167
+ "Asia Pacific (Melbourne)": "ap-southeast-4",
168
+ "Asia Pacific (Mumbai)": "ap-south-1",
169
+ "Asia Pacific (Osaka)": "ap-northeast-3",
170
+ "Asia Pacific (Seoul)": "ap-northeast-2",
171
+ "Asia Pacific (Singapore)": "ap-southeast-1",
172
+ "Asia Pacific (Sydney)": "ap-southeast-2",
173
+ "Asia Pacific (Tokyo)": "ap-northeast-1",
174
+ "Canada (Central)": "ca-central-1",
175
+ "Canada West (Calgary)": "ca-west-1",
176
+ "Europe (Frankfurt)": "eu-central-1",
177
+ "Europe (Ireland)": "eu-west-1",
178
+ "Europe (London)": "eu-west-2",
179
+ "Europe (Milan)": "eu-south-1",
180
+ "Europe (Paris)": "eu-west-3",
181
+ "Europe (Spain)": "eu-south-2",
182
+ "Europe (Stockholm)": "eu-north-1",
183
+ "Europe (Zurich)": "eu-central-2",
184
+ "Israel (Tel Aviv)": "il-central-1",
185
+ "Middle East (Bahrain)": "me-south-1",
186
+ "Middle East (UAE)": "me-central-1",
187
+ "South America (São Paulo)": "sa-east-1",
188
+ }
189
+
190
+ def deploy_url(
191
+ self,
192
+ zenml_server_url: str,
193
+ zenml_server_api_token: str,
194
+ ) -> Tuple[str, str]:
195
+ """Return the URL to deploy the ZenML stack to the specified cloud provider.
196
+
197
+ The URL should point to a cloud provider console where the user can
198
+ deploy the ZenML stack and should include as many pre-filled parameters
199
+ as possible.
200
+
201
+ Args:
202
+ zenml_server_url: The URL of the ZenML server.
203
+ zenml_server_api_token: The API token to authenticate with the ZenML
204
+ server.
205
+
206
+ Returns:
207
+ The URL to deploy the ZenML stack to the specified cloud provider
208
+ and a text description of the URL.
209
+ """
210
+ params = dict(
211
+ stackName=self.stack_name,
212
+ templateURL="https://zenml-cf-templates.s3.eu-central-1.amazonaws.com/aws-ecr-s3-sagemaker.yaml",
213
+ param_ResourceName=f"zenml-{random_str(6).lower()}",
214
+ param_ZenMLServerURL=zenml_server_url,
215
+ param_ZenMLServerAPIToken=zenml_server_api_token,
216
+ )
217
+ # Encode the parameters as URL query parameters
218
+ query_params = "&".join([f"{k}={v}" for k, v in params.items()])
219
+
220
+ region = ""
221
+ if self.location:
222
+ region = f"region={self.location}"
223
+
224
+ return (
225
+ f"https://console.aws.amazon.com/cloudformation/home?"
226
+ f"{region}#/stacks/create/review?{query_params}",
227
+ "AWS CloudFormation Console",
228
+ )
229
+
230
+ def get_stack(
231
+ self, date_start: Optional[datetime.datetime] = None
232
+ ) -> Optional[DeployedStack]:
233
+ """Return the ZenML stack that was deployed and registered.
234
+
235
+ This method is called to retrieve a ZenML stack matching the deployment
236
+ provider.
237
+
238
+ Args:
239
+ date_start: The date when the deployment started.
240
+
241
+ Returns:
242
+ The ZenML stack that was deployed and registered or None if a
243
+ matching stack was not found.
244
+ """
245
+ client = Client()
246
+
247
+ # It's difficult to find a stack that matches the CloudFormation
248
+ # deployment 100% because the user can change the stack name before they
249
+ # deploy the stack in AWS.
250
+ #
251
+ # We try to find a full AWS stack that matches the deployment provider
252
+ # that was registered after this deployment was created.
253
+
254
+ # Get all stacks created after the start date
255
+ stacks = client.list_stacks(
256
+ created=f"gt:{str(date_start.replace(microsecond=0))}"
257
+ if date_start
258
+ else None,
259
+ sort_by="desc:created",
260
+ size=50,
261
+ )
262
+
263
+ if not stacks.items:
264
+ return None
265
+
266
+ # Find a stack that best matches the deployment provider
267
+ for stack in stacks.items:
268
+ if not stack.labels:
269
+ continue
270
+
271
+ if stack.labels.get("zenml:provider") != self.provider.value:
272
+ continue
273
+
274
+ if stack.labels.get("zenml:deployment") != AWS_DEPLOYMENT_TYPE:
275
+ continue
276
+
277
+ artifact_store = stack.components[
278
+ StackComponentType.ARTIFACT_STORE
279
+ ][0]
280
+
281
+ if not artifact_store.connector:
282
+ continue
283
+
284
+ return DeployedStack(
285
+ stack=stack,
286
+ service_connector=artifact_store.connector,
287
+ )
288
+
289
+ return None
@@ -0,0 +1,130 @@
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
+ """Functionality to deploy a ZenML stack to a cloud provider."""
15
+
16
+ import datetime
17
+ from abc import abstractmethod
18
+ from typing import ClassVar, Dict, List, Optional, Tuple
19
+
20
+ from pydantic import BaseModel
21
+
22
+ from zenml.enums import StackDeploymentProvider
23
+ from zenml.models import (
24
+ DeployedStack,
25
+ )
26
+
27
+
28
+ class ZenMLCloudStackDeployment(BaseModel):
29
+ """ZenML Cloud Stack CLI Deployment base class."""
30
+
31
+ provider: ClassVar[StackDeploymentProvider]
32
+ stack_name: str
33
+ location: Optional[str] = None
34
+
35
+ @classmethod
36
+ @abstractmethod
37
+ def description(cls) -> str:
38
+ """Return a description of the ZenML Cloud Stack Deployment.
39
+
40
+ This will be displayed when the user is prompted to deploy
41
+ the ZenML stack.
42
+
43
+ Returns:
44
+ A MarkDown description of the ZenML Cloud Stack Deployment.
45
+ """
46
+
47
+ @classmethod
48
+ @abstractmethod
49
+ def instructions(cls) -> str:
50
+ """Return instructions on how to deploy the ZenML stack to the specified cloud provider.
51
+
52
+ This will be displayed before the user is prompted to deploy the ZenML
53
+ stack.
54
+
55
+ Returns:
56
+ MarkDown instructions on how to deploy the ZenML stack to the
57
+ specified cloud provider.
58
+ """
59
+
60
+ @classmethod
61
+ @abstractmethod
62
+ def post_deploy_instructions(cls) -> str:
63
+ """Return instructions on what to do after the deployment is complete.
64
+
65
+ This will be displayed after the deployment is complete.
66
+
67
+ Returns:
68
+ MarkDown instructions on what to do after the deployment is
69
+ complete.
70
+ """
71
+
72
+ @classmethod
73
+ @abstractmethod
74
+ def permissions(cls) -> Dict[str, List[str]]:
75
+ """Return the permissions granted to ZenML to access the cloud resources.
76
+
77
+ Returns:
78
+ The permissions granted to ZenML to access the cloud resources, as
79
+ a dictionary grouping permissions by resource.
80
+ """
81
+
82
+ @classmethod
83
+ @abstractmethod
84
+ def locations(cls) -> Dict[str, str]:
85
+ """Return the locations where the ZenML stack can be deployed.
86
+
87
+ Returns:
88
+ The regions where the ZenML stack can be deployed as a map of region
89
+ names to region descriptions.
90
+ """
91
+
92
+ @abstractmethod
93
+ def deploy_url(
94
+ self,
95
+ zenml_server_url: str,
96
+ zenml_server_api_token: str,
97
+ ) -> Tuple[str, str]:
98
+ """Return the URL to deploy the ZenML stack to the specified cloud provider.
99
+
100
+ The URL should point to a cloud provider console where the user can
101
+ deploy the ZenML stack and should include as many pre-filled parameters
102
+ as possible.
103
+
104
+ Args:
105
+ zenml_server_url: The URL of the ZenML server.
106
+ zenml_server_api_token: The API token to authenticate with the ZenML
107
+ server.
108
+
109
+ Returns:
110
+ The URL to deploy the ZenML stack to the specified cloud provider
111
+ and a text description of the URL.
112
+ """
113
+
114
+ @abstractmethod
115
+ def get_stack(
116
+ self,
117
+ date_start: Optional[datetime.datetime] = None,
118
+ ) -> Optional[DeployedStack]:
119
+ """Return the ZenML stack that was deployed and registered.
120
+
121
+ This method is called to retrieve a ZenML stack matching the deployment
122
+ provider and stack name.
123
+
124
+ Args:
125
+ date_start: The start date of the deployment.
126
+
127
+ Returns:
128
+ The ZenML stack that was deployed and registered or None if the
129
+ stack was not found.
130
+ """
@@ -0,0 +1,40 @@
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
+ """Functionality to deploy a ZenML stack to a cloud provider."""
15
+
16
+ from typing import Type
17
+
18
+ from zenml.enums import StackDeploymentProvider
19
+ from zenml.stack_deployments.aws_stack_deployment import (
20
+ AWSZenMLCloudStackDeployment,
21
+ )
22
+ from zenml.stack_deployments.stack_deployment import ZenMLCloudStackDeployment
23
+
24
+ STACK_DEPLOYMENT_PROVIDERS = {
25
+ StackDeploymentProvider.AWS: AWSZenMLCloudStackDeployment,
26
+ }
27
+
28
+
29
+ def get_stack_deployment_class(
30
+ provider: StackDeploymentProvider,
31
+ ) -> Type[ZenMLCloudStackDeployment]:
32
+ """Get the ZenML Cloud Stack Deployment class for the specified provider.
33
+
34
+ Args:
35
+ provider: The stack deployment provider.
36
+
37
+ Returns:
38
+ The ZenML Cloud Stack Deployment class for the specified provider.
39
+ """
40
+ return STACK_DEPLOYMENT_PROVIDERS[provider]
@@ -146,7 +146,7 @@ def _cli_wrapped_function(func: F) -> F:
146
146
  if _is_valid_optional_arg(arg_type):
147
147
  arg_type = arg_type.__args__[0]
148
148
  arg_name = _cli_arg_name(arg_name)
149
- if arg_type == bool:
149
+ if arg_type is bool:
150
150
  options.append(
151
151
  click.option(
152
152
  f"--{arg_name}",
@@ -13,7 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Pagination utilities."""
15
15
 
16
- from typing import Callable, List, TypeVar
16
+ from typing import Any, Callable, List, TypeVar
17
17
 
18
18
  from zenml.models import BaseIdentifiedResponse, Page
19
19
 
@@ -21,20 +21,22 @@ AnyResponse = TypeVar("AnyResponse", bound=BaseIdentifiedResponse) # type: igno
21
21
 
22
22
 
23
23
  def depaginate(
24
- list_method: Callable[..., Page[AnyResponse]],
24
+ list_method: Callable[..., Page[AnyResponse]], **kwargs: Any
25
25
  ) -> List[AnyResponse]:
26
26
  """Depaginate the results from a client or store method that returns pages.
27
27
 
28
28
  Args:
29
- list_method: The list method to wrap around.
29
+ list_method: The list method to depaginate.
30
+ **kwargs: Arguments for the list method.
30
31
 
31
32
  Returns:
32
33
  A list of the corresponding Response Models.
33
34
  """
34
- page = list_method()
35
+ page = list_method(**kwargs)
35
36
  items = list(page.items)
36
37
  while page.index < page.total_pages:
37
- page = list_method(page=page.index + 1)
38
+ kwargs["page"] = page.index + 1
39
+ page = list_method(**kwargs)
38
40
  items += list(page.items)
39
41
 
40
42
  return items