zenml-nightly 0.62.0.dev20240729__py3-none-any.whl → 0.63.0.dev20240731__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 (157) hide show
  1. README.md +1 -1
  2. RELEASE_NOTES.md +41 -0
  3. zenml/VERSION +1 -1
  4. zenml/actions/pipeline_run/pipeline_run_action.py +19 -17
  5. zenml/analytics/enums.py +4 -0
  6. zenml/cli/__init__.py +28 -15
  7. zenml/cli/base.py +1 -1
  8. zenml/cli/pipeline.py +54 -61
  9. zenml/cli/stack.py +6 -8
  10. zenml/client.py +232 -99
  11. zenml/config/compiler.py +14 -22
  12. zenml/config/pipeline_run_configuration.py +3 -0
  13. zenml/config/server_config.py +3 -0
  14. zenml/config/source.py +2 -1
  15. zenml/constants.py +2 -0
  16. zenml/enums.py +3 -0
  17. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +13 -4
  18. zenml/integrations/databricks/flavors/databricks_orchestrator_flavor.py +11 -2
  19. zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +19 -13
  20. zenml/models/__init__.py +26 -10
  21. zenml/models/v2/base/filter.py +32 -0
  22. zenml/models/v2/core/pipeline.py +73 -89
  23. zenml/models/v2/core/pipeline_build.py +15 -11
  24. zenml/models/v2/core/pipeline_deployment.py +56 -0
  25. zenml/models/v2/core/pipeline_run.py +52 -1
  26. zenml/models/v2/core/run_template.py +393 -0
  27. zenml/models/v2/misc/stack_deployment.py +5 -0
  28. zenml/new/pipelines/build_utils.py +34 -58
  29. zenml/new/pipelines/pipeline.py +17 -76
  30. zenml/new/pipelines/run_utils.py +12 -0
  31. zenml/post_execution/pipeline.py +1 -4
  32. zenml/service_connectors/service_connector_utils.py +4 -2
  33. zenml/stack_deployments/aws_stack_deployment.py +6 -5
  34. zenml/stack_deployments/azure_stack_deployment.py +118 -11
  35. zenml/stack_deployments/gcp_stack_deployment.py +12 -5
  36. zenml/stack_deployments/stack_deployment.py +6 -5
  37. zenml/steps/utils.py +0 -4
  38. zenml/utils/package_utils.py +39 -0
  39. zenml/zen_server/dashboard/assets/{404-B_YdvmwS.js → 404-CI13wQp4.js} +1 -1
  40. zenml/zen_server/dashboard/assets/{@reactflow-l_1hUr1S.js → @reactflow-DIYUhKYX.js} +1 -1
  41. zenml/zen_server/dashboard/assets/{@tanstack-DYiOyJUL.js → @tanstack-k96lU_C-.js} +4 -4
  42. zenml/zen_server/dashboard/assets/{AwarenessChannel-CFg5iX4Z.js → AwarenessChannel-BNg5uWgI.js} +1 -1
  43. zenml/zen_server/dashboard/assets/{CodeSnippet-Dvkx_82E.js → CodeSnippet-Cyp7f4dM.js} +2 -2
  44. zenml/zen_server/dashboard/assets/CollapsibleCard-Cu_A9W57.js +1 -0
  45. zenml/zen_server/dashboard/assets/{Commands-DoN1xrEq.js → Commands-DmQwTXjj.js} +1 -1
  46. zenml/zen_server/dashboard/assets/{CopyButton-Cr7xYEPb.js → CopyButton-B3sWVJ4Z.js} +1 -1
  47. zenml/zen_server/dashboard/assets/{CsvVizualization-Ck-nZ43m.js → CsvVizualization-BvqItd-O.js} +1 -1
  48. zenml/zen_server/dashboard/assets/{Error-kLtljEOM.js → Error-DbXCTGua.js} +1 -1
  49. zenml/zen_server/dashboard/assets/{ExecutionStatus-DguLLgTK.js → ExecutionStatus-9zM7eaLh.js} +1 -1
  50. zenml/zen_server/dashboard/assets/{Helpbox-BXUMP21n.js → Helpbox-BIiNc-uH.js} +1 -1
  51. zenml/zen_server/dashboard/assets/{Infobox-DSt0O-dm.js → Infobox-iv1Nu1A0.js} +1 -1
  52. zenml/zen_server/dashboard/assets/{InlineAvatar-xsrsIGE-.js → InlineAvatar-BvBtO2Dp.js} +1 -1
  53. zenml/zen_server/dashboard/assets/ProviderRadio-pSAvrGRS.js +1 -0
  54. zenml/zen_server/dashboard/assets/SearchField-CXoBknpt.js +1 -0
  55. zenml/zen_server/dashboard/assets/{SetPassword-BXGTWiwj.js → SetPassword-BOxpgh6N.js} +1 -1
  56. zenml/zen_server/dashboard/assets/{SuccessStep-DZC60t0x.js → SuccessStep-CTSKN2lp.js} +1 -1
  57. zenml/zen_server/dashboard/assets/Tick-Bnr2TpW6.js +1 -0
  58. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DGvwFWO1.js → UpdatePasswordSchemas-BeCeaRW5.js} +1 -1
  59. zenml/zen_server/dashboard/assets/chevron-down-D_ZlKMqH.js +1 -0
  60. zenml/zen_server/dashboard/assets/{cloud-only-C_yFCAkP.js → cloud-only-qelmY92E.js} +1 -1
  61. zenml/zen_server/dashboard/assets/components-DWe4cTjS.js +1 -0
  62. zenml/zen_server/dashboard/assets/dots-horizontal-BObFzD5l.js +1 -0
  63. zenml/zen_server/dashboard/assets/{index-BczVOqUf.js → index-KsTz2dHG.js} +5 -5
  64. zenml/zen_server/dashboard/assets/index-vfjX_fJV.css +1 -0
  65. zenml/zen_server/dashboard/assets/index.esm-CbHNSeVw.js +1 -0
  66. zenml/zen_server/dashboard/assets/{login-mutation-CrHrndTI.js → login-mutation-DRpbESS7.js} +1 -1
  67. zenml/zen_server/dashboard/assets/{not-found-DYa4pC-C.js → not-found-Dfx9hfkf.js} +1 -1
  68. zenml/zen_server/dashboard/assets/package-ClbU3KUi.js +1 -0
  69. zenml/zen_server/dashboard/assets/{page-uA5prJGY.js → page-399pVZHU.js} +1 -1
  70. zenml/zen_server/dashboard/assets/{page-1h_sD1jz.js → page-BoFtUD9H.js} +1 -1
  71. zenml/zen_server/dashboard/assets/{page-BDns21Iz.js → page-Btu39x7k.js} +1 -1
  72. zenml/zen_server/dashboard/assets/{page-BnaevhnB.js → page-BxiWdeyg.js} +1 -1
  73. zenml/zen_server/dashboard/assets/{page-1iL8aMqs.js → page-C176KxyB.js} +1 -1
  74. zenml/zen_server/dashboard/assets/page-C6tXXjnK.js +1 -0
  75. zenml/zen_server/dashboard/assets/{page-BkeAAYwp.js → page-CDgZmwxP.js} +1 -1
  76. zenml/zen_server/dashboard/assets/page-CP9obrnG.js +1 -0
  77. zenml/zen_server/dashboard/assets/{page-C6-UGEbH.js → page-CZe9GEBF.js} +1 -1
  78. zenml/zen_server/dashboard/assets/page-CaTOsNNw.js +1 -0
  79. zenml/zen_server/dashboard/assets/{page-CCNRIt_f.js → page-Cjn97HMv.js} +1 -1
  80. zenml/zen_server/dashboard/assets/page-CmXmB_5i.js +1 -0
  81. zenml/zen_server/dashboard/assets/page-CvGAOfad.js +1 -0
  82. zenml/zen_server/dashboard/assets/page-CzucfYPo.js +2 -0
  83. zenml/zen_server/dashboard/assets/{page-Bi-wtWiO.js → page-D0bbc-qr.js} +1 -1
  84. zenml/zen_server/dashboard/assets/page-DLEtD2ex.js +1 -0
  85. zenml/zen_server/dashboard/assets/{page-BhgCDInH.js → page-DVPxY5fT.js} +1 -1
  86. zenml/zen_server/dashboard/assets/{page-BkuQDIf-.js → page-DYBNGxJt.js} +1 -1
  87. zenml/zen_server/dashboard/assets/{page-8a4UMKXZ.js → page-DtpwnNXq.js} +1 -1
  88. zenml/zen_server/dashboard/assets/{page-B6h3iaHJ.js → page-DupV0aBd.js} +1 -1
  89. zenml/zen_server/dashboard/assets/page-EweAR81y.js +1 -0
  90. zenml/zen_server/dashboard/assets/{page-MFQyIJd3.js → page-f3jBVI5Z.js} +1 -1
  91. zenml/zen_server/dashboard/assets/{page-2grKx_MY.js → page-p2hLJdS2.js} +1 -1
  92. zenml/zen_server/dashboard/assets/page-w-YaL77M.js +9 -0
  93. zenml/zen_server/dashboard/assets/persist-BReKApOc.js +14 -0
  94. zenml/zen_server/dashboard/assets/plus-DOeLmm7C.js +1 -0
  95. zenml/zen_server/dashboard/assets/{stack-detail-query-Cficsl6d.js → stack-detail-query-Ck7j7BP_.js} +1 -1
  96. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-7d8xi1tS.js → update-server-settings-mutation-f3ZT7psb.js} +1 -1
  97. zenml/zen_server/dashboard/assets/{url-D7mAQGUM.js → url-rGEp5Umh.js} +1 -1
  98. zenml/zen_server/dashboard/assets/{zod-BhoGpZ63.js → zod-BtSyGx4C.js} +1 -1
  99. zenml/zen_server/dashboard/index.html +5 -5
  100. zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
  101. zenml/zen_server/dashboard_legacy/index.html +1 -1
  102. zenml/zen_server/dashboard_legacy/{precache-manifest.12246c7548e71e2c4438e496360de80c.js → precache-manifest.2fa6e528a6e7447caaf35dadfe7514bb.js} +4 -4
  103. zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
  104. zenml/zen_server/dashboard_legacy/static/js/{main.3b27024b.chunk.js → main.4aab7e98.chunk.js} +2 -2
  105. zenml/zen_server/dashboard_legacy/static/js/{main.3b27024b.chunk.js.map → main.4aab7e98.chunk.js.map} +1 -1
  106. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  107. zenml/zen_server/deploy/helm/README.md +2 -2
  108. zenml/zen_server/rbac/models.py +1 -0
  109. zenml/zen_server/rbac/utils.py +4 -0
  110. zenml/zen_server/routers/pipeline_builds_endpoints.py +2 -66
  111. zenml/zen_server/routers/pipeline_deployments_endpoints.py +2 -53
  112. zenml/zen_server/routers/pipelines_endpoints.py +1 -74
  113. zenml/zen_server/routers/run_templates_endpoints.py +212 -0
  114. zenml/zen_server/routers/workspaces_endpoints.py +79 -0
  115. zenml/zen_server/{pipeline_deployment → template_execution}/runner_entrypoint_configuration.py +1 -8
  116. zenml/zen_server/{pipeline_deployment → template_execution}/utils.py +214 -92
  117. zenml/zen_server/utils.py +2 -2
  118. zenml/zen_server/zen_server_api.py +2 -1
  119. zenml/zen_stores/migrations/versions/0.63.0_release.py +23 -0
  120. zenml/zen_stores/migrations/versions/7d1919bb1ef0_add_run_templates.py +100 -0
  121. zenml/zen_stores/migrations/versions/b59aa68fdb1f_simplify_pipelines.py +139 -0
  122. zenml/zen_stores/rest_zen_store.py +107 -36
  123. zenml/zen_stores/schemas/__init__.py +2 -0
  124. zenml/zen_stores/schemas/pipeline_build_schemas.py +3 -3
  125. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +29 -2
  126. zenml/zen_stores/schemas/pipeline_run_schemas.py +26 -3
  127. zenml/zen_stores/schemas/pipeline_schemas.py +29 -30
  128. zenml/zen_stores/schemas/run_template_schemas.py +264 -0
  129. zenml/zen_stores/schemas/step_run_schemas.py +11 -4
  130. zenml/zen_stores/sql_zen_store.py +364 -150
  131. zenml/zen_stores/template_utils.py +261 -0
  132. zenml/zen_stores/zen_store_interface.py +93 -20
  133. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.63.0.dev20240731.dist-info}/METADATA +2 -2
  134. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.63.0.dev20240731.dist-info}/RECORD +139 -129
  135. zenml/models/v2/core/pipeline_namespace.py +0 -113
  136. zenml/new/pipelines/deserialization_utils.py +0 -292
  137. zenml/zen_server/dashboard/assets/CollapsibleCard-opiuBHHc.js +0 -1
  138. zenml/zen_server/dashboard/assets/Pagination-C6X-mifw.js +0 -1
  139. zenml/zen_server/dashboard/assets/index-EpMIKgrI.css +0 -1
  140. zenml/zen_server/dashboard/assets/index-rK_Wuy2W.js +0 -1
  141. zenml/zen_server/dashboard/assets/index.esm-Corw4lXQ.js +0 -1
  142. zenml/zen_server/dashboard/assets/package-B3fWP-Dh.js +0 -1
  143. zenml/zen_server/dashboard/assets/page-5NCOHOsy.js +0 -1
  144. zenml/zen_server/dashboard/assets/page-Bq0YxkLV.js +0 -1
  145. zenml/zen_server/dashboard/assets/page-Bs2F4eoD.js +0 -2
  146. zenml/zen_server/dashboard/assets/page-CHNxpz3n.js +0 -1
  147. zenml/zen_server/dashboard/assets/page-DgorQFqi.js +0 -1
  148. zenml/zen_server/dashboard/assets/page-K8ebxVIs.js +0 -1
  149. zenml/zen_server/dashboard/assets/page-TgCF0P_U.js +0 -1
  150. zenml/zen_server/dashboard/assets/page-ZnCEe-eK.js +0 -9
  151. zenml/zen_server/dashboard/assets/persist-D7HJNBWx.js +0 -1
  152. zenml/zen_server/dashboard/assets/plus-C8WOyCzt.js +0 -1
  153. /zenml/zen_server/{pipeline_deployment → template_execution}/__init__.py +0 -0
  154. /zenml/zen_server/{pipeline_deployment → template_execution}/workload_manager_interface.py +0 -0
  155. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.63.0.dev20240731.dist-info}/LICENSE +0 -0
  156. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.63.0.dev20240731.dist-info}/WHEEL +0 -0
  157. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.63.0.dev20240731.dist-info}/entry_points.txt +0 -0
@@ -17,15 +17,11 @@ from zenml.client import Client
17
17
  from zenml.entrypoints.base_entrypoint_configuration import (
18
18
  BaseEntrypointConfiguration,
19
19
  )
20
- from zenml.logger import get_logger
21
20
  from zenml.new.pipelines.run_utils import (
22
21
  deploy_pipeline,
23
- get_placeholder_run,
24
22
  prepare_model_versions,
25
23
  )
26
24
 
27
- logger = get_logger(__name__)
28
-
29
25
 
30
26
  class RunnerEntrypointConfiguration(BaseEntrypointConfiguration):
31
27
  """Runner entrypoint configuration."""
@@ -37,12 +33,9 @@ class RunnerEntrypointConfiguration(BaseEntrypointConfiguration):
37
33
  to the entrypoint configuration.
38
34
  """
39
35
  deployment = self.load_deployment()
40
- placeholder_run = get_placeholder_run(deployment_id=deployment.id)
41
36
 
42
37
  stack = Client().active_stack
43
38
  assert deployment.stack and stack.id == deployment.stack.id
44
39
 
45
40
  prepare_model_versions(deployment=deployment)
46
- deploy_pipeline(
47
- deployment=deployment, stack=stack, placeholder_run=placeholder_run
48
- )
41
+ deploy_pipeline(deployment=deployment, stack=stack)
@@ -3,15 +3,19 @@
3
3
  import copy
4
4
  import hashlib
5
5
  import sys
6
- from typing import List, Optional, Set, Tuple
6
+ from typing import Any, Dict, List, Optional, Set, Tuple
7
7
  from uuid import UUID
8
8
 
9
9
  from fastapi import BackgroundTasks
10
10
  from packaging import version
11
11
 
12
+ from zenml.analytics.enums import AnalyticsEvent
13
+ from zenml.analytics.utils import track_handler
12
14
  from zenml.config.base_settings import BaseSettings
13
15
  from zenml.config.pipeline_configurations import PipelineConfiguration
14
- from zenml.config.pipeline_run_configuration import PipelineRunConfiguration
16
+ from zenml.config.pipeline_run_configuration import (
17
+ PipelineRunConfiguration,
18
+ )
15
19
  from zenml.config.step_configurations import Step, StepConfiguration
16
20
  from zenml.constants import (
17
21
  ENV_ZENML_ACTIVE_STACK_ID,
@@ -19,6 +23,7 @@ from zenml.constants import (
19
23
  )
20
24
  from zenml.enums import ExecutionStatus, StackComponentType, StoreType
21
25
  from zenml.integrations.utils import get_integration_for_module
26
+ from zenml.logger import get_logger
22
27
  from zenml.models import (
23
28
  CodeReferenceRequest,
24
29
  ComponentResponse,
@@ -27,62 +32,80 @@ from zenml.models import (
27
32
  PipelineDeploymentResponse,
28
33
  PipelineRunResponse,
29
34
  PipelineRunUpdate,
35
+ RunTemplateResponse,
30
36
  StackResponse,
31
37
  )
38
+ from zenml.new.pipelines.build_utils import compute_stack_checksum
32
39
  from zenml.new.pipelines.run_utils import (
33
40
  create_placeholder_run,
41
+ get_default_run_name,
34
42
  validate_run_config_is_runnable_from_server,
35
43
  validate_stack_is_runnable_from_server,
36
44
  )
37
45
  from zenml.stack.flavor import Flavor
38
- from zenml.utils import dict_utils, pydantic_utils, settings_utils
46
+ from zenml.utils import dict_utils, settings_utils
39
47
  from zenml.zen_server.auth import AuthContext
40
- from zenml.zen_server.pipeline_deployment.runner_entrypoint_configuration import (
48
+ from zenml.zen_server.template_execution.runner_entrypoint_configuration import (
41
49
  RunnerEntrypointConfiguration,
42
50
  )
43
51
  from zenml.zen_server.utils import server_config, workload_manager, zen_store
44
52
 
53
+ logger = get_logger(__name__)
54
+
45
55
  RUNNER_IMAGE_REPOSITORY = "zenml-runner"
46
56
 
47
57
 
48
- def run_pipeline(
49
- deployment: PipelineDeploymentResponse,
58
+ def run_template(
59
+ template: RunTemplateResponse,
50
60
  auth_context: AuthContext,
51
61
  background_tasks: Optional[BackgroundTasks] = None,
52
62
  run_config: Optional[PipelineRunConfiguration] = None,
53
63
  ) -> PipelineRunResponse:
54
- """Run a pipeline from an existing deployment.
64
+ """Run a pipeline from a template.
55
65
 
56
66
  Args:
57
- deployment: The pipeline deployment.
67
+ template: The template to run.
58
68
  auth_context: Authentication context.
59
69
  background_tasks: Background tasks.
60
70
  run_config: The run configuration.
61
71
 
62
72
  Raises:
63
- ValueError: If the deployment does not have an associated stack or
64
- build.
73
+ ValueError: If the template can not be run.
65
74
  RuntimeError: If the server URL is not set in the server configuration.
66
75
 
67
76
  Returns:
68
77
  ID of the new pipeline run.
69
78
  """
70
- build = deployment.build
71
- stack = deployment.stack
72
-
73
- if not build:
74
- raise ValueError("Unable to run deployment without associated build.")
79
+ if not template.runnable:
80
+ raise ValueError(
81
+ "This template can not be run because its associated deployment, "
82
+ "stack or build have been deleted."
83
+ )
75
84
 
76
- if not stack:
77
- raise ValueError("Unable to run deployment without associated stack.")
85
+ # Guaranteed by the `runnable` check above
86
+ build = template.build
87
+ assert build
88
+ stack = build.stack
89
+ assert stack
90
+
91
+ if build.stack_checksum and build.stack_checksum != compute_stack_checksum(
92
+ stack=stack
93
+ ):
94
+ raise ValueError(
95
+ f"The stack {stack.name} has been updated since it was used for "
96
+ "the run that is the base for this template. This means the Docker "
97
+ "images associated with this template most likely do not contain "
98
+ "the necessary requirements. Please create a new template from a "
99
+ "recent run on this stack."
100
+ )
78
101
 
79
102
  validate_stack_is_runnable_from_server(zen_store=zen_store(), stack=stack)
80
103
  if run_config:
81
104
  validate_run_config_is_runnable_from_server(run_config)
82
105
 
83
- deployment_request = apply_run_config(
84
- deployment=deployment,
85
- run_config=run_config or PipelineRunConfiguration(),
106
+ deployment_request = deployment_request_from_template(
107
+ template=template,
108
+ config=run_config or PipelineRunConfiguration(),
86
109
  user_id=auth_context.user.id,
87
110
  )
88
111
 
@@ -104,7 +127,7 @@ def run_pipeline(
104
127
  server_url = server_config().server_url
105
128
  if not server_url:
106
129
  raise RuntimeError(
107
- "The server URL is not set in the server configuration"
130
+ "The server URL is not set in the server configuration."
108
131
  )
109
132
  assert build.zenml_version
110
133
  zenml_version = build.zenml_version
@@ -128,66 +151,86 @@ def run_pipeline(
128
151
  assert placeholder_run
129
152
 
130
153
  def _task() -> None:
131
- try:
132
- pypi_requirements, apt_packages = get_requirements_for_stack(
133
- stack=stack
154
+ pypi_requirements, apt_packages = get_requirements_for_stack(
155
+ stack=stack
156
+ )
157
+
158
+ if build.python_version:
159
+ version_info = version.parse(build.python_version)
160
+ python_version = f"{version_info.major}.{version_info.minor}"
161
+ else:
162
+ python_version = (
163
+ f"{sys.version_info.major}.{sys.version_info.minor}"
134
164
  )
135
165
 
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
- )
166
+ dockerfile = generate_dockerfile(
167
+ pypi_requirements=pypi_requirements,
168
+ apt_packages=apt_packages,
169
+ zenml_version=zenml_version,
170
+ python_version=python_version,
171
+ )
143
172
 
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
- )
173
+ image_hash = generate_image_hash(dockerfile=dockerfile)
150
174
 
151
- image_hash = generate_image_hash(dockerfile=dockerfile)
175
+ runner_image = workload_manager().build_and_push_image(
176
+ workload_id=new_deployment.id,
177
+ dockerfile=dockerfile,
178
+ image_name=f"{RUNNER_IMAGE_REPOSITORY}:{image_hash}",
179
+ sync=True,
180
+ )
152
181
 
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
- )
182
+ workload_manager().log(
183
+ workload_id=new_deployment.id,
184
+ message="Starting pipeline run.",
185
+ )
186
+ workload_manager().run(
187
+ workload_id=new_deployment.id,
188
+ image=runner_image,
189
+ command=command,
190
+ arguments=args,
191
+ environment=environment,
192
+ timeout_in_seconds=30,
193
+ sync=True,
194
+ )
195
+ workload_manager().log(
196
+ workload_id=new_deployment.id,
197
+ message="Pipeline run started successfully.",
198
+ )
159
199
 
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(
200
+ def _task_with_analytics_and_error_handling() -> None:
201
+ with track_handler(
202
+ event=AnalyticsEvent.RUN_PIPELINE
203
+ ) as analytics_handler:
204
+ analytics_handler.metadata = get_pipeline_run_analytics_metadata(
205
+ deployment=new_deployment,
206
+ stack=stack,
207
+ template_id=template.id,
179
208
  run_id=placeholder_run.id,
180
- run_update=PipelineRunUpdate(status=ExecutionStatus.FAILED),
181
209
  )
182
- raise
210
+
211
+ try:
212
+ _task()
213
+ except Exception:
214
+ logger.exception(
215
+ "Failed to run template %s, run ID: %s",
216
+ str(template.id),
217
+ str(placeholder_run.id),
218
+ )
219
+ zen_store().update_run(
220
+ run_id=placeholder_run.id,
221
+ run_update=PipelineRunUpdate(
222
+ status=ExecutionStatus.FAILED
223
+ ),
224
+ )
225
+ raise
183
226
 
184
227
  if background_tasks:
185
- background_tasks.add_task(_task)
228
+ background_tasks.add_task(_task_with_analytics_and_error_handling)
186
229
  else:
187
230
  # Run synchronously if no background tasks were passed. This is probably
188
231
  # when coming from a trigger which itself is already running in the
189
232
  # background
190
- _task()
233
+ _task_with_analytics_and_error_handling()
191
234
 
192
235
  return placeholder_run
193
236
 
@@ -332,47 +375,77 @@ def generate_dockerfile(
332
375
  return "\n".join(lines)
333
376
 
334
377
 
335
- def apply_run_config(
336
- deployment: "PipelineDeploymentResponse",
337
- run_config: "PipelineRunConfiguration",
378
+ def deployment_request_from_template(
379
+ template: RunTemplateResponse,
380
+ config: PipelineRunConfiguration,
338
381
  user_id: UUID,
339
382
  ) -> "PipelineDeploymentRequest":
340
- """Apply run configuration to a deployment.
383
+ """Generate a deployment request from a template.
341
384
 
342
385
  Args:
343
- deployment: The deployment to which to apply the config.
344
- run_config: The run configuration to apply.
345
- user_id: The ID of the user that wants to run the deployment.
386
+ template: The template from which to create the deployment request.
387
+ config: The run configuration.
388
+ user_id: ID of the user that is trying to run the template.
389
+
390
+ Raises:
391
+ ValueError: If the run configuration is missing step parameters.
346
392
 
347
393
  Returns:
348
- The updated deployment.
394
+ The generated deployment request.
349
395
  """
350
- pipeline_updates = run_config.model_dump(
351
- exclude_none=True, include=set(PipelineConfiguration.model_fields)
396
+ deployment = template.source_deployment
397
+ assert deployment
398
+ pipeline_configuration = PipelineConfiguration(
399
+ **config.model_dump(
400
+ include=set(PipelineConfiguration.model_fields),
401
+ exclude={"name", "parameters"},
402
+ ),
403
+ name=deployment.pipeline_configuration.name,
404
+ parameters=deployment.pipeline_configuration.parameters,
352
405
  )
353
406
 
354
- pipeline_configuration = pydantic_utils.update_model(
355
- deployment.pipeline_configuration, update=pipeline_updates
356
- )
357
- pipeline_configuration_dict = pipeline_configuration.model_dump(
358
- exclude_none=True
407
+ step_config_dict_base = pipeline_configuration.model_dump(
408
+ exclude={"name", "parameters"}
359
409
  )
360
410
  steps = {}
361
411
  for invocation_id, step in deployment.step_configurations.items():
362
- step_config_dict = dict_utils.recursive_update(
363
- copy.deepcopy(pipeline_configuration_dict),
364
- update=step.config.model_dump(exclude_none=True),
365
- )
366
- step_config = StepConfiguration.model_validate(step_config_dict)
367
-
368
- if update := run_config.steps.get(invocation_id):
412
+ step_config_dict = {
413
+ **copy.deepcopy(step_config_dict_base),
414
+ **step.config.model_dump(
415
+ # TODO: Maybe we need to make some of these configurable via
416
+ # yaml as well, e.g. the lazy loaders?
417
+ include={
418
+ "name",
419
+ "caching_parameters",
420
+ "external_input_artifacts",
421
+ "model_artifacts_or_metadata",
422
+ "client_lazy_loaders",
423
+ "outputs",
424
+ }
425
+ ),
426
+ }
427
+
428
+ required_parameters = set(step.config.parameters)
429
+ configured_parameters = set()
430
+
431
+ if update := config.steps.get(invocation_id):
369
432
  update_dict = update.model_dump()
370
433
  # Get rid of deprecated name to prevent overriding the step name
371
434
  # with `None`.
372
435
  update_dict.pop("name", None)
373
- step_config = pydantic_utils.update_model(
374
- step_config, update=update_dict
436
+ configured_parameters = set(update.parameters)
437
+ step_config_dict = dict_utils.recursive_update(
438
+ step_config_dict, update=update_dict
375
439
  )
440
+
441
+ if configured_parameters != required_parameters:
442
+ missing_parameters = required_parameters - configured_parameters
443
+ raise ValueError(
444
+ "Run configuration is missing missing the following required "
445
+ f"parameters for step {step.config.name}: {missing_parameters}."
446
+ )
447
+
448
+ step_config = StepConfiguration.model_validate(step_config_dict)
376
449
  steps[invocation_id] = Step(spec=step.spec, config=step_config)
377
450
 
378
451
  code_reference_request = None
@@ -389,7 +462,8 @@ def apply_run_config(
389
462
  deployment_request = PipelineDeploymentRequest(
390
463
  user=user_id,
391
464
  workspace=deployment.workspace.id,
392
- run_name_template=run_config.run_name or deployment.run_name_template,
465
+ run_name_template=config.run_name
466
+ or get_default_run_name(pipeline_name=pipeline_configuration.name),
393
467
  pipeline_configuration=pipeline_configuration,
394
468
  step_configurations=steps,
395
469
  client_environment={},
@@ -400,6 +474,54 @@ def apply_run_config(
400
474
  build=deployment.build.id,
401
475
  schedule=None,
402
476
  code_reference=code_reference_request,
477
+ template=template.id,
478
+ pipeline_version_hash=deployment.pipeline_version_hash,
479
+ pipeline_spec=deployment.pipeline_spec,
403
480
  )
404
481
 
405
482
  return deployment_request
483
+
484
+
485
+ def get_pipeline_run_analytics_metadata(
486
+ deployment: "PipelineDeploymentResponse",
487
+ stack: StackResponse,
488
+ template_id: UUID,
489
+ run_id: UUID,
490
+ ) -> Dict[str, Any]:
491
+ """Get metadata for the pipeline run analytics event.
492
+
493
+ Args:
494
+ deployment: The deployment of the run.
495
+ stack: The stack on which the run will happen.
496
+ template_id: ID of the template from which the run was started.
497
+ run_id: ID of the run.
498
+
499
+ Returns:
500
+ The analytics metadata.
501
+ """
502
+ custom_materializer = False
503
+ for step in deployment.step_configurations.values():
504
+ for output in step.config.outputs.values():
505
+ for source in output.materializer_source:
506
+ if not source.is_internal:
507
+ custom_materializer = True
508
+
509
+ assert deployment.user
510
+ stack_creator = stack.user
511
+ own_stack = stack_creator and stack_creator.id == deployment.user.id
512
+
513
+ stack_metadata = {
514
+ component_type.value: component_list[0].flavor
515
+ for component_type, component_list in stack.components.items()
516
+ }
517
+
518
+ return {
519
+ "store_type": "rest", # This method is called from within a REST endpoint
520
+ **stack_metadata,
521
+ "total_steps": len(deployment.step_configurations),
522
+ "schedule": deployment.schedule is not None,
523
+ "custom_materializer": custom_materializer,
524
+ "own_stack": own_stack,
525
+ "pipeline_run_id": str(run_id),
526
+ "template_id": str(template_id),
527
+ }
zenml/zen_server/utils.py CHANGED
@@ -47,10 +47,10 @@ from zenml.zen_server.exceptions import http_exception_from_error
47
47
  from zenml.zen_server.feature_gate.feature_gate_interface import (
48
48
  FeatureGateInterface,
49
49
  )
50
- from zenml.zen_server.pipeline_deployment.workload_manager_interface import (
50
+ from zenml.zen_server.rbac.rbac_interface import RBACInterface
51
+ from zenml.zen_server.template_execution.workload_manager_interface import (
51
52
  WorkloadManagerInterface,
52
53
  )
53
- from zenml.zen_server.rbac.rbac_interface import RBACInterface
54
54
  from zenml.zen_stores.sql_zen_store import SqlZenStore
55
55
 
56
56
  logger = get_logger(__name__)
@@ -55,6 +55,7 @@ from zenml.zen_server.routers import (
55
55
  pipelines_endpoints,
56
56
  plugin_endpoints,
57
57
  run_metadata_endpoints,
58
+ run_templates_endpoints,
58
59
  runs_endpoints,
59
60
  schedule_endpoints,
60
61
  secrets_endpoints,
@@ -278,11 +279,11 @@ app.include_router(model_versions_endpoints.router)
278
279
  app.include_router(model_versions_endpoints.model_version_artifacts_router)
279
280
  app.include_router(model_versions_endpoints.model_version_pipeline_runs_router)
280
281
  app.include_router(pipelines_endpoints.router)
281
- app.include_router(pipelines_endpoints.namespace_router)
282
282
  app.include_router(pipeline_builds_endpoints.router)
283
283
  app.include_router(pipeline_deployments_endpoints.router)
284
284
  app.include_router(runs_endpoints.router)
285
285
  app.include_router(run_metadata_endpoints.router)
286
+ app.include_router(run_templates_endpoints.router)
286
287
  app.include_router(schedule_endpoints.router)
287
288
  app.include_router(secrets_endpoints.router)
288
289
  app.include_router(secrets_endpoints.op_router)
@@ -0,0 +1,23 @@
1
+ """Release [0.63.0].
2
+
3
+ Revision ID: 0.63.0
4
+ Revises: 7d1919bb1ef0
5
+ Create Date: 2024-07-29 16:59:59.891939
6
+
7
+ """
8
+
9
+ # revision identifiers, used by Alembic.
10
+ revision = "0.63.0"
11
+ down_revision = "7d1919bb1ef0"
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,100 @@
1
+ """Add run templates [7d1919bb1ef0].
2
+
3
+ Revision ID: 7d1919bb1ef0
4
+ Revises: b59aa68fdb1f
5
+ Create Date: 2024-07-22 11:20:00.544451
6
+
7
+ """
8
+
9
+ import sqlalchemy as sa
10
+ import sqlmodel
11
+ from alembic import op
12
+ from sqlalchemy.dialects import mysql
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision = "7d1919bb1ef0"
16
+ down_revision = "b59aa68fdb1f"
17
+ branch_labels = None
18
+ depends_on = None
19
+
20
+
21
+ def upgrade() -> None:
22
+ """Upgrade database schema and/or data, creating a new revision."""
23
+ # ### commands auto generated by Alembic - please adjust! ###
24
+ op.create_table(
25
+ "run_template",
26
+ sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
27
+ sa.Column("created", sa.DateTime(), nullable=False),
28
+ sa.Column("updated", sa.DateTime(), nullable=False),
29
+ sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
30
+ sa.Column(
31
+ "description",
32
+ sa.String(length=16777215).with_variant(mysql.MEDIUMTEXT, "mysql"),
33
+ nullable=True,
34
+ ),
35
+ sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True),
36
+ sa.Column(
37
+ "workspace_id", sqlmodel.sql.sqltypes.GUID(), nullable=False
38
+ ),
39
+ sa.Column(
40
+ "source_deployment_id", sqlmodel.sql.sqltypes.GUID(), nullable=True
41
+ ),
42
+ sa.ForeignKeyConstraint(
43
+ ["source_deployment_id"],
44
+ ["pipeline_deployment.id"],
45
+ name="fk_run_template_source_deployment_id_pipeline_deployment",
46
+ ondelete="SET NULL",
47
+ ),
48
+ sa.ForeignKeyConstraint(
49
+ ["user_id"],
50
+ ["user.id"],
51
+ name="fk_run_template_user_id_user",
52
+ ondelete="SET NULL",
53
+ ),
54
+ sa.ForeignKeyConstraint(
55
+ ["workspace_id"],
56
+ ["workspace.id"],
57
+ name="fk_run_template_workspace_id_workspace",
58
+ ondelete="CASCADE",
59
+ ),
60
+ sa.PrimaryKeyConstraint("id"),
61
+ sa.UniqueConstraint(
62
+ "name", "workspace_id", name="unique_template_name_in_workspace"
63
+ ),
64
+ )
65
+ with op.batch_alter_table("pipeline_build", schema=None) as batch_op:
66
+ batch_op.add_column(
67
+ sa.Column(
68
+ "stack_checksum",
69
+ sqlmodel.sql.sqltypes.AutoString(),
70
+ nullable=True,
71
+ )
72
+ )
73
+ batch_op.drop_column("template_deployment_id")
74
+
75
+ with op.batch_alter_table("pipeline_deployment", schema=None) as batch_op:
76
+ batch_op.add_column(
77
+ sa.Column(
78
+ "template_id", sqlmodel.sql.sqltypes.GUID(), nullable=True
79
+ )
80
+ )
81
+
82
+ # ### end Alembic commands ###
83
+
84
+
85
+ def downgrade() -> None:
86
+ """Downgrade database schema and/or data back to the previous revision."""
87
+ # ### commands auto generated by Alembic - please adjust! ###
88
+ with op.batch_alter_table("pipeline_deployment", schema=None) as batch_op:
89
+ batch_op.drop_column("template_id")
90
+
91
+ with op.batch_alter_table("pipeline_build", schema=None) as batch_op:
92
+ batch_op.add_column(
93
+ sa.Column(
94
+ "template_deployment_id", sa.CHAR(length=32), nullable=True
95
+ )
96
+ )
97
+ batch_op.drop_column("stack_checksum")
98
+
99
+ op.drop_table("run_template")
100
+ # ### end Alembic commands ###