zenml-nightly 0.75.0.dev20250311__py3-none-any.whl → 0.75.0.dev20250313__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 (163) hide show
  1. zenml/VERSION +1 -1
  2. zenml/__init__.py +2 -0
  3. zenml/analytics/context.py +7 -0
  4. zenml/artifacts/utils.py +0 -2
  5. zenml/cli/login.py +6 -0
  6. zenml/cli/model.py +7 -15
  7. zenml/cli/secret.py +47 -44
  8. zenml/cli/service_connectors.py +0 -1
  9. zenml/cli/stack.py +0 -1
  10. zenml/cli/tag.py +3 -5
  11. zenml/cli/utils.py +25 -23
  12. zenml/cli/workspace.py +79 -5
  13. zenml/client.py +618 -348
  14. zenml/config/global_config.py +16 -3
  15. zenml/config/pipeline_configurations.py +3 -2
  16. zenml/config/pipeline_run_configuration.py +2 -1
  17. zenml/config/secret_reference_mixin.py +1 -1
  18. zenml/constants.py +1 -3
  19. zenml/enums.py +0 -7
  20. zenml/event_hub/event_hub.py +3 -1
  21. zenml/exceptions.py +0 -24
  22. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +5 -3
  23. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +1 -4
  24. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +1 -4
  25. zenml/integrations/mlflow/steps/mlflow_registry.py +1 -1
  26. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
  27. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +3 -3
  28. zenml/model/model.py +8 -8
  29. zenml/models/__init__.py +18 -1
  30. zenml/models/v2/base/base.py +0 -5
  31. zenml/models/v2/base/filter.py +1 -1
  32. zenml/models/v2/base/scoped.py +104 -121
  33. zenml/models/v2/core/api_key.py +1 -1
  34. zenml/models/v2/core/artifact.py +31 -18
  35. zenml/models/v2/core/artifact_version.py +42 -25
  36. zenml/models/v2/core/component.py +22 -33
  37. zenml/models/v2/core/device.py +3 -2
  38. zenml/models/v2/core/event_source.py +2 -2
  39. zenml/models/v2/core/flavor.py +19 -47
  40. zenml/models/v2/core/logs.py +1 -2
  41. zenml/models/v2/core/model.py +7 -4
  42. zenml/models/v2/core/model_version.py +36 -27
  43. zenml/models/v2/core/pipeline.py +1 -1
  44. zenml/models/v2/core/pipeline_build.py +18 -0
  45. zenml/models/v2/core/pipeline_run.py +5 -13
  46. zenml/models/v2/core/run_template.py +1 -2
  47. zenml/models/v2/core/schedule.py +0 -9
  48. zenml/models/v2/core/secret.py +93 -127
  49. zenml/models/v2/core/server_settings.py +2 -2
  50. zenml/models/v2/core/service.py +43 -12
  51. zenml/models/v2/core/service_connector.py +14 -16
  52. zenml/models/v2/core/stack.py +24 -26
  53. zenml/models/v2/core/step_run.py +3 -15
  54. zenml/models/v2/core/tag.py +41 -15
  55. zenml/models/v2/core/user.py +19 -2
  56. zenml/models/v2/misc/statistics.py +45 -0
  57. zenml/models/v2/misc/tag.py +27 -0
  58. zenml/orchestrators/cache_utils.py +1 -1
  59. zenml/orchestrators/input_utils.py +1 -0
  60. zenml/orchestrators/step_launcher.py +0 -1
  61. zenml/orchestrators/step_run_utils.py +0 -2
  62. zenml/orchestrators/step_runner.py +10 -1
  63. zenml/pipelines/build_utils.py +4 -2
  64. zenml/pipelines/pipeline_decorator.py +3 -2
  65. zenml/pipelines/pipeline_definition.py +4 -5
  66. zenml/pipelines/run_utils.py +3 -3
  67. zenml/service_connectors/service_connector.py +0 -7
  68. zenml/service_connectors/service_connector_utils.py +0 -1
  69. zenml/stack/authentication_mixin.py +1 -1
  70. zenml/stack/flavor.py +3 -14
  71. zenml/stack/stack_component.py +1 -5
  72. zenml/steps/step_context.py +19 -0
  73. zenml/utils/string_utils.py +1 -1
  74. zenml/utils/tag_utils.py +642 -0
  75. zenml/zen_server/cloud_utils.py +21 -0
  76. zenml/zen_server/exceptions.py +0 -6
  77. zenml/zen_server/rbac/endpoint_utils.py +134 -46
  78. zenml/zen_server/rbac/models.py +65 -3
  79. zenml/zen_server/rbac/rbac_interface.py +9 -0
  80. zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
  81. zenml/zen_server/rbac/utils.py +156 -29
  82. zenml/zen_server/rbac/zenml_cloud_rbac.py +43 -11
  83. zenml/zen_server/routers/actions_endpoints.py +3 -5
  84. zenml/zen_server/routers/artifact_endpoint.py +0 -5
  85. zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
  86. zenml/zen_server/routers/auth_endpoints.py +22 -7
  87. zenml/zen_server/routers/code_repositories_endpoints.py +56 -3
  88. zenml/zen_server/routers/devices_endpoints.py +0 -4
  89. zenml/zen_server/routers/event_source_endpoints.py +0 -5
  90. zenml/zen_server/routers/flavors_endpoints.py +0 -5
  91. zenml/zen_server/routers/logs_endpoints.py +0 -1
  92. zenml/zen_server/routers/model_versions_endpoints.py +102 -23
  93. zenml/zen_server/routers/models_endpoints.py +51 -68
  94. zenml/zen_server/routers/pipeline_builds_endpoints.py +58 -4
  95. zenml/zen_server/routers/pipeline_deployments_endpoints.py +58 -4
  96. zenml/zen_server/routers/pipelines_endpoints.py +73 -4
  97. zenml/zen_server/routers/plugin_endpoints.py +0 -1
  98. zenml/zen_server/routers/run_metadata_endpoints.py +99 -0
  99. zenml/zen_server/routers/run_templates_endpoints.py +66 -3
  100. zenml/zen_server/routers/runs_endpoints.py +60 -8
  101. zenml/zen_server/routers/schedule_endpoints.py +69 -6
  102. zenml/zen_server/routers/secrets_endpoints.py +40 -4
  103. zenml/zen_server/routers/server_endpoints.py +53 -1
  104. zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
  105. zenml/zen_server/routers/service_connectors_endpoints.py +96 -14
  106. zenml/zen_server/routers/service_endpoints.py +20 -7
  107. zenml/zen_server/routers/stack_components_endpoints.py +68 -7
  108. zenml/zen_server/routers/stacks_endpoints.py +98 -7
  109. zenml/zen_server/routers/steps_endpoints.py +17 -11
  110. zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
  111. zenml/zen_server/routers/tags_endpoints.py +6 -17
  112. zenml/zen_server/routers/triggers_endpoints.py +5 -8
  113. zenml/zen_server/routers/users_endpoints.py +47 -12
  114. zenml/zen_server/routers/workspaces_endpoints.py +56 -1285
  115. zenml/zen_server/template_execution/utils.py +5 -4
  116. zenml/zen_server/utils.py +21 -0
  117. zenml/zen_server/zen_server_api.py +4 -0
  118. zenml/zen_stores/base_zen_store.py +29 -44
  119. zenml/zen_stores/migrations/versions/0392807467dc_add_build_duration.py +34 -0
  120. zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
  121. zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
  122. zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
  123. zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
  124. zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
  125. zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
  126. zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
  127. zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
  128. zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
  129. zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
  130. zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
  131. zenml/zen_stores/rest_zen_store.py +172 -171
  132. zenml/zen_stores/schemas/action_schemas.py +8 -1
  133. zenml/zen_stores/schemas/api_key_schemas.py +8 -1
  134. zenml/zen_stores/schemas/artifact_schemas.py +28 -1
  135. zenml/zen_stores/schemas/code_repository_schemas.py +8 -1
  136. zenml/zen_stores/schemas/component_schemas.py +9 -14
  137. zenml/zen_stores/schemas/event_source_schemas.py +8 -1
  138. zenml/zen_stores/schemas/flavor_schemas.py +14 -20
  139. zenml/zen_stores/schemas/model_schemas.py +3 -0
  140. zenml/zen_stores/schemas/pipeline_build_schemas.py +4 -0
  141. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +3 -1
  142. zenml/zen_stores/schemas/pipeline_run_schemas.py +0 -3
  143. zenml/zen_stores/schemas/run_template_schemas.py +8 -4
  144. zenml/zen_stores/schemas/schedule_schema.py +9 -14
  145. zenml/zen_stores/schemas/secret_schemas.py +15 -25
  146. zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
  147. zenml/zen_stores/schemas/service_schemas.py +0 -1
  148. zenml/zen_stores/schemas/stack_schemas.py +12 -15
  149. zenml/zen_stores/schemas/step_run_schemas.py +7 -8
  150. zenml/zen_stores/schemas/tag_schemas.py +30 -2
  151. zenml/zen_stores/schemas/trigger_schemas.py +8 -1
  152. zenml/zen_stores/schemas/user_schemas.py +24 -2
  153. zenml/zen_stores/schemas/utils.py +16 -0
  154. zenml/zen_stores/schemas/workspace_schemas.py +7 -25
  155. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
  156. zenml/zen_stores/sql_zen_store.py +2905 -2280
  157. zenml/zen_stores/template_utils.py +1 -1
  158. zenml/zen_stores/zen_store_interface.py +82 -58
  159. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/METADATA +1 -1
  160. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/RECORD +163 -149
  161. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/LICENSE +0 -0
  162. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/WHEEL +0 -0
  163. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/entry_points.txt +0 -0
@@ -13,7 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for run templates."""
15
15
 
16
- from typing import Optional
16
+ from typing import Optional, Union
17
17
  from uuid import UUID
18
18
 
19
19
  from fastapi import APIRouter, BackgroundTasks, Depends, Security
@@ -26,12 +26,14 @@ from zenml.models import (
26
26
  Page,
27
27
  PipelineRunResponse,
28
28
  RunTemplateFilter,
29
+ RunTemplateRequest,
29
30
  RunTemplateResponse,
30
31
  RunTemplateUpdate,
31
32
  )
32
33
  from zenml.zen_server.auth import AuthContext, authorize
33
34
  from zenml.zen_server.exceptions import error_response
34
35
  from zenml.zen_server.rbac.endpoint_utils import (
36
+ verify_permissions_and_create_entity,
35
37
  verify_permissions_and_delete_entity,
36
38
  verify_permissions_and_get_entity,
37
39
  verify_permissions_and_list_entities,
@@ -39,6 +41,9 @@ from zenml.zen_server.rbac.endpoint_utils import (
39
41
  )
40
42
  from zenml.zen_server.rbac.models import Action, ResourceType
41
43
  from zenml.zen_server.rbac.utils import verify_permission
44
+ from zenml.zen_server.routers.workspaces_endpoints import (
45
+ router as workspace_router,
46
+ )
42
47
  from zenml.zen_server.utils import (
43
48
  handle_exceptions,
44
49
  make_dependable,
@@ -53,15 +58,61 @@ router = APIRouter(
53
58
  )
54
59
 
55
60
 
61
+ @router.post(
62
+ "",
63
+ responses={401: error_response, 409: error_response, 422: error_response},
64
+ )
65
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
66
+ # and can be removed after the migration
67
+ @workspace_router.post(
68
+ "/{workspace_name_or_id}" + RUN_TEMPLATES,
69
+ responses={401: error_response, 409: error_response, 422: error_response},
70
+ deprecated=True,
71
+ tags=["run_templates"],
72
+ )
73
+ @handle_exceptions
74
+ def create_run_template(
75
+ run_template: RunTemplateRequest,
76
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
77
+ _: AuthContext = Security(authorize),
78
+ ) -> RunTemplateResponse:
79
+ """Create a run template.
80
+
81
+ Args:
82
+ run_template: Run template to create.
83
+ workspace_name_or_id: Optional name or ID of the workspace.
84
+
85
+ Returns:
86
+ The created run template.
87
+ """
88
+ if workspace_name_or_id:
89
+ workspace = zen_store().get_workspace(workspace_name_or_id)
90
+ run_template.workspace = workspace.id
91
+
92
+ return verify_permissions_and_create_entity(
93
+ request_model=run_template,
94
+ create_method=zen_store().create_run_template,
95
+ )
96
+
97
+
56
98
  @router.get(
57
99
  "",
58
100
  responses={401: error_response, 404: error_response, 422: error_response},
59
101
  )
102
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
103
+ # and can be removed after the migration
104
+ @workspace_router.get(
105
+ "/{workspace_name_or_id}" + RUN_TEMPLATES,
106
+ responses={401: error_response, 404: error_response, 422: error_response},
107
+ deprecated=True,
108
+ tags=["run_templates"],
109
+ )
60
110
  @handle_exceptions
61
111
  def list_run_templates(
62
112
  filter_model: RunTemplateFilter = Depends(
63
113
  make_dependable(RunTemplateFilter)
64
114
  ),
115
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
65
116
  hydrate: bool = False,
66
117
  _: AuthContext = Security(authorize),
67
118
  ) -> Page[RunTemplateResponse]:
@@ -70,12 +121,16 @@ def list_run_templates(
70
121
  Args:
71
122
  filter_model: Filter model used for pagination, sorting,
72
123
  filtering.
124
+ workspace_name_or_id: Optional name or ID of the workspace.
73
125
  hydrate: Flag deciding whether to hydrate the output model(s)
74
126
  by including metadata fields in the response.
75
127
 
76
128
  Returns:
77
129
  Page of run templates.
78
130
  """
131
+ if workspace_name_or_id:
132
+ filter_model.workspace = workspace_name_or_id
133
+
79
134
  return verify_permissions_and_list_entities(
80
135
  filter_model=filter_model,
81
136
  resource_type=ResourceType.RUN_TEMPLATE,
@@ -189,19 +244,27 @@ if server_config().workload_manager_enabled:
189
244
  """
190
245
  from zenml.zen_server.template_execution.utils import run_template
191
246
 
192
- with track_handler(event=AnalyticsEvent.EXECUTED_RUN_TEMPLATE):
247
+ with track_handler(
248
+ event=AnalyticsEvent.EXECUTED_RUN_TEMPLATE,
249
+ ) as analytics_handler:
193
250
  template = verify_permissions_and_get_entity(
194
251
  id=template_id,
195
252
  get_method=zen_store().get_run_template,
196
253
  hydrate=True,
197
254
  )
255
+ analytics_handler.metadata = {
256
+ "workspace_id": template.workspace.id,
257
+ }
198
258
 
199
259
  verify_permission(
200
260
  resource_type=ResourceType.PIPELINE_DEPLOYMENT,
201
261
  action=Action.CREATE,
262
+ workspace_id=template.workspace.id,
202
263
  )
203
264
  verify_permission(
204
- resource_type=ResourceType.PIPELINE_RUN, action=Action.CREATE
265
+ resource_type=ResourceType.PIPELINE_RUN,
266
+ action=Action.CREATE,
267
+ workspace_id=template.workspace.id,
205
268
  )
206
269
 
207
270
  return run_template(
@@ -13,7 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for pipeline runs."""
15
15
 
16
- from typing import Any, Dict
16
+ from typing import Any, Dict, Optional, Tuple, Union
17
17
  from uuid import UUID
18
18
 
19
19
  from fastapi import APIRouter, Depends, Security
@@ -32,6 +32,7 @@ from zenml.logger import get_logger
32
32
  from zenml.models import (
33
33
  Page,
34
34
  PipelineRunFilter,
35
+ PipelineRunRequest,
35
36
  PipelineRunResponse,
36
37
  PipelineRunUpdate,
37
38
  StepRunFilter,
@@ -42,11 +43,17 @@ from zenml.zen_server.exceptions import error_response
42
43
  from zenml.zen_server.rbac.endpoint_utils import (
43
44
  verify_permissions_and_delete_entity,
44
45
  verify_permissions_and_get_entity,
46
+ verify_permissions_and_get_or_create_entity,
45
47
  verify_permissions_and_list_entities,
46
48
  verify_permissions_and_update_entity,
47
49
  )
48
50
  from zenml.zen_server.rbac.models import Action, ResourceType
49
- from zenml.zen_server.rbac.utils import verify_permission_for_model
51
+ from zenml.zen_server.rbac.utils import (
52
+ verify_permission_for_model,
53
+ )
54
+ from zenml.zen_server.routers.workspaces_endpoints import (
55
+ router as workspace_router,
56
+ )
50
57
  from zenml.zen_server.utils import (
51
58
  handle_exceptions,
52
59
  make_dependable,
@@ -63,16 +70,62 @@ router = APIRouter(
63
70
  logger = get_logger(__name__)
64
71
 
65
72
 
73
+ @router.post(
74
+ "",
75
+ responses={401: error_response, 409: error_response, 422: error_response},
76
+ )
77
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
78
+ # and can be removed after the migration
79
+ @workspace_router.post(
80
+ "/{workspace_name_or_id}" + RUNS,
81
+ responses={401: error_response, 409: error_response, 422: error_response},
82
+ deprecated=True,
83
+ tags=["runs"],
84
+ )
85
+ @handle_exceptions
86
+ def get_or_create_pipeline_run(
87
+ pipeline_run: PipelineRunRequest,
88
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
89
+ _: AuthContext = Security(authorize),
90
+ ) -> Tuple[PipelineRunResponse, bool]:
91
+ """Get or create a pipeline run.
92
+
93
+ Args:
94
+ pipeline_run: Pipeline run to create.
95
+ workspace_name_or_id: Optional name or ID of the workspace.
96
+
97
+ Returns:
98
+ The pipeline run and a boolean indicating whether the run was created
99
+ or not.
100
+ """
101
+ if workspace_name_or_id:
102
+ workspace = zen_store().get_workspace(workspace_name_or_id)
103
+ pipeline_run.workspace = workspace.id
104
+
105
+ return verify_permissions_and_get_or_create_entity(
106
+ request_model=pipeline_run,
107
+ get_or_create_method=zen_store().get_or_create_run,
108
+ )
109
+
110
+
66
111
  @router.get(
67
112
  "",
68
- response_model=Page[PipelineRunResponse],
69
113
  responses={401: error_response, 404: error_response, 422: error_response},
70
114
  )
115
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
116
+ # and can be removed after the migration
117
+ @workspace_router.get(
118
+ "/{workspace_name_or_id}" + RUNS,
119
+ responses={401: error_response, 404: error_response, 422: error_response},
120
+ deprecated=True,
121
+ tags=["runs"],
122
+ )
71
123
  @handle_exceptions
72
124
  def list_runs(
73
125
  runs_filter_model: PipelineRunFilter = Depends(
74
126
  make_dependable(PipelineRunFilter)
75
127
  ),
128
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
76
129
  hydrate: bool = False,
77
130
  _: AuthContext = Security(authorize),
78
131
  ) -> Page[PipelineRunResponse]:
@@ -80,12 +133,16 @@ def list_runs(
80
133
 
81
134
  Args:
82
135
  runs_filter_model: Filter model used for pagination, sorting, filtering.
136
+ workspace_name_or_id: Optional name or ID of the workspace.
83
137
  hydrate: Flag deciding whether to hydrate the output model(s)
84
138
  by including metadata fields in the response.
85
139
 
86
140
  Returns:
87
141
  The pipeline runs according to query filters.
88
142
  """
143
+ if workspace_name_or_id:
144
+ runs_filter_model.workspace = workspace_name_or_id
145
+
89
146
  return verify_permissions_and_list_entities(
90
147
  filter_model=runs_filter_model,
91
148
  resource_type=ResourceType.PIPELINE_RUN,
@@ -96,7 +153,6 @@ def list_runs(
96
153
 
97
154
  @router.get(
98
155
  "/{run_id}",
99
- response_model=PipelineRunResponse,
100
156
  responses={401: error_response, 404: error_response, 422: error_response},
101
157
  )
102
158
  @handle_exceptions
@@ -157,7 +213,6 @@ def get_run(
157
213
 
158
214
  @router.put(
159
215
  "/{run_id}",
160
- response_model=PipelineRunResponse,
161
216
  responses={401: error_response, 404: error_response, 422: error_response},
162
217
  )
163
218
  @handle_exceptions
@@ -206,7 +261,6 @@ def delete_run(
206
261
 
207
262
  @router.get(
208
263
  "/{run_id}" + STEPS,
209
- response_model=Page[StepRunResponse],
210
264
  responses={401: error_response, 404: error_response, 422: error_response},
211
265
  )
212
266
  @handle_exceptions
@@ -236,7 +290,6 @@ def get_run_steps(
236
290
 
237
291
  @router.get(
238
292
  "/{run_id}" + PIPELINE_CONFIGURATION,
239
- response_model=Dict[str, Any],
240
293
  responses={401: error_response, 404: error_response, 422: error_response},
241
294
  )
242
295
  @handle_exceptions
@@ -260,7 +313,6 @@ def get_pipeline_configuration(
260
313
 
261
314
  @router.get(
262
315
  "/{run_id}" + STATUS,
263
- response_model=ExecutionStatus,
264
316
  responses={401: error_response, 404: error_response, 422: error_response},
265
317
  )
266
318
  @handle_exceptions
@@ -13,6 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for pipeline run schedules."""
15
15
 
16
+ from typing import Optional, Union
16
17
  from uuid import UUID
17
18
 
18
19
  from fastapi import APIRouter, Depends, Security
@@ -21,11 +22,18 @@ from zenml.constants import API, SCHEDULES, VERSION_1
21
22
  from zenml.models import (
22
23
  Page,
23
24
  ScheduleFilter,
25
+ ScheduleRequest,
24
26
  ScheduleResponse,
25
27
  ScheduleUpdate,
26
28
  )
27
29
  from zenml.zen_server.auth import AuthContext, authorize
28
30
  from zenml.zen_server.exceptions import error_response
31
+ from zenml.zen_server.rbac.endpoint_utils import (
32
+ verify_permissions_and_create_entity,
33
+ )
34
+ from zenml.zen_server.routers.workspaces_endpoints import (
35
+ router as workspace_router,
36
+ )
29
37
  from zenml.zen_server.utils import (
30
38
  handle_exceptions,
31
39
  make_dependable,
@@ -39,16 +47,64 @@ router = APIRouter(
39
47
  )
40
48
 
41
49
 
50
+ @router.post(
51
+ "",
52
+ responses={401: error_response, 409: error_response, 422: error_response},
53
+ )
54
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
55
+ # and can be removed after the migration
56
+ @workspace_router.post(
57
+ "/{workspace_name_or_id}" + SCHEDULES,
58
+ responses={401: error_response, 409: error_response, 422: error_response},
59
+ deprecated=True,
60
+ tags=["schedules"],
61
+ )
62
+ @handle_exceptions
63
+ def create_schedule(
64
+ schedule: ScheduleRequest,
65
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
66
+ auth_context: AuthContext = Security(authorize),
67
+ ) -> ScheduleResponse:
68
+ """Creates a schedule.
69
+
70
+ Args:
71
+ schedule: Schedule to create.
72
+ workspace_name_or_id: Optional name or ID of the workspace.
73
+ auth_context: Authentication context.
74
+
75
+ Returns:
76
+ The created schedule.
77
+ """
78
+ if workspace_name_or_id:
79
+ workspace = zen_store().get_workspace(workspace_name_or_id)
80
+ schedule.workspace = workspace.id
81
+
82
+ # NOTE: no RBAC is enforced currently for schedules, but we're
83
+ # keeping the RBAC checks here for consistency
84
+ return verify_permissions_and_create_entity(
85
+ request_model=schedule,
86
+ create_method=zen_store().create_schedule,
87
+ )
88
+
89
+
42
90
  @router.get(
43
91
  "",
44
- response_model=Page[ScheduleResponse],
45
92
  responses={401: error_response, 404: error_response, 422: error_response},
46
93
  )
94
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
95
+ # and can be removed after the migration
96
+ @workspace_router.get(
97
+ "/{workspace_name_or_id}" + SCHEDULES,
98
+ responses={401: error_response, 404: error_response, 422: error_response},
99
+ deprecated=True,
100
+ tags=["schedules"],
101
+ )
47
102
  @handle_exceptions
48
103
  def list_schedules(
49
104
  schedule_filter_model: ScheduleFilter = Depends(
50
105
  make_dependable(ScheduleFilter)
51
106
  ),
107
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
52
108
  hydrate: bool = False,
53
109
  _: AuthContext = Security(authorize),
54
110
  ) -> Page[ScheduleResponse]:
@@ -57,20 +113,24 @@ def list_schedules(
57
113
  Args:
58
114
  schedule_filter_model: Filter model used for pagination, sorting,
59
115
  filtering
116
+ workspace_name_or_id: Optional name or ID of the workspace.
60
117
  hydrate: Flag deciding whether to hydrate the output model(s)
61
118
  by including metadata fields in the response.
62
119
 
63
120
  Returns:
64
121
  List of schedule objects.
65
122
  """
123
+ if workspace_name_or_id:
124
+ schedule_filter_model.workspace = workspace_name_or_id
125
+
66
126
  return zen_store().list_schedules(
67
- schedule_filter_model=schedule_filter_model, hydrate=hydrate
127
+ schedule_filter_model=schedule_filter_model,
128
+ hydrate=hydrate,
68
129
  )
69
130
 
70
131
 
71
132
  @router.get(
72
133
  "/{schedule_id}",
73
- response_model=ScheduleResponse,
74
134
  responses={401: error_response, 404: error_response, 422: error_response},
75
135
  )
76
136
  @handle_exceptions
@@ -89,12 +149,14 @@ def get_schedule(
89
149
  Returns:
90
150
  A specific schedule object.
91
151
  """
92
- return zen_store().get_schedule(schedule_id=schedule_id, hydrate=hydrate)
152
+ return zen_store().get_schedule(
153
+ schedule_id=schedule_id,
154
+ hydrate=hydrate,
155
+ )
93
156
 
94
157
 
95
158
  @router.put(
96
159
  "/{schedule_id}",
97
- response_model=ScheduleResponse,
98
160
  responses={401: error_response, 404: error_response, 422: error_response},
99
161
  )
100
162
  @handle_exceptions
@@ -113,7 +175,8 @@ def update_schedule(
113
175
  The updated schedule object.
114
176
  """
115
177
  return zen_store().update_schedule(
116
- schedule_id=schedule_id, schedule_update=schedule_update
178
+ schedule_id=schedule_id,
179
+ schedule_update=schedule_update,
117
180
  )
118
181
 
119
182
 
@@ -13,7 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for pipeline run secrets."""
15
15
 
16
- from typing import Optional
16
+ from typing import Optional, Union
17
17
  from uuid import UUID
18
18
 
19
19
  from fastapi import APIRouter, Depends, Security
@@ -29,12 +29,14 @@ from zenml.constants import (
29
29
  from zenml.models import (
30
30
  Page,
31
31
  SecretFilter,
32
+ SecretRequest,
32
33
  SecretResponse,
33
34
  SecretUpdate,
34
35
  )
35
36
  from zenml.zen_server.auth import AuthContext, authorize
36
37
  from zenml.zen_server.exceptions import error_response
37
38
  from zenml.zen_server.rbac.endpoint_utils import (
39
+ verify_permissions_and_create_entity,
38
40
  verify_permissions_and_delete_entity,
39
41
  verify_permissions_and_get_entity,
40
42
  verify_permissions_and_list_entities,
@@ -47,6 +49,9 @@ from zenml.zen_server.rbac.utils import (
47
49
  is_owned_by_authenticated_user,
48
50
  verify_permission,
49
51
  )
52
+ from zenml.zen_server.routers.workspaces_endpoints import (
53
+ router as workspace_router,
54
+ )
50
55
  from zenml.zen_server.utils import (
51
56
  handle_exceptions,
52
57
  make_dependable,
@@ -66,9 +71,41 @@ op_router = APIRouter(
66
71
  )
67
72
 
68
73
 
74
+ @router.post(
75
+ "",
76
+ responses={401: error_response, 409: error_response, 422: error_response},
77
+ )
78
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
79
+ # and can be removed after the migration
80
+ @workspace_router.post(
81
+ "/{workspace_name_or_id}" + SECRETS,
82
+ responses={401: error_response, 409: error_response, 422: error_response},
83
+ deprecated=True,
84
+ tags=["secrets"],
85
+ )
86
+ @handle_exceptions
87
+ def create_secret(
88
+ secret: SecretRequest,
89
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
90
+ _: AuthContext = Security(authorize),
91
+ ) -> SecretResponse:
92
+ """Creates a secret.
93
+
94
+ Args:
95
+ secret: Secret to create.
96
+ workspace_name_or_id: Optional name or ID of the workspace.
97
+
98
+ Returns:
99
+ The created secret.
100
+ """
101
+ return verify_permissions_and_create_entity(
102
+ request_model=secret,
103
+ create_method=zen_store().create_secret,
104
+ )
105
+
106
+
69
107
  @router.get(
70
108
  "",
71
- response_model=Page[SecretResponse],
72
109
  responses={401: error_response, 404: error_response, 422: error_response},
73
110
  )
74
111
  @handle_exceptions
@@ -116,7 +153,6 @@ def list_secrets(
116
153
 
117
154
  @router.get(
118
155
  "/{secret_id}",
119
- response_model=SecretResponse,
120
156
  responses={401: error_response, 404: error_response, 422: error_response},
121
157
  )
122
158
  @handle_exceptions
@@ -140,6 +176,7 @@ def get_secret(
140
176
  get_method=zen_store().get_secret,
141
177
  hydrate=hydrate,
142
178
  )
179
+
143
180
  if not has_permissions_for_model(secret, action=Action.READ_SECRET_VALUE):
144
181
  secret.remove_secrets()
145
182
 
@@ -148,7 +185,6 @@ def get_secret(
148
185
 
149
186
  @router.put(
150
187
  "/{secret_id}",
151
- response_model=SecretResponse,
152
188
  responses={401: error_response, 404: error_response, 422: error_response},
153
189
  )
154
190
  @handle_exceptions
@@ -25,20 +25,27 @@ from zenml.constants import (
25
25
  LOAD_INFO,
26
26
  ONBOARDING_STATE,
27
27
  SERVER_SETTINGS,
28
+ STATISTICS,
28
29
  VERSION_1,
29
30
  )
30
31
  from zenml.enums import AuthScheme
31
32
  from zenml.exceptions import IllegalOperationError
32
33
  from zenml.models import (
34
+ ComponentFilter,
33
35
  ServerActivationRequest,
34
36
  ServerLoadInfo,
35
37
  ServerModel,
36
38
  ServerSettingsResponse,
37
39
  ServerSettingsUpdate,
40
+ ServerStatistics,
41
+ StackFilter,
38
42
  UserResponse,
43
+ WorkspaceFilter,
39
44
  )
40
45
  from zenml.zen_server.auth import AuthContext, authorize
41
46
  from zenml.zen_server.exceptions import error_response
47
+ from zenml.zen_server.rbac.models import ResourceType
48
+ from zenml.zen_server.rbac.utils import get_allowed_resource_ids
42
49
  from zenml.zen_server.utils import handle_exceptions, server_config, zen_store
43
50
 
44
51
  router = APIRouter(
@@ -60,7 +67,6 @@ def version() -> str:
60
67
 
61
68
  @router.get(
62
69
  INFO,
63
- response_model=ServerModel,
64
70
  responses={401: error_response, 404: error_response, 422: error_response},
65
71
  )
66
72
  @handle_exceptions
@@ -234,3 +240,49 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
234
240
  The default admin user that was created during activation, if any.
235
241
  """
236
242
  return zen_store().activate_server(activate_request)
243
+
244
+
245
+ @router.get(
246
+ STATISTICS,
247
+ responses={401: error_response, 404: error_response, 422: error_response},
248
+ )
249
+ @handle_exceptions
250
+ def get_server_statistics(
251
+ auth_context: AuthContext = Security(authorize),
252
+ ) -> ServerStatistics:
253
+ """Gets server statistics.
254
+
255
+ Args:
256
+ auth_context: Authentication context.
257
+
258
+ Returns:
259
+ Statistics of the server.
260
+ """
261
+ user_id = auth_context.user.id
262
+ component_filter = ComponentFilter()
263
+ component_filter.configure_rbac(
264
+ authenticated_user_id=user_id,
265
+ id=get_allowed_resource_ids(
266
+ resource_type=ResourceType.STACK_COMPONENT
267
+ ),
268
+ )
269
+
270
+ workspace_filter = WorkspaceFilter()
271
+ workspace_filter.configure_rbac(
272
+ authenticated_user_id=user_id,
273
+ id=get_allowed_resource_ids(resource_type=ResourceType.WORKSPACE),
274
+ )
275
+
276
+ stack_filter = StackFilter()
277
+ stack_filter.configure_rbac(
278
+ authenticated_user_id=user_id,
279
+ id=get_allowed_resource_ids(resource_type=ResourceType.STACK),
280
+ )
281
+
282
+ return ServerStatistics(
283
+ stacks=zen_store().count_stacks(filter_model=stack_filter),
284
+ components=zen_store().count_stack_components(
285
+ filter_model=component_filter
286
+ ),
287
+ workspaces=zen_store().count_workspaces(filter_model=workspace_filter),
288
+ )