zenml-nightly 0.75.0.dev20250312__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 (160) 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 +615 -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_run.py +5 -13
  45. zenml/models/v2/core/run_template.py +1 -2
  46. zenml/models/v2/core/schedule.py +0 -9
  47. zenml/models/v2/core/secret.py +93 -127
  48. zenml/models/v2/core/server_settings.py +2 -2
  49. zenml/models/v2/core/service.py +43 -12
  50. zenml/models/v2/core/service_connector.py +14 -16
  51. zenml/models/v2/core/stack.py +24 -26
  52. zenml/models/v2/core/step_run.py +3 -15
  53. zenml/models/v2/core/tag.py +41 -15
  54. zenml/models/v2/core/user.py +19 -2
  55. zenml/models/v2/misc/statistics.py +45 -0
  56. zenml/models/v2/misc/tag.py +27 -0
  57. zenml/orchestrators/cache_utils.py +1 -1
  58. zenml/orchestrators/input_utils.py +1 -0
  59. zenml/orchestrators/step_launcher.py +0 -1
  60. zenml/orchestrators/step_run_utils.py +0 -2
  61. zenml/orchestrators/step_runner.py +10 -1
  62. zenml/pipelines/build_utils.py +0 -2
  63. zenml/pipelines/pipeline_decorator.py +3 -2
  64. zenml/pipelines/pipeline_definition.py +4 -5
  65. zenml/pipelines/run_utils.py +3 -3
  66. zenml/service_connectors/service_connector.py +0 -7
  67. zenml/service_connectors/service_connector_utils.py +0 -1
  68. zenml/stack/authentication_mixin.py +1 -1
  69. zenml/stack/flavor.py +3 -14
  70. zenml/stack/stack_component.py +1 -5
  71. zenml/steps/step_context.py +19 -0
  72. zenml/utils/string_utils.py +1 -1
  73. zenml/utils/tag_utils.py +642 -0
  74. zenml/zen_server/cloud_utils.py +21 -0
  75. zenml/zen_server/exceptions.py +0 -6
  76. zenml/zen_server/rbac/endpoint_utils.py +134 -46
  77. zenml/zen_server/rbac/models.py +65 -3
  78. zenml/zen_server/rbac/rbac_interface.py +9 -0
  79. zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
  80. zenml/zen_server/rbac/utils.py +156 -29
  81. zenml/zen_server/rbac/zenml_cloud_rbac.py +43 -11
  82. zenml/zen_server/routers/actions_endpoints.py +3 -5
  83. zenml/zen_server/routers/artifact_endpoint.py +0 -5
  84. zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
  85. zenml/zen_server/routers/auth_endpoints.py +22 -7
  86. zenml/zen_server/routers/code_repositories_endpoints.py +56 -3
  87. zenml/zen_server/routers/devices_endpoints.py +0 -4
  88. zenml/zen_server/routers/event_source_endpoints.py +0 -5
  89. zenml/zen_server/routers/flavors_endpoints.py +0 -5
  90. zenml/zen_server/routers/logs_endpoints.py +0 -1
  91. zenml/zen_server/routers/model_versions_endpoints.py +102 -23
  92. zenml/zen_server/routers/models_endpoints.py +51 -68
  93. zenml/zen_server/routers/pipeline_builds_endpoints.py +58 -4
  94. zenml/zen_server/routers/pipeline_deployments_endpoints.py +58 -4
  95. zenml/zen_server/routers/pipelines_endpoints.py +73 -4
  96. zenml/zen_server/routers/plugin_endpoints.py +0 -1
  97. zenml/zen_server/routers/run_metadata_endpoints.py +99 -0
  98. zenml/zen_server/routers/run_templates_endpoints.py +66 -3
  99. zenml/zen_server/routers/runs_endpoints.py +60 -8
  100. zenml/zen_server/routers/schedule_endpoints.py +69 -6
  101. zenml/zen_server/routers/secrets_endpoints.py +40 -4
  102. zenml/zen_server/routers/server_endpoints.py +53 -1
  103. zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
  104. zenml/zen_server/routers/service_connectors_endpoints.py +96 -14
  105. zenml/zen_server/routers/service_endpoints.py +20 -7
  106. zenml/zen_server/routers/stack_components_endpoints.py +68 -7
  107. zenml/zen_server/routers/stacks_endpoints.py +98 -7
  108. zenml/zen_server/routers/steps_endpoints.py +17 -11
  109. zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
  110. zenml/zen_server/routers/tags_endpoints.py +6 -17
  111. zenml/zen_server/routers/triggers_endpoints.py +5 -8
  112. zenml/zen_server/routers/users_endpoints.py +47 -12
  113. zenml/zen_server/routers/workspaces_endpoints.py +56 -1285
  114. zenml/zen_server/template_execution/utils.py +5 -4
  115. zenml/zen_server/utils.py +21 -0
  116. zenml/zen_server/zen_server_api.py +4 -0
  117. zenml/zen_stores/base_zen_store.py +29 -44
  118. zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
  119. zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
  120. zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
  121. zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
  122. zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
  123. zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
  124. zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
  125. zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
  126. zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
  127. zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
  128. zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
  129. zenml/zen_stores/rest_zen_store.py +172 -171
  130. zenml/zen_stores/schemas/action_schemas.py +8 -1
  131. zenml/zen_stores/schemas/api_key_schemas.py +8 -1
  132. zenml/zen_stores/schemas/artifact_schemas.py +28 -1
  133. zenml/zen_stores/schemas/code_repository_schemas.py +8 -1
  134. zenml/zen_stores/schemas/component_schemas.py +9 -14
  135. zenml/zen_stores/schemas/event_source_schemas.py +8 -1
  136. zenml/zen_stores/schemas/flavor_schemas.py +14 -20
  137. zenml/zen_stores/schemas/model_schemas.py +3 -0
  138. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +3 -1
  139. zenml/zen_stores/schemas/pipeline_run_schemas.py +0 -3
  140. zenml/zen_stores/schemas/run_template_schemas.py +8 -4
  141. zenml/zen_stores/schemas/schedule_schema.py +9 -14
  142. zenml/zen_stores/schemas/secret_schemas.py +15 -25
  143. zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
  144. zenml/zen_stores/schemas/service_schemas.py +0 -1
  145. zenml/zen_stores/schemas/stack_schemas.py +12 -15
  146. zenml/zen_stores/schemas/step_run_schemas.py +7 -8
  147. zenml/zen_stores/schemas/tag_schemas.py +30 -2
  148. zenml/zen_stores/schemas/trigger_schemas.py +8 -1
  149. zenml/zen_stores/schemas/user_schemas.py +24 -2
  150. zenml/zen_stores/schemas/utils.py +16 -0
  151. zenml/zen_stores/schemas/workspace_schemas.py +7 -25
  152. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
  153. zenml/zen_stores/sql_zen_store.py +2905 -2280
  154. zenml/zen_stores/template_utils.py +1 -1
  155. zenml/zen_stores/zen_store_interface.py +82 -58
  156. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/METADATA +1 -1
  157. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/RECORD +160 -147
  158. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/LICENSE +0 -0
  159. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/WHEEL +0 -0
  160. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/entry_points.txt +0 -0
@@ -67,7 +67,6 @@ router = APIRouter(
67
67
 
68
68
  @router.post(
69
69
  "",
70
- response_model=ServiceAccountResponse,
71
70
  responses={
72
71
  401: error_response,
73
72
  409: error_response,
@@ -89,14 +88,12 @@ def create_service_account(
89
88
  """
90
89
  return verify_permissions_and_create_entity(
91
90
  request_model=service_account,
92
- resource_type=ResourceType.SERVICE_ACCOUNT,
93
91
  create_method=zen_store().create_service_account,
94
92
  )
95
93
 
96
94
 
97
95
  @router.get(
98
96
  "/{service_account_name_or_id}",
99
- response_model=ServiceAccountResponse,
100
97
  responses={401: error_response, 404: error_response, 422: error_response},
101
98
  )
102
99
  @handle_exceptions
@@ -124,7 +121,6 @@ def get_service_account(
124
121
 
125
122
  @router.get(
126
123
  "",
127
- response_model=Page[ServiceAccountResponse],
128
124
  responses={401: error_response, 404: error_response, 422: error_response},
129
125
  )
130
126
  @handle_exceptions
@@ -156,7 +152,6 @@ def list_service_accounts(
156
152
 
157
153
  @router.put(
158
154
  "/{service_account_name_or_id}",
159
- response_model=ServiceAccountResponse,
160
155
  responses={
161
156
  401: error_response,
162
157
  404: error_response,
@@ -214,7 +209,6 @@ def delete_service_account(
214
209
 
215
210
  @router.post(
216
211
  "/{service_account_id}" + API_KEYS,
217
- response_model=APIKeyResponse,
218
212
  responses={401: error_response, 409: error_response, 422: error_response},
219
213
  )
220
214
  @handle_exceptions
@@ -233,18 +227,26 @@ def create_api_key(
233
227
  Returns:
234
228
  The created API key.
235
229
  """
230
+
231
+ def create_api_key_wrapper(
232
+ api_key: APIKeyRequest,
233
+ ) -> APIKeyResponse:
234
+ return zen_store().create_api_key(
235
+ service_account_id=service_account_id,
236
+ api_key=api_key,
237
+ )
238
+
236
239
  service_account = zen_store().get_service_account(service_account_id)
237
- verify_permission_for_model(service_account, action=Action.UPDATE)
238
- created_api_key = zen_store().create_api_key(
239
- service_account_id=service_account_id,
240
- api_key=api_key,
240
+
241
+ return verify_permissions_and_create_entity(
242
+ request_model=api_key,
243
+ create_method=create_api_key_wrapper,
244
+ surrogate_models=[service_account],
241
245
  )
242
- return created_api_key
243
246
 
244
247
 
245
248
  @router.get(
246
249
  "/{service_account_id}" + API_KEYS + "/{api_key_name_or_id}",
247
- response_model=APIKeyResponse,
248
250
  responses={401: error_response, 404: error_response, 422: error_response},
249
251
  )
250
252
  @handle_exceptions
@@ -278,7 +280,6 @@ def get_api_key(
278
280
 
279
281
  @router.get(
280
282
  "/{service_account_id}" + API_KEYS,
281
- response_model=Page[APIKeyResponse],
282
283
  responses={401: error_response, 404: error_response, 422: error_response},
283
284
  )
284
285
  @handle_exceptions
@@ -313,7 +314,6 @@ def list_api_keys(
313
314
 
314
315
  @router.put(
315
316
  "/{service_account_id}" + API_KEYS + "/{api_key_name_or_id}",
316
- response_model=APIKeyResponse,
317
317
  responses={401: error_response, 409: error_response, 422: error_response},
318
318
  )
319
319
  @handle_exceptions
@@ -348,7 +348,6 @@ def update_api_key(
348
348
  + API_KEYS
349
349
  + "/{api_key_name_or_id}"
350
350
  + API_KEY_ROTATE,
351
- response_model=APIKeyResponse,
352
351
  responses={401: error_response, 409: error_response, 422: error_response},
353
352
  )
354
353
  @handle_exceptions
@@ -13,7 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for service connectors."""
15
15
 
16
- from typing import List, Optional
16
+ from typing import List, Optional, Union
17
17
  from uuid import UUID
18
18
 
19
19
  from fastapi import APIRouter, Depends, Security
@@ -22,6 +22,7 @@ from zenml.constants import (
22
22
  API,
23
23
  SERVICE_CONNECTOR_CLIENT,
24
24
  SERVICE_CONNECTOR_FULL_STACK,
25
+ SERVICE_CONNECTOR_RESOURCES,
25
26
  SERVICE_CONNECTOR_TYPES,
26
27
  SERVICE_CONNECTOR_VERIFY,
27
28
  SERVICE_CONNECTORS,
@@ -44,6 +45,7 @@ from zenml.service_connectors.service_connector_utils import (
44
45
  from zenml.zen_server.auth import AuthContext, authorize
45
46
  from zenml.zen_server.exceptions import error_response
46
47
  from zenml.zen_server.rbac.endpoint_utils import (
48
+ verify_permissions_and_create_entity,
47
49
  verify_permissions_and_delete_entity,
48
50
  verify_permissions_and_list_entities,
49
51
  verify_permissions_and_update_entity,
@@ -57,6 +59,9 @@ from zenml.zen_server.rbac.utils import (
57
59
  verify_permission,
58
60
  verify_permission_for_model,
59
61
  )
62
+ from zenml.zen_server.routers.workspaces_endpoints import (
63
+ router as workspace_router,
64
+ )
60
65
  from zenml.zen_server.utils import (
61
66
  handle_exceptions,
62
67
  make_dependable,
@@ -76,31 +81,73 @@ types_router = APIRouter(
76
81
  )
77
82
 
78
83
 
84
+ @router.post(
85
+ "",
86
+ responses={401: error_response, 409: error_response, 422: error_response},
87
+ )
88
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
89
+ # and can be removed after the migration
90
+ @workspace_router.post(
91
+ "/{workspace_name_or_id}" + SERVICE_CONNECTORS,
92
+ responses={401: error_response, 409: error_response, 422: error_response},
93
+ deprecated=True,
94
+ tags=["service_connectors"],
95
+ )
96
+ @handle_exceptions
97
+ def create_service_connector(
98
+ connector: ServiceConnectorRequest,
99
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
100
+ _: AuthContext = Security(authorize),
101
+ ) -> ServiceConnectorResponse:
102
+ """Creates a service connector.
103
+
104
+ Args:
105
+ connector: Service connector to register.
106
+ workspace_name_or_id: Optional name or ID of the workspace.
107
+
108
+ Returns:
109
+ The created service connector.
110
+ """
111
+ return verify_permissions_and_create_entity(
112
+ request_model=connector,
113
+ create_method=zen_store().create_service_connector,
114
+ )
115
+
116
+
79
117
  @router.get(
80
118
  "",
81
- response_model=Page[ServiceConnectorResponse],
82
119
  responses={401: error_response, 404: error_response, 422: error_response},
83
120
  )
121
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
122
+ # and can be removed after the migration
123
+ @workspace_router.get(
124
+ "/{workspace_name_or_id}" + SERVICE_CONNECTORS,
125
+ responses={401: error_response, 404: error_response, 422: error_response},
126
+ deprecated=True,
127
+ tags=["service_connectors"],
128
+ )
84
129
  @handle_exceptions
85
130
  def list_service_connectors(
86
131
  connector_filter_model: ServiceConnectorFilter = Depends(
87
132
  make_dependable(ServiceConnectorFilter)
88
133
  ),
134
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
89
135
  expand_secrets: bool = True,
90
136
  hydrate: bool = False,
91
137
  _: AuthContext = Security(authorize),
92
138
  ) -> Page[ServiceConnectorResponse]:
93
- """Get a list of all service connectors for a specific type.
139
+ """Get a list of all service connectors, optionally filtered by workspace.
94
140
 
95
141
  Args:
96
142
  connector_filter_model: Filter model used for pagination, sorting,
97
143
  filtering
144
+ workspace_name_or_id: Optional name or ID of the workspace to filter by.
98
145
  expand_secrets: Whether to expand secrets or not.
99
146
  hydrate: Flag deciding whether to hydrate the output model(s)
100
147
  by including metadata fields in the response.
101
148
 
102
149
  Returns:
103
- Page with list of service connectors for a specific type.
150
+ Page with list of service connectors matching the filter criteria.
104
151
  """
105
152
  connectors = verify_permissions_and_list_entities(
106
153
  filter_model=connector_filter_model,
@@ -143,7 +190,6 @@ def list_service_connectors(
143
190
 
144
191
  @router.get(
145
192
  "/{connector_id}",
146
- response_model=ServiceConnectorResponse,
147
193
  responses={401: error_response, 404: error_response, 422: error_response},
148
194
  )
149
195
  @handle_exceptions
@@ -186,7 +232,6 @@ def get_service_connector(
186
232
 
187
233
  @router.put(
188
234
  "/{connector_id}",
189
- response_model=ServiceConnectorResponse,
190
235
  responses={401: error_response, 404: error_response, 422: error_response},
191
236
  )
192
237
  @handle_exceptions
@@ -235,7 +280,6 @@ def delete_service_connector(
235
280
 
236
281
  @router.post(
237
282
  SERVICE_CONNECTOR_VERIFY,
238
- response_model=ServiceConnectorResourcesModel,
239
283
  responses={401: error_response, 409: error_response, 422: error_response},
240
284
  )
241
285
  @handle_exceptions
@@ -259,9 +303,7 @@ def validate_and_verify_service_connector_config(
259
303
  The list of resources that the service connector configuration has
260
304
  access to.
261
305
  """
262
- verify_permission(
263
- resource_type=ResourceType.SERVICE_CONNECTOR, action=Action.CREATE
264
- )
306
+ verify_permission_for_model(model=connector, action=Action.CREATE)
265
307
 
266
308
  return zen_store().verify_service_connector_config(
267
309
  service_connector=connector,
@@ -269,9 +311,52 @@ def validate_and_verify_service_connector_config(
269
311
  )
270
312
 
271
313
 
314
+ @router.get(
315
+ SERVICE_CONNECTOR_RESOURCES,
316
+ responses={401: error_response, 404: error_response, 422: error_response},
317
+ )
318
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
319
+ # and can be removed after the migration
320
+ @workspace_router.get(
321
+ "/{workspace_name_or_id}" + SERVICE_CONNECTOR_RESOURCES,
322
+ responses={401: error_response, 404: error_response, 422: error_response},
323
+ deprecated=True,
324
+ tags=["service_connectors"],
325
+ )
326
+ @handle_exceptions
327
+ def list_service_connector_resources(
328
+ filter_model: ServiceConnectorFilter = Depends(
329
+ make_dependable(ServiceConnectorFilter)
330
+ ),
331
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
332
+ auth_context: AuthContext = Security(authorize),
333
+ ) -> List[ServiceConnectorResourcesModel]:
334
+ """List resources that can be accessed by service connectors.
335
+
336
+ Args:
337
+ filter_model: The filter model to use when fetching service
338
+ connectors.
339
+ workspace_name_or_id: Optional name or ID of the workspace.
340
+ auth_context: Authentication context.
341
+
342
+ Returns:
343
+ The matching list of resources that available service
344
+ connectors have access to.
345
+ """
346
+ allowed_ids = get_allowed_resource_ids(
347
+ resource_type=ResourceType.SERVICE_CONNECTOR
348
+ )
349
+ filter_model.configure_rbac(
350
+ authenticated_user_id=auth_context.user.id, id=allowed_ids
351
+ )
352
+
353
+ return zen_store().list_service_connector_resources(
354
+ filter_model=filter_model,
355
+ )
356
+
357
+
272
358
  @router.put(
273
359
  "/{connector_id}" + SERVICE_CONNECTOR_VERIFY,
274
- response_model=ServiceConnectorResourcesModel,
275
360
  responses={401: error_response, 404: error_response, 422: error_response},
276
361
  )
277
362
  @handle_exceptions
@@ -313,7 +398,6 @@ def validate_and_verify_service_connector(
313
398
 
314
399
  @router.get(
315
400
  "/{connector_id}" + SERVICE_CONNECTOR_CLIENT,
316
- response_model=ServiceConnectorResponse,
317
401
  responses={401: error_response, 404: error_response, 422: error_response},
318
402
  )
319
403
  @handle_exceptions
@@ -351,7 +435,6 @@ def get_service_connector_client(
351
435
 
352
436
  @types_router.get(
353
437
  "",
354
- response_model=List[ServiceConnectorTypeModel],
355
438
  responses={401: error_response, 404: error_response, 422: error_response},
356
439
  )
357
440
  @handle_exceptions
@@ -382,7 +465,6 @@ def list_service_connector_types(
382
465
 
383
466
  @types_router.get(
384
467
  "/{connector_type}",
385
- response_model=ServiceConnectorTypeModel,
386
468
  responses={401: error_response, 404: error_response, 422: error_response},
387
469
  )
388
470
  @handle_exceptions
@@ -13,6 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for services."""
15
15
 
16
+ from typing import Optional, Union
16
17
  from uuid import UUID
17
18
 
18
19
  from fastapi import APIRouter, Depends, Security
@@ -35,6 +36,9 @@ from zenml.zen_server.rbac.endpoint_utils import (
35
36
  verify_permissions_and_update_entity,
36
37
  )
37
38
  from zenml.zen_server.rbac.models import ResourceType
39
+ from zenml.zen_server.routers.workspaces_endpoints import (
40
+ router as workspace_router,
41
+ )
38
42
  from zenml.zen_server.utils import (
39
43
  handle_exceptions,
40
44
  make_dependable,
@@ -50,32 +54,43 @@ router = APIRouter(
50
54
 
51
55
  @router.post(
52
56
  "",
53
- response_model=ServiceResponse,
54
57
  responses={401: error_response, 422: error_response},
55
58
  )
59
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
60
+ # and can be removed after the migration
61
+ @workspace_router.post(
62
+ "/{workspace_name_or_id}" + SERVICES,
63
+ responses={401: error_response, 409: error_response, 422: error_response},
64
+ deprecated=True,
65
+ tags=["services"],
66
+ )
56
67
  @handle_exceptions
57
68
  def create_service(
58
69
  service: ServiceRequest,
70
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
59
71
  _: AuthContext = Security(authorize),
60
72
  ) -> ServiceResponse:
61
73
  """Creates a new service.
62
74
 
63
75
  Args:
64
- service: The model containing the attributes of the new service.
76
+ service: The service to create.
77
+ workspace_name_or_id: Optional name or ID of the workspace.
65
78
 
66
79
  Returns:
67
- The created service object.
80
+ The created service.
68
81
  """
82
+ if workspace_name_or_id:
83
+ workspace = zen_store().get_workspace(workspace_name_or_id)
84
+ service.workspace = workspace.id
85
+
69
86
  return verify_permissions_and_create_entity(
70
87
  request_model=service,
71
88
  create_method=zen_store().create_service,
72
- resource_type=ResourceType.SERVICE,
73
89
  )
74
90
 
75
91
 
76
92
  @router.get(
77
93
  "",
78
- response_model=Page[ServiceResponse],
79
94
  responses={401: error_response, 404: error_response, 422: error_response},
80
95
  )
81
96
  @handle_exceptions
@@ -105,7 +120,6 @@ def list_services(
105
120
 
106
121
  @router.get(
107
122
  "/{service_id}",
108
- response_model=ServiceResponse,
109
123
  responses={401: error_response, 404: error_response, 422: error_response},
110
124
  )
111
125
  @handle_exceptions
@@ -133,7 +147,6 @@ def get_service(
133
147
 
134
148
  @router.put(
135
149
  "/{service_id}",
136
- response_model=ServiceResponse,
137
150
  responses={401: error_response, 404: error_response, 422: error_response},
138
151
  )
139
152
  @handle_exceptions
@@ -13,7 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for stack components."""
15
15
 
16
- from typing import List
16
+ from typing import List, Optional, Union
17
17
  from uuid import UUID
18
18
 
19
19
  from fastapi import APIRouter, Depends, Security
@@ -22,6 +22,7 @@ from zenml.constants import API, COMPONENT_TYPES, STACK_COMPONENTS, VERSION_1
22
22
  from zenml.enums import StackComponentType
23
23
  from zenml.models import (
24
24
  ComponentFilter,
25
+ ComponentRequest,
25
26
  ComponentResponse,
26
27
  ComponentUpdate,
27
28
  Page,
@@ -29,6 +30,7 @@ from zenml.models import (
29
30
  from zenml.zen_server.auth import AuthContext, authorize
30
31
  from zenml.zen_server.exceptions import error_response
31
32
  from zenml.zen_server.rbac.endpoint_utils import (
33
+ verify_permissions_and_create_entity,
32
34
  verify_permissions_and_delete_entity,
33
35
  verify_permissions_and_get_entity,
34
36
  verify_permissions_and_list_entities,
@@ -36,6 +38,9 @@ from zenml.zen_server.rbac.endpoint_utils import (
36
38
  )
37
39
  from zenml.zen_server.rbac.models import Action, ResourceType
38
40
  from zenml.zen_server.rbac.utils import verify_permission_for_model
41
+ from zenml.zen_server.routers.workspaces_endpoints import (
42
+ router as workspace_router,
43
+ )
39
44
  from zenml.zen_server.utils import (
40
45
  handle_exceptions,
41
46
  make_dependable,
@@ -55,29 +60,88 @@ types_router = APIRouter(
55
60
  )
56
61
 
57
62
 
63
+ @router.post(
64
+ "",
65
+ responses={401: error_response, 409: error_response, 422: error_response},
66
+ )
67
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
68
+ # and can be removed after the migration
69
+ @workspace_router.post(
70
+ "/{workspace_name_or_id}" + STACK_COMPONENTS,
71
+ responses={401: error_response, 409: error_response, 422: error_response},
72
+ deprecated=True,
73
+ tags=["stack_components"],
74
+ )
75
+ @handle_exceptions
76
+ def create_stack_component(
77
+ component: ComponentRequest,
78
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
79
+ _: AuthContext = Security(authorize),
80
+ ) -> ComponentResponse:
81
+ """Creates a stack component, optionally in a specific workspace.
82
+
83
+ Args:
84
+ component: Stack component to register.
85
+ workspace_name_or_id: Optional name or ID of the workspace.
86
+
87
+ Returns:
88
+ The created stack component.
89
+ """
90
+ if component.connector:
91
+ service_connector = zen_store().get_service_connector(
92
+ component.connector
93
+ )
94
+ verify_permission_for_model(service_connector, action=Action.READ)
95
+
96
+ from zenml.stack.utils import validate_stack_component_config
97
+
98
+ validate_stack_component_config(
99
+ configuration_dict=component.configuration,
100
+ flavor=component.flavor,
101
+ component_type=component.type,
102
+ zen_store=zen_store(),
103
+ # We allow custom flavors to fail import on the server side.
104
+ validate_custom_flavors=False,
105
+ )
106
+
107
+ return verify_permissions_and_create_entity(
108
+ request_model=component,
109
+ create_method=zen_store().create_stack_component,
110
+ )
111
+
112
+
58
113
  @router.get(
59
114
  "",
60
- response_model=Page[ComponentResponse],
61
115
  responses={401: error_response, 404: error_response, 422: error_response},
62
116
  )
117
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
118
+ # and can be removed after the migration
119
+ @workspace_router.get(
120
+ "/{workspace_name_or_id}" + STACK_COMPONENTS,
121
+ responses={401: error_response, 404: error_response, 422: error_response},
122
+ deprecated=True,
123
+ tags=["stack_components"],
124
+ )
63
125
  @handle_exceptions
64
126
  def list_stack_components(
65
127
  component_filter_model: ComponentFilter = Depends(
66
128
  make_dependable(ComponentFilter)
67
129
  ),
130
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
68
131
  hydrate: bool = False,
69
132
  _: AuthContext = Security(authorize),
70
133
  ) -> Page[ComponentResponse]:
71
- """Get a list of all stack components for a specific type.
134
+ """Get a list of all stack components, optionally filtered by workspace.
72
135
 
73
136
  Args:
74
137
  component_filter_model: Filter model used for pagination, sorting,
75
138
  filtering.
139
+ workspace_name_or_id: Optional name or ID of the workspace to filter by.
76
140
  hydrate: Flag deciding whether to hydrate the output model(s)
77
141
  by including metadata fields in the response.
78
142
 
79
143
  Returns:
80
- List of stack components for a specific type.
144
+ List of stack components matching the filter criteria.
81
145
  """
82
146
  return verify_permissions_and_list_entities(
83
147
  filter_model=component_filter_model,
@@ -89,7 +153,6 @@ def list_stack_components(
89
153
 
90
154
  @router.get(
91
155
  "/{component_id}",
92
- response_model=ComponentResponse,
93
156
  responses={401: error_response, 404: error_response, 422: error_response},
94
157
  )
95
158
  @handle_exceptions
@@ -117,7 +180,6 @@ def get_stack_component(
117
180
 
118
181
  @router.put(
119
182
  "/{component_id}",
120
- response_model=ComponentResponse,
121
183
  responses={401: error_response, 404: error_response, 422: error_response},
122
184
  )
123
185
  @handle_exceptions
@@ -185,7 +247,6 @@ def deregister_stack_component(
185
247
 
186
248
  @types_router.get(
187
249
  "",
188
- response_model=List[str],
189
250
  responses={401: error_response, 404: error_response, 422: error_response},
190
251
  )
191
252
  @handle_exceptions