zenml-nightly 0.61.0.dev20240712__py3-none-any.whl → 0.62.0.dev20240726__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 (152) hide show
  1. README.md +2 -2
  2. RELEASE_NOTES.md +40 -0
  3. zenml/VERSION +1 -1
  4. zenml/__init__.py +2 -0
  5. zenml/cli/stack.py +114 -248
  6. zenml/cli/stack_components.py +5 -3
  7. zenml/constants.py +3 -0
  8. zenml/enums.py +16 -0
  9. zenml/integrations/__init__.py +1 -0
  10. zenml/integrations/azure/__init__.py +2 -2
  11. zenml/integrations/constants.py +1 -0
  12. zenml/integrations/databricks/__init__.py +52 -0
  13. zenml/integrations/databricks/flavors/__init__.py +30 -0
  14. zenml/integrations/databricks/flavors/databricks_model_deployer_flavor.py +118 -0
  15. zenml/integrations/databricks/flavors/databricks_orchestrator_flavor.py +147 -0
  16. zenml/integrations/databricks/model_deployers/__init__.py +20 -0
  17. zenml/integrations/databricks/model_deployers/databricks_model_deployer.py +249 -0
  18. zenml/integrations/databricks/orchestrators/__init__.py +20 -0
  19. zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +497 -0
  20. zenml/integrations/databricks/orchestrators/databricks_orchestrator_entrypoint_config.py +97 -0
  21. zenml/integrations/databricks/services/__init__.py +19 -0
  22. zenml/integrations/databricks/services/databricks_deployment.py +407 -0
  23. zenml/integrations/databricks/utils/__init__.py +14 -0
  24. zenml/integrations/databricks/utils/databricks_utils.py +87 -0
  25. zenml/integrations/great_expectations/data_validators/ge_data_validator.py +12 -8
  26. zenml/integrations/huggingface/materializers/huggingface_datasets_materializer.py +88 -3
  27. zenml/integrations/huggingface/steps/accelerate_runner.py +1 -7
  28. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +1 -13
  29. zenml/integrations/kubernetes/orchestrators/manifest_utils.py +22 -4
  30. zenml/integrations/kubernetes/pod_settings.py +4 -0
  31. zenml/integrations/lightgbm/__init__.py +1 -0
  32. zenml/integrations/mlflow/__init__.py +1 -1
  33. zenml/integrations/mlflow/model_registries/mlflow_model_registry.py +6 -2
  34. zenml/integrations/mlflow/services/mlflow_deployment.py +1 -1
  35. zenml/integrations/skypilot_azure/__init__.py +1 -3
  36. zenml/integrations/skypilot_lambda/__init__.py +1 -1
  37. zenml/logging/step_logging.py +34 -35
  38. zenml/materializers/built_in_materializer.py +1 -1
  39. zenml/materializers/cloudpickle_materializer.py +1 -1
  40. zenml/model/model.py +1 -1
  41. zenml/models/v2/core/component.py +29 -0
  42. zenml/models/v2/core/server_settings.py +0 -20
  43. zenml/models/v2/misc/full_stack.py +32 -0
  44. zenml/models/v2/misc/stack_deployment.py +5 -0
  45. zenml/new/pipelines/run_utils.py +1 -1
  46. zenml/orchestrators/__init__.py +4 -0
  47. zenml/orchestrators/step_launcher.py +1 -0
  48. zenml/orchestrators/wheeled_orchestrator.py +147 -0
  49. zenml/service_connectors/service_connector_utils.py +408 -0
  50. zenml/stack_deployments/azure_stack_deployment.py +179 -0
  51. zenml/stack_deployments/gcp_stack_deployment.py +13 -4
  52. zenml/stack_deployments/stack_deployment.py +10 -0
  53. zenml/stack_deployments/utils.py +4 -0
  54. zenml/steps/base_step.py +7 -5
  55. zenml/utils/function_utils.py +1 -1
  56. zenml/utils/pipeline_docker_image_builder.py +8 -0
  57. zenml/utils/source_utils.py +4 -1
  58. zenml/zen_server/dashboard/assets/{404-DpJaNHKF.js → 404-B_YdvmwS.js} +1 -1
  59. zenml/zen_server/dashboard/assets/{@reactflow-DJfzkHO1.js → @reactflow-l_1hUr1S.js} +1 -1
  60. zenml/zen_server/dashboard/assets/{AwarenessChannel-BYDLT2xC.js → AwarenessChannel-CFg5iX4Z.js} +1 -1
  61. zenml/zen_server/dashboard/assets/{CodeSnippet-BkOuRmyq.js → CodeSnippet-Dvkx_82E.js} +1 -1
  62. zenml/zen_server/dashboard/assets/CollapsibleCard-opiuBHHc.js +1 -0
  63. zenml/zen_server/dashboard/assets/{Commands-ZvWR1BRs.js → Commands-DoN1xrEq.js} +1 -1
  64. zenml/zen_server/dashboard/assets/{CopyButton-DVwLkafa.js → CopyButton-Cr7xYEPb.js} +1 -1
  65. zenml/zen_server/dashboard/assets/{CsvVizualization-C2IiqX4I.js → CsvVizualization-Ck-nZ43m.js} +3 -3
  66. zenml/zen_server/dashboard/assets/{Error-CqX0VqW_.js → Error-kLtljEOM.js} +1 -1
  67. zenml/zen_server/dashboard/assets/{ExecutionStatus-BoLUXR9t.js → ExecutionStatus-DguLLgTK.js} +1 -1
  68. zenml/zen_server/dashboard/assets/{Helpbox-LFydyVwh.js → Helpbox-BXUMP21n.js} +1 -1
  69. zenml/zen_server/dashboard/assets/{Infobox-DnENC0sh.js → Infobox-DSt0O-dm.js} +1 -1
  70. zenml/zen_server/dashboard/assets/{InlineAvatar-CbJtYr0t.js → InlineAvatar-xsrsIGE-.js} +1 -1
  71. zenml/zen_server/dashboard/assets/Pagination-C6X-mifw.js +1 -0
  72. zenml/zen_server/dashboard/assets/{SetPassword-BYBdbQDo.js → SetPassword-BXGTWiwj.js} +1 -1
  73. zenml/zen_server/dashboard/assets/{SuccessStep-Nx743hll.js → SuccessStep-DZC60t0x.js} +1 -1
  74. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DF9gSzE0.js → UpdatePasswordSchemas-DGvwFWO1.js} +1 -1
  75. zenml/zen_server/dashboard/assets/{chevron-right-double-BiEMg7rd.js → chevron-right-double-CZBOf6JM.js} +1 -1
  76. zenml/zen_server/dashboard/assets/cloud-only-C_yFCAkP.js +1 -0
  77. zenml/zen_server/dashboard/assets/index-BczVOqUf.js +55 -0
  78. zenml/zen_server/dashboard/assets/index-EpMIKgrI.css +1 -0
  79. zenml/zen_server/dashboard/assets/{login-mutation-BUnVASxp.js → login-mutation-CrHrndTI.js} +1 -1
  80. zenml/zen_server/dashboard/assets/logs-D8k8BVFf.js +1 -0
  81. zenml/zen_server/dashboard/assets/{not-found-B4VnX8gK.js → not-found-DYa4pC-C.js} +1 -1
  82. zenml/zen_server/dashboard/assets/{package-CsUhPmou.js → package-B3fWP-Dh.js} +1 -1
  83. zenml/zen_server/dashboard/assets/page-1h_sD1jz.js +1 -0
  84. zenml/zen_server/dashboard/assets/{page-Sxn82W-5.js → page-1iL8aMqs.js} +1 -1
  85. zenml/zen_server/dashboard/assets/{page-DMOYZppS.js → page-2grKx_MY.js} +1 -1
  86. zenml/zen_server/dashboard/assets/page-5NCOHOsy.js +1 -0
  87. zenml/zen_server/dashboard/assets/{page-JyfeDUfu.js → page-8a4UMKXZ.js} +1 -1
  88. zenml/zen_server/dashboard/assets/{page-Bx6o0ARS.js → page-B6h3iaHJ.js} +1 -1
  89. zenml/zen_server/dashboard/assets/page-BDns21Iz.js +1 -0
  90. zenml/zen_server/dashboard/assets/{page-3efNCDeb.js → page-BhgCDInH.js} +2 -2
  91. zenml/zen_server/dashboard/assets/{page-DKlIdAe5.js → page-Bi-wtWiO.js} +2 -2
  92. zenml/zen_server/dashboard/assets/{page-7zTHbhhI.js → page-BkeAAYwp.js} +1 -1
  93. zenml/zen_server/dashboard/assets/{page-CRTJ0UuR.js → page-BkuQDIf-.js} +1 -1
  94. zenml/zen_server/dashboard/assets/page-BnaevhnB.js +1 -0
  95. zenml/zen_server/dashboard/assets/{page-BEs6jK71.js → page-Bq0YxkLV.js} +1 -1
  96. zenml/zen_server/dashboard/assets/page-Bs2F4eoD.js +2 -0
  97. zenml/zen_server/dashboard/assets/{page-CUZIGO-3.js → page-C6-UGEbH.js} +1 -1
  98. zenml/zen_server/dashboard/assets/{page-Xu8JEjSU.js → page-CCNRIt_f.js} +1 -1
  99. zenml/zen_server/dashboard/assets/{page-DvCvroOM.js → page-CHNxpz3n.js} +1 -1
  100. zenml/zen_server/dashboard/assets/{page-BpSqIf4B.js → page-DgorQFqi.js} +1 -1
  101. zenml/zen_server/dashboard/assets/page-K8ebxVIs.js +1 -0
  102. zenml/zen_server/dashboard/assets/{page-Cx67M0QT.js → page-MFQyIJd3.js} +1 -1
  103. zenml/zen_server/dashboard/assets/page-TgCF0P_U.js +1 -0
  104. zenml/zen_server/dashboard/assets/page-ZnCEe-eK.js +9 -0
  105. zenml/zen_server/dashboard/assets/{page-Dc_7KMQE.js → page-uA5prJGY.js} +1 -1
  106. zenml/zen_server/dashboard/assets/persist-D7HJNBWx.js +1 -0
  107. zenml/zen_server/dashboard/assets/plus-C8WOyCzt.js +1 -0
  108. zenml/zen_server/dashboard/assets/stack-detail-query-Cficsl6d.js +1 -0
  109. zenml/zen_server/dashboard/assets/update-server-settings-mutation-7d8xi1tS.js +1 -0
  110. zenml/zen_server/dashboard/assets/{url-DuQMeqYA.js → url-D7mAQGUM.js} +1 -1
  111. zenml/zen_server/dashboard/index.html +4 -4
  112. zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
  113. zenml/zen_server/dashboard_legacy/index.html +1 -1
  114. zenml/zen_server/dashboard_legacy/{precache-manifest.c8c57fb0d2132b1d3c2119e776b7dfb3.js → precache-manifest.12246c7548e71e2c4438e496360de80c.js} +4 -4
  115. zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
  116. zenml/zen_server/dashboard_legacy/static/js/main.3b27024b.chunk.js +2 -0
  117. zenml/zen_server/dashboard_legacy/static/js/{main.382439a7.chunk.js.map → main.3b27024b.chunk.js.map} +1 -1
  118. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  119. zenml/zen_server/deploy/helm/README.md +2 -2
  120. zenml/zen_server/rbac/utils.py +10 -2
  121. zenml/zen_server/routers/devices_endpoints.py +4 -1
  122. zenml/zen_server/routers/server_endpoints.py +29 -2
  123. zenml/zen_server/routers/service_connectors_endpoints.py +57 -0
  124. zenml/zen_server/routers/steps_endpoints.py +2 -1
  125. zenml/zen_stores/migrations/versions/0.62.0_release.py +23 -0
  126. zenml/zen_stores/migrations/versions/b4fca5241eea_migrate_onboarding_state.py +167 -0
  127. zenml/zen_stores/rest_zen_store.py +4 -0
  128. zenml/zen_stores/schemas/component_schemas.py +14 -0
  129. zenml/zen_stores/schemas/server_settings_schemas.py +23 -11
  130. zenml/zen_stores/sql_zen_store.py +151 -1
  131. {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240726.dist-info}/METADATA +5 -5
  132. {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240726.dist-info}/RECORD +135 -115
  133. zenml/zen_server/dashboard/assets/Pagination-DEbVUupy.js +0 -1
  134. zenml/zen_server/dashboard/assets/chevron-down-D_ZlKMqH.js +0 -1
  135. zenml/zen_server/dashboard/assets/cloud-only-DVbIeckv.js +0 -1
  136. zenml/zen_server/dashboard/assets/index-C_CrU4vI.js +0 -1
  137. zenml/zen_server/dashboard/assets/index-DK1ynKjA.js +0 -55
  138. zenml/zen_server/dashboard/assets/index-inApY3KQ.css +0 -1
  139. zenml/zen_server/dashboard/assets/page-C43QGHTt.js +0 -9
  140. zenml/zen_server/dashboard/assets/page-CR0OG7ss.js +0 -1
  141. zenml/zen_server/dashboard/assets/page-CaopxiU1.js +0 -1
  142. zenml/zen_server/dashboard/assets/page-D7Z399xy.js +0 -1
  143. zenml/zen_server/dashboard/assets/page-D93kd7Xj.js +0 -1
  144. zenml/zen_server/dashboard/assets/page-DMsSn3dv.js +0 -2
  145. zenml/zen_server/dashboard/assets/page-Hus2pr9T.js +0 -1
  146. zenml/zen_server/dashboard/assets/page-TKXERe16.js +0 -1
  147. zenml/zen_server/dashboard/assets/plus-DOeLmm7C.js +0 -1
  148. zenml/zen_server/dashboard/assets/update-server-settings-mutation-CR8e3Sir.js +0 -1
  149. zenml/zen_server/dashboard_legacy/static/js/main.382439a7.chunk.js +0 -2
  150. {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240726.dist-info}/LICENSE +0 -0
  151. {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240726.dist-info}/WHEEL +0 -0
  152. {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240726.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  apiVersion: v2
2
2
  name: zenml
3
- version: "0.61.0"
3
+ version: "0.62.0"
4
4
  description: Open source MLOps framework for portable production ready ML pipelines
5
5
  keywords:
6
6
  - mlops
@@ -20,8 +20,8 @@ ZenML is an open-source MLOps framework designed to help you create robust, main
20
20
  To install the ZenML chart directly from Amazon ECR, use the following command:
21
21
 
22
22
  ```bash
23
- # example command for version 0.61.0
24
- helm install my-zenml oci://public.ecr.aws/zenml/zenml --version 0.61.0
23
+ # example command for version 0.62.0
24
+ helm install my-zenml oci://public.ecr.aws/zenml/zenml --version 0.62.0
25
25
  ```
26
26
 
27
27
  Note: Ensure you have OCI support enabled in your Helm client and that you are authenticated with Amazon ECR.
@@ -103,7 +103,9 @@ def dehydrate_response_model(
103
103
  )
104
104
 
105
105
  dehydrated_values = {}
106
- for key, value in dict(model).items():
106
+ # See `get_subresources_for_model(...)` for a detailed explanation why we
107
+ # need to use `model.__iter__()` here
108
+ for key, value in model.__iter__():
107
109
  dehydrated_values[key] = _dehydrate_value(
108
110
  value, permissions=permissions
109
111
  )
@@ -484,7 +486,13 @@ def get_subresources_for_model(
484
486
  """
485
487
  resources = set()
486
488
 
487
- for value in dict(model).values():
489
+ # We don't want to use `model.model_dump()` here as that recursively
490
+ # converts models to dicts, but we want to preserve those classes for
491
+ # the recursive `_get_subresources_for_value` calls.
492
+ # We previously used `dict(model)` here, but that lead to issues with
493
+ # models overwriting `__getattr__`, this `model.__iter__()` has the same
494
+ # results though.
495
+ for _, value in model.__iter__():
488
496
  resources.update(_get_subresources_for_value(value))
489
497
 
490
498
  return resources
@@ -27,7 +27,7 @@ from zenml.constants import (
27
27
  DEVICES,
28
28
  VERSION_1,
29
29
  )
30
- from zenml.enums import OAuthDeviceStatus
30
+ from zenml.enums import OAuthDeviceStatus, OnboardingStep
31
31
  from zenml.models import (
32
32
  OAuthDeviceFilter,
33
33
  OAuthDeviceInternalUpdate,
@@ -270,6 +270,9 @@ def verify_authorized_device(
270
270
  update=update,
271
271
  )
272
272
 
273
+ store.update_onboarding_state(
274
+ completed_steps={OnboardingStep.DEVICE_VERIFIED}
275
+ )
273
276
  return device_model
274
277
 
275
278
 
@@ -13,12 +13,19 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for authentication (login)."""
15
15
 
16
- from typing import Optional
16
+ from typing import List, Optional
17
17
 
18
18
  from fastapi import APIRouter, Security
19
19
 
20
20
  import zenml
21
- from zenml.constants import ACTIVATE, API, INFO, SERVER_SETTINGS, VERSION_1
21
+ from zenml.constants import (
22
+ ACTIVATE,
23
+ API,
24
+ INFO,
25
+ ONBOARDING_STATE,
26
+ SERVER_SETTINGS,
27
+ VERSION_1,
28
+ )
22
29
  from zenml.enums import AuthScheme
23
30
  from zenml.exceptions import IllegalOperationError
24
31
  from zenml.models import (
@@ -64,6 +71,26 @@ def server_info() -> ServerModel:
64
71
  return zen_store().get_store_info()
65
72
 
66
73
 
74
+ @router.get(
75
+ ONBOARDING_STATE,
76
+ responses={
77
+ 401: error_response,
78
+ 404: error_response,
79
+ 422: error_response,
80
+ },
81
+ )
82
+ @handle_exceptions
83
+ def get_onboarding_state(
84
+ _: AuthContext = Security(authorize),
85
+ ) -> List[str]:
86
+ """Get the onboarding state of the server.
87
+
88
+ Returns:
89
+ The onboarding state of the server.
90
+ """
91
+ return zen_store().get_onboarding_state()
92
+
93
+
67
94
  # We don't have any concrete value that tells us whether a server is a cloud
68
95
  # tenant, so we use `external_server_id` as the best proxy option.
69
96
  # For cloud tenants, we don't add these endpoints as the server settings don't
@@ -21,6 +21,7 @@ from fastapi import APIRouter, Depends, Security
21
21
  from zenml.constants import (
22
22
  API,
23
23
  SERVICE_CONNECTOR_CLIENT,
24
+ SERVICE_CONNECTOR_FULL_STACK,
24
25
  SERVICE_CONNECTOR_TYPES,
25
26
  SERVICE_CONNECTOR_VERIFY,
26
27
  SERVICE_CONNECTORS,
@@ -35,6 +36,13 @@ from zenml.models import (
35
36
  ServiceConnectorTypeModel,
36
37
  ServiceConnectorUpdate,
37
38
  )
39
+ from zenml.models.v2.misc.full_stack import (
40
+ ServiceConnectorInfo,
41
+ ServiceConnectorResourcesInfo,
42
+ )
43
+ from zenml.service_connectors.service_connector_utils import (
44
+ get_resources_options_from_resource_model_for_full_stack,
45
+ )
38
46
  from zenml.zen_server.auth import AuthContext, authorize
39
47
  from zenml.zen_server.exceptions import error_response
40
48
  from zenml.zen_server.rbac.endpoint_utils import (
@@ -393,3 +401,52 @@ def get_service_connector_type(
393
401
  The requested service connector type.
394
402
  """
395
403
  return zen_store().get_service_connector_type(connector_type)
404
+
405
+
406
+ @router.post(
407
+ SERVICE_CONNECTOR_FULL_STACK,
408
+ responses={401: error_response, 409: error_response, 422: error_response},
409
+ )
410
+ @handle_exceptions
411
+ def get_resources_based_on_service_connector_info(
412
+ connector_info: Optional[ServiceConnectorInfo] = None,
413
+ connector_uuid: Optional[UUID] = None,
414
+ _: AuthContext = Security(authorize),
415
+ ) -> ServiceConnectorResourcesInfo:
416
+ """Gets the list of resources that a service connector can access.
417
+
418
+ Args:
419
+ connector_info: The service connector info.
420
+ connector_uuid: The service connector uuid.
421
+
422
+ Returns:
423
+ The list of resources that the service connector configuration has
424
+ access to and consumable from UI/CLI.
425
+
426
+ Raises:
427
+ ValueError: If both connector_info and connector_uuid are provided.
428
+ ValueError: If neither connector_info nor connector_uuid are provided.
429
+ """
430
+ if connector_info is not None and connector_uuid is not None:
431
+ raise ValueError(
432
+ "Only one of connector_info or connector_uuid must be provided."
433
+ )
434
+ if connector_info is None and connector_uuid is None:
435
+ raise ValueError(
436
+ "Either connector_info or connector_uuid must be provided."
437
+ )
438
+
439
+ if connector_info is not None:
440
+ verify_permission(
441
+ resource_type=ResourceType.SERVICE_CONNECTOR, action=Action.CREATE
442
+ )
443
+ elif connector_uuid is not None:
444
+ verify_permission(
445
+ resource_type=ResourceType.SERVICE_CONNECTOR,
446
+ action=Action.READ,
447
+ resource_id=connector_uuid,
448
+ )
449
+
450
+ return get_resources_options_from_resource_model_for_full_stack(
451
+ connector_details=connector_info or connector_uuid # type: ignore[arg-type]
452
+ )
@@ -117,7 +117,8 @@ def create_run_step(
117
117
  pipeline_run = zen_store().get_run(step.pipeline_run_id)
118
118
  verify_permission_for_model(pipeline_run, action=Action.UPDATE)
119
119
 
120
- return zen_store().create_run_step(step_run=step)
120
+ step_response = zen_store().create_run_step(step_run=step)
121
+ return dehydrate_response_model(step_response)
121
122
 
122
123
 
123
124
  @router.get(
@@ -0,0 +1,23 @@
1
+ """Release [0.62.0].
2
+
3
+ Revision ID: 0.62.0
4
+ Revises: b4fca5241eea
5
+ Create Date: 2024-07-15 14:15:45.347033
6
+
7
+ """
8
+
9
+ # revision identifiers, used by Alembic.
10
+ revision = "0.62.0"
11
+ down_revision = "b4fca5241eea"
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,167 @@
1
+ """Migrate onboarding state [b4fca5241eea].
2
+
3
+ Revision ID: b4fca5241eea
4
+ Revises: 0.61.0
5
+ Create Date: 2024-06-20 15:01:22.414801
6
+
7
+ """
8
+
9
+ import json
10
+ from typing import Dict, List
11
+
12
+ import sqlalchemy as sa
13
+ from alembic import op
14
+
15
+ # revision identifiers, used by Alembic.
16
+ revision = "b4fca5241eea"
17
+ down_revision = "0.61.0"
18
+ branch_labels = None
19
+ depends_on = None
20
+
21
+
22
+ ONBOARDING_KEY_MAPPING = {
23
+ "connect_zenml": ["device_verified"],
24
+ "run_first_pipeline": ["pipeline_run", "starter_setup_completed"],
25
+ "run_remote_pipeline": [
26
+ "production_setup_completed",
27
+ ],
28
+ }
29
+
30
+
31
+ def upgrade() -> None:
32
+ """Upgrade database schema and/or data, creating a new revision."""
33
+ connection = op.get_bind()
34
+
35
+ meta = sa.MetaData()
36
+ meta.reflect(only=("server_settings",), bind=connection)
37
+
38
+ server_settings_table = sa.Table("server_settings", meta)
39
+
40
+ existing_onboarding_state = connection.execute(
41
+ sa.select(server_settings_table.c.onboarding_state)
42
+ ).scalar_one_or_none()
43
+
44
+ new_state = []
45
+
46
+ if existing_onboarding_state:
47
+ # There was already an existing onboarding state in the DB
48
+ # -> Migrate to the new server keys
49
+ state = json.loads(existing_onboarding_state)
50
+
51
+ if isinstance(state, Dict):
52
+ for key in state.keys():
53
+ if key in ONBOARDING_KEY_MAPPING:
54
+ new_state.extend(ONBOARDING_KEY_MAPPING[key])
55
+ elif isinstance(state, List):
56
+ # Somehow the state is already converted, probably shouldn't happen
57
+ return
58
+
59
+ # We now query the DB and complete all onboarding steps that we can detect
60
+ # from the database
61
+ meta = sa.MetaData()
62
+ meta.reflect(
63
+ only=(
64
+ "pipeline_run",
65
+ "stack_component",
66
+ "stack",
67
+ "stack_composition",
68
+ "pipeline_deployment",
69
+ ),
70
+ bind=connection,
71
+ )
72
+
73
+ pipeline_run_table = sa.Table("pipeline_run", meta)
74
+ stack_component_table = sa.Table("stack_component", meta)
75
+ stack_table = sa.Table("stack", meta)
76
+ stack_composition_table = sa.Table("stack_composition", meta)
77
+ pipeline_deployment_table = sa.Table("pipeline_deployment", meta)
78
+
79
+ pipeline_run_count = connection.execute(
80
+ sa.select(sa.func.count(pipeline_run_table.c.id))
81
+ ).scalar()
82
+ if pipeline_run_count and pipeline_run_count > 0:
83
+ new_state.extend(ONBOARDING_KEY_MAPPING["run_first_pipeline"])
84
+
85
+ stack_with_remote_orchestrator_count = connection.execute(
86
+ sa.select(sa.func.count(stack_table.c.id))
87
+ .where(stack_composition_table.c.stack_id == stack_table.c.id)
88
+ .where(
89
+ stack_composition_table.c.component_id
90
+ == stack_component_table.c.id
91
+ )
92
+ .where(
93
+ stack_component_table.c.flavor.not_in(["local", "local_docker"])
94
+ )
95
+ .where(stack_component_table.c.type == "orchestrator")
96
+ ).scalar()
97
+ if (
98
+ stack_with_remote_orchestrator_count
99
+ and stack_with_remote_orchestrator_count > 0
100
+ ):
101
+ new_state.append("stack_with_remote_orchestrator_created")
102
+
103
+ pipeline_run_with_remote_artifact_store_count = connection.execute(
104
+ sa.select(sa.func.count(pipeline_run_table.c.id))
105
+ .where(
106
+ pipeline_run_table.c.deployment_id
107
+ == pipeline_deployment_table.c.id
108
+ )
109
+ .where(pipeline_deployment_table.c.stack_id == stack_table.c.id)
110
+ .where(stack_composition_table.c.stack_id == stack_table.c.id)
111
+ .where(
112
+ stack_composition_table.c.component_id
113
+ == stack_component_table.c.id
114
+ )
115
+ .where(stack_component_table.c.flavor != "local")
116
+ .where(stack_component_table.c.type == "artifact_store")
117
+ ).scalar()
118
+ if (
119
+ pipeline_run_with_remote_artifact_store_count
120
+ and pipeline_run_with_remote_artifact_store_count > 0
121
+ ):
122
+ new_state.append("production_setup_completed")
123
+
124
+ pipeline_run_with_remote_orchestrator_count = connection.execute(
125
+ sa.select(sa.func.count(pipeline_run_table.c.id))
126
+ .where(
127
+ pipeline_run_table.c.deployment_id
128
+ == pipeline_deployment_table.c.id
129
+ )
130
+ .where(pipeline_deployment_table.c.stack_id == stack_table.c.id)
131
+ .where(stack_composition_table.c.stack_id == stack_table.c.id)
132
+ .where(
133
+ stack_composition_table.c.component_id
134
+ == stack_component_table.c.id
135
+ )
136
+ .where(
137
+ stack_component_table.c.flavor.not_in(["local", "local_docker"])
138
+ )
139
+ .where(stack_component_table.c.type == "orchestrator")
140
+ ).scalar()
141
+ if (
142
+ pipeline_run_with_remote_orchestrator_count
143
+ and pipeline_run_with_remote_orchestrator_count > 0
144
+ ):
145
+ new_state.append("pipeline_run_with_remote_orchestrator")
146
+ new_state.append("production_setup_completed")
147
+
148
+ if new_state:
149
+ # If any of the items are finished, we also complete the initial
150
+ # onboarding step which is not explicitly tracked in the database
151
+ new_state.append("device_verified")
152
+
153
+ # Remove duplicate keys
154
+ new_state = list(set(new_state))
155
+
156
+ connection.execute(
157
+ sa.update(server_settings_table).values(
158
+ onboarding_state=json.dumps(new_state)
159
+ )
160
+ )
161
+
162
+
163
+ def downgrade() -> None:
164
+ """Downgrade database schema and/or data back to the previous revision."""
165
+ # ### commands auto generated by Alembic - please adjust! ###
166
+ pass
167
+ # ### end Alembic commands ###
@@ -2591,6 +2591,10 @@ class RestZenStore(BaseZenStore):
2591
2591
  response_body = self.get(
2592
2592
  f"{WORKSPACES}/{workspace_name_or_id}{SERVICE_CONNECTORS}{SERVICE_CONNECTOR_RESOURCES}",
2593
2593
  params=params,
2594
+ timeout=max(
2595
+ self.config.http_timeout,
2596
+ SERVICE_CONNECTOR_VERIFY_REQUEST_TIMEOUT,
2597
+ ),
2594
2598
  )
2595
2599
 
2596
2600
  assert isinstance(response_body, list)
@@ -38,6 +38,7 @@ from zenml.zen_stores.schemas.user_schemas import UserSchema
38
38
  from zenml.zen_stores.schemas.workspace_schemas import WorkspaceSchema
39
39
 
40
40
  if TYPE_CHECKING:
41
+ from zenml.zen_stores.schemas.flavor_schemas import FlavorSchema
41
42
  from zenml.zen_stores.schemas.logs_schemas import LogsSchema
42
43
  from zenml.zen_stores.schemas.run_metadata_schemas import RunMetadataSchema
43
44
  from zenml.zen_stores.schemas.schedule_schema import ScheduleSchema
@@ -85,6 +86,13 @@ class StackComponentSchema(NamedSchema, table=True):
85
86
  run_metadata: List["RunMetadataSchema"] = Relationship(
86
87
  back_populates="stack_component",
87
88
  )
89
+ flavor_schema: Optional["FlavorSchema"] = Relationship(
90
+ sa_relationship_kwargs={
91
+ "primaryjoin": "and_(foreign(StackComponentSchema.flavor) == FlavorSchema.name, foreign(StackComponentSchema.type) == FlavorSchema.type)",
92
+ "lazy": "joined",
93
+ "uselist": False,
94
+ },
95
+ )
88
96
 
89
97
  run_or_step_logs: List["LogsSchema"] = Relationship(
90
98
  back_populates="artifact_store",
@@ -161,6 +169,12 @@ class StackComponentSchema(NamedSchema, table=True):
161
169
  user=self.user.to_model() if self.user else None,
162
170
  created=self.created,
163
171
  updated=self.updated,
172
+ logo_url=self.flavor_schema.logo_url
173
+ if self.flavor_schema
174
+ else None,
175
+ integration=self.flavor_schema.integration
176
+ if self.flavor_schema
177
+ else None,
164
178
  )
165
179
  metadata = None
166
180
  if include_metadata:
@@ -15,7 +15,7 @@
15
15
 
16
16
  import json
17
17
  from datetime import datetime
18
- from typing import Any, Optional
18
+ from typing import Any, Optional, Set
19
19
  from uuid import UUID
20
20
 
21
21
  from sqlmodel import Field, SQLModel
@@ -59,16 +59,33 @@ class ServerSettingsSchema(SQLModel, table=True):
59
59
  for field, value in settings_update.model_dump(
60
60
  exclude_unset=True
61
61
  ).items():
62
- if field == "onboarding_state":
63
- if value is not None:
64
- self.onboarding_state = json.dumps(value)
65
- elif hasattr(self, field):
62
+ if hasattr(self, field):
66
63
  setattr(self, field, value)
67
64
 
68
65
  self.updated = datetime.utcnow()
69
66
 
70
67
  return self
71
68
 
69
+ def update_onboarding_state(
70
+ self, completed_steps: Set[str]
71
+ ) -> "ServerSettingsSchema":
72
+ """Update the onboarding state.
73
+
74
+ Args:
75
+ completed_steps: Newly completed onboarding steps.
76
+
77
+ Returns:
78
+ The updated schema.
79
+ """
80
+ old_state = set(
81
+ json.loads(self.onboarding_state) if self.onboarding_state else []
82
+ )
83
+ new_state = old_state.union(completed_steps)
84
+ self.onboarding_state = json.dumps(list(new_state))
85
+ self.updated = datetime.utcnow()
86
+
87
+ return self
88
+
72
89
  def to_model(
73
90
  self,
74
91
  include_metadata: bool = False,
@@ -82,7 +99,6 @@ class ServerSettingsSchema(SQLModel, table=True):
82
99
  include_resources: Whether the resources will be filled.
83
100
  **kwargs: Keyword arguments to allow schema specific logic
84
101
 
85
-
86
102
  Returns:
87
103
  The created `SettingsResponse`.
88
104
  """
@@ -101,11 +117,7 @@ class ServerSettingsSchema(SQLModel, table=True):
101
117
  resources = None
102
118
 
103
119
  if include_metadata:
104
- metadata = ServerSettingsResponseMetadata(
105
- onboarding_state=json.loads(self.onboarding_state)
106
- if self.onboarding_state
107
- else {},
108
- )
120
+ metadata = ServerSettingsResponseMetadata()
109
121
 
110
122
  if include_resources:
111
123
  resources = ServerSettingsResponseResources()