zenml-nightly 0.70.0.dev20241121__py3-none-any.whl → 0.70.0.dev20241123__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 (23) hide show
  1. zenml/VERSION +1 -1
  2. zenml/constants.py +1 -0
  3. zenml/integrations/kubernetes/orchestrators/kube_utils.py +8 -7
  4. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +52 -1
  5. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +11 -1
  6. zenml/integrations/kubernetes/orchestrators/manifest_utils.py +3 -3
  7. zenml/integrations/kubernetes/service_connectors/kubernetes_service_connector.py +2 -1
  8. zenml/models/__init__.py +6 -1
  9. zenml/models/v2/core/service_connector.py +4 -0
  10. zenml/models/v2/misc/server_models.py +23 -0
  11. zenml/zen_server/deploy/helm/templates/_environment.tpl +117 -0
  12. zenml/zen_server/deploy/helm/templates/server-db-job.yaml +3 -14
  13. zenml/zen_server/deploy/helm/templates/server-deployment.yaml +16 -4
  14. zenml/zen_server/deploy/helm/templates/server-secret.yaml +2 -17
  15. zenml/zen_server/routers/server_endpoints.py +47 -0
  16. zenml/zen_server/zen_server_api.py +45 -6
  17. zenml/zen_stores/migrations/utils.py +40 -24
  18. zenml/zen_stores/rest_zen_store.py +38 -1
  19. {zenml_nightly-0.70.0.dev20241121.dist-info → zenml_nightly-0.70.0.dev20241123.dist-info}/METADATA +1 -1
  20. {zenml_nightly-0.70.0.dev20241121.dist-info → zenml_nightly-0.70.0.dev20241123.dist-info}/RECORD +23 -23
  21. {zenml_nightly-0.70.0.dev20241121.dist-info → zenml_nightly-0.70.0.dev20241123.dist-info}/LICENSE +0 -0
  22. {zenml_nightly-0.70.0.dev20241121.dist-info → zenml_nightly-0.70.0.dev20241123.dist-info}/WHEEL +0 -0
  23. {zenml_nightly-0.70.0.dev20241121.dist-info → zenml_nightly-0.70.0.dev20241123.dist-info}/entry_points.txt +0 -0
zenml/VERSION CHANGED
@@ -1 +1 @@
1
- 0.70.0.dev20241121
1
+ 0.70.0.dev20241123
zenml/constants.py CHANGED
@@ -353,6 +353,7 @@ FLAVORS = "/flavors"
353
353
  GET_OR_CREATE = "/get-or-create"
354
354
  HEALTH = "/health"
355
355
  INFO = "/info"
356
+ LOAD_INFO = "/load-info"
356
357
  LOGIN = "/login"
357
358
  LOGOUT = "/logout"
358
359
  LOGS = "/logs"
@@ -42,8 +42,8 @@ from kubernetes import config as k8s_config
42
42
  from kubernetes.client.rest import ApiException
43
43
 
44
44
  from zenml.integrations.kubernetes.orchestrators.manifest_utils import (
45
- build_cluster_role_binding_manifest_for_service_account,
46
45
  build_namespace_manifest,
46
+ build_role_binding_manifest_for_service_account,
47
47
  build_service_account_manifest,
48
48
  )
49
49
  from zenml.logger import get_logger
@@ -288,7 +288,7 @@ def create_edit_service_account(
288
288
  rbac_api: k8s_client.RbacAuthorizationV1Api,
289
289
  service_account_name: str,
290
290
  namespace: str,
291
- cluster_role_binding_name: str = "zenml-edit",
291
+ role_binding_name: str = "zenml-edit",
292
292
  ) -> None:
293
293
  """Create a new Kubernetes service account with "edit" rights.
294
294
 
@@ -297,16 +297,17 @@ def create_edit_service_account(
297
297
  rbac_api: Client of Rbac Authorization V1 API of Kubernetes API.
298
298
  service_account_name: Name of the service account.
299
299
  namespace: Kubernetes namespace. Defaults to "default".
300
- cluster_role_binding_name: Name of the cluster role binding.
301
- Defaults to "zenml-edit".
300
+ role_binding_name: Name of the role binding. Defaults to "zenml-edit".
302
301
  """
303
- crb_manifest = build_cluster_role_binding_manifest_for_service_account(
304
- name=cluster_role_binding_name,
302
+ rb_manifest = build_role_binding_manifest_for_service_account(
303
+ name=role_binding_name,
305
304
  role_name="edit",
306
305
  service_account_name=service_account_name,
307
306
  namespace=namespace,
308
307
  )
309
- _if_not_exists(rbac_api.create_cluster_role_binding)(body=crb_manifest)
308
+ _if_not_exists(rbac_api.create_namespaced_role_binding)(
309
+ namespace=namespace, body=rb_manifest
310
+ )
310
311
 
311
312
  sa_manifest = build_service_account_manifest(
312
313
  name=service_account_name, namespace=namespace
@@ -59,6 +59,7 @@ from zenml.integrations.kubernetes.orchestrators.manifest_utils import (
59
59
  build_cron_job_manifest,
60
60
  build_pod_manifest,
61
61
  )
62
+ from zenml.integrations.kubernetes.pod_settings import KubernetesPodSettings
62
63
  from zenml.logger import get_logger
63
64
  from zenml.orchestrators import ContainerizedOrchestrator
64
65
  from zenml.orchestrators.utils import get_orchestrator_run_name
@@ -328,6 +329,45 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
328
329
  custom_validation_function=_validate_local_requirements,
329
330
  )
330
331
 
332
+ @classmethod
333
+ def apply_default_resource_requests(
334
+ cls,
335
+ memory: str,
336
+ cpu: Optional[str] = None,
337
+ pod_settings: Optional[KubernetesPodSettings] = None,
338
+ ) -> KubernetesPodSettings:
339
+ """Applies default resource requests to a pod settings object.
340
+
341
+ Args:
342
+ memory: The memory resource request.
343
+ cpu: The CPU resource request.
344
+ pod_settings: The pod settings to update. A new one will be created
345
+ if not provided.
346
+
347
+ Returns:
348
+ The new or updated pod settings.
349
+ """
350
+ resources = {
351
+ "requests": {"memory": memory},
352
+ }
353
+ if cpu:
354
+ resources["requests"]["cpu"] = cpu
355
+ if not pod_settings:
356
+ pod_settings = KubernetesPodSettings(resources=resources)
357
+ elif not pod_settings.resources:
358
+ # We can't update the pod settings in place (because it's a frozen
359
+ # pydantic model), so we have to create a new one.
360
+ pod_settings = KubernetesPodSettings(
361
+ **pod_settings.model_dump(exclude_unset=True),
362
+ resources=resources,
363
+ )
364
+ else:
365
+ set_requests = pod_settings.resources.get("requests", {})
366
+ resources["requests"].update(set_requests)
367
+ pod_settings.resources["requests"] = resources["requests"]
368
+
369
+ return pod_settings
370
+
331
371
  def prepare_or_run_pipeline(
332
372
  self,
333
373
  deployment: "PipelineDeploymentResponse",
@@ -422,6 +462,17 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
422
462
  )
423
463
  return
424
464
 
465
+ # We set some default minimum resource requests for the orchestrator pod
466
+ # here if the user has not specified any, because the orchestrator pod
467
+ # takes up some memory resources itself and, if not specified, the pod
468
+ # will be scheduled on any node regardless of available memory and risk
469
+ # negatively impacting or even crashing the node due to memory pressure.
470
+ orchestrator_pod_settings = self.apply_default_resource_requests(
471
+ memory="400Mi",
472
+ cpu="100m",
473
+ pod_settings=settings.orchestrator_pod_settings,
474
+ )
475
+
425
476
  # Create and run the orchestrator pod.
426
477
  pod_manifest = build_pod_manifest(
427
478
  run_name=orchestrator_run_name,
@@ -431,7 +482,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
431
482
  command=command,
432
483
  args=args,
433
484
  privileged=False,
434
- pod_settings=settings.orchestrator_pod_settings,
485
+ pod_settings=orchestrator_pod_settings,
435
486
  service_account_name=service_account_name,
436
487
  env=environment,
437
488
  mount_local_stores=self.config.is_local,
@@ -116,6 +116,16 @@ def main() -> None:
116
116
  env = get_config_environment_vars()
117
117
  env[ENV_ZENML_KUBERNETES_RUN_ID] = orchestrator_run_id
118
118
 
119
+ # We set some default minimum memory resource requests for the step pod
120
+ # here if the user has not specified any, because the step pod takes up
121
+ # some memory resources itself and, if not specified, the pod will be
122
+ # scheduled on any node regardless of available memory and risk
123
+ # negatively impacting or even crashing the node due to memory pressure.
124
+ pod_settings = KubernetesOrchestrator.apply_default_resource_requests(
125
+ memory="400Mi",
126
+ pod_settings=settings.pod_settings,
127
+ )
128
+
119
129
  # Define Kubernetes pod manifest.
120
130
  pod_manifest = build_pod_manifest(
121
131
  pod_name=pod_name,
@@ -126,7 +136,7 @@ def main() -> None:
126
136
  args=step_args,
127
137
  env=env,
128
138
  privileged=settings.privileged,
129
- pod_settings=settings.pod_settings,
139
+ pod_settings=pod_settings,
130
140
  service_account_name=settings.step_pod_service_account_name
131
141
  or settings.service_account_name,
132
142
  mount_local_stores=mount_local_stores,
@@ -304,13 +304,13 @@ def build_cron_job_manifest(
304
304
  return job_manifest
305
305
 
306
306
 
307
- def build_cluster_role_binding_manifest_for_service_account(
307
+ def build_role_binding_manifest_for_service_account(
308
308
  name: str,
309
309
  role_name: str,
310
310
  service_account_name: str,
311
311
  namespace: str = "default",
312
312
  ) -> Dict[str, Any]:
313
- """Build a manifest for a cluster role binding of a service account.
313
+ """Build a manifest for a role binding of a service account.
314
314
 
315
315
  Args:
316
316
  name: Name of the cluster role binding.
@@ -323,7 +323,7 @@ def build_cluster_role_binding_manifest_for_service_account(
323
323
  """
324
324
  return {
325
325
  "apiVersion": "rbac.authorization.k8s.io/v1",
326
- "kind": "ClusterRoleBinding",
326
+ "kind": "RoleBinding",
327
327
  "metadata": {"name": name},
328
328
  "subjects": [
329
329
  {
@@ -26,6 +26,7 @@ from typing import Any, List, Optional
26
26
  from kubernetes import client as k8s_client
27
27
  from kubernetes import config as k8s_config
28
28
  from pydantic import Field
29
+ from urllib3.exceptions import HTTPError
29
30
 
30
31
  from zenml.constants import KUBERNETES_CLUSTER_RESOURCE_TYPE
31
32
  from zenml.exceptions import AuthorizationException
@@ -572,7 +573,7 @@ class KubernetesServiceConnector(ServiceConnector):
572
573
  auth_settings=["BearerToken"],
573
574
  response_type="VersionInfo",
574
575
  )
575
- except k8s_client.ApiException as err:
576
+ except (k8s_client.ApiException, HTTPError) as err:
576
577
  raise AuthorizationException(
577
578
  f"failed to verify Kubernetes cluster access: {err}"
578
579
  ) from err
zenml/models/__init__.py CHANGED
@@ -328,7 +328,11 @@ from zenml.models.v2.misc.service_connector_type import (
328
328
  ServiceConnectorTypedResourcesModel,
329
329
  ResourceTypeModel,
330
330
  )
331
- from zenml.models.v2.misc.server_models import ServerDatabaseType, ServerModel
331
+ from zenml.models.v2.misc.server_models import (
332
+ ServerDatabaseType,
333
+ ServerLoadInfo,
334
+ ServerModel,
335
+ )
332
336
  from zenml.models.v2.core.trigger import (
333
337
  TriggerRequest,
334
338
  TriggerFilter,
@@ -731,6 +735,7 @@ __all__ = [
731
735
  "ExternalUserModel",
732
736
  "BuildItem",
733
737
  "LoadedVisualization",
738
+ "ServerLoadInfo",
734
739
  "ServerModel",
735
740
  "ServerDatabaseType",
736
741
  "ServerDeploymentType",
@@ -488,6 +488,10 @@ class ServiceConnectorResponse(
488
488
  ):
489
489
  """Response model for service connectors."""
490
490
 
491
+ # Disable the warning for updating responses, because we update the
492
+ # service connector type in place
493
+ _warn_on_response_updates: bool = False
494
+
491
495
  name: str = Field(
492
496
  title="The service connector name.",
493
497
  max_length=STR_FIELD_MAX_LENGTH,
@@ -118,3 +118,26 @@ class ServerModel(BaseModel):
118
118
  # Local ZenML servers are identifiable by the fact that their
119
119
  # server ID is the same as the local client (user) ID.
120
120
  return self.id == GlobalConfiguration().user_id
121
+
122
+
123
+ class ServerLoadInfo(BaseModel):
124
+ """Domain model for ZenML server load information."""
125
+
126
+ threads: int = Field(
127
+ title="Number of threads that the server is currently using."
128
+ )
129
+
130
+ db_connections_total: int = Field(
131
+ title="Total number of database connections (active and idle) that the "
132
+ "server currently has established."
133
+ )
134
+
135
+ db_connections_active: int = Field(
136
+ title="Number of database connections that the server is currently "
137
+ "actively using to make queries or transactions."
138
+ )
139
+
140
+ db_connections_overflow: int = Field(
141
+ title="Number of overflow database connections that the server is "
142
+ "currently actively using to make queries or transactions."
143
+ )
@@ -3,6 +3,123 @@ Helpers for environment variables configured in ZenML deployments and secrets st
3
3
  */}}
4
4
 
5
5
 
6
+ {{/*
7
+ ZenML store configuration options (non-secret values).
8
+
9
+ This template constructs a dictionary that is similar to the python values that
10
+ can be configured in the zenml.zen_store.sql_zen_store.SqlZenStoreConfiguration
11
+ class. Only non-secret values are included in this dictionary.
12
+
13
+ The dictionary is then converted into deployment environment variables by other
14
+ templates and inserted where it is needed.
15
+
16
+ The input is taken from a .ZenML dict that is passed to the template and
17
+ contains the values configured in the values.yaml file for the ZenML server.
18
+
19
+ Args:
20
+ .ZenML: A dictionary with the ZenML configuration values configured for the
21
+ ZenML server.
22
+ Returns:
23
+ A dictionary with the non-secret values configured for the ZenML store.
24
+ */}}
25
+ {{- define "zenml.storeConfigurationAttrs" -}}
26
+ {{- if .ZenML.database.url }}
27
+ type: sql
28
+ ssl_verify_server_cert: {{ .ZenML.database.sslVerifyServerCert | default "false" | quote }}
29
+ {{- if .ZenML.database.backupStrategy }}
30
+ backup_strategy: {{ .ZenML.database.backupStrategy | quote }}
31
+ {{- if eq .ZenML.database.backupStrategy "database" }}
32
+ backup_database: {{ .ZenML.database.backupDatabase | quote }}
33
+ {{- else if eq .ZenML.database.backupStrategy "dump-file" }}
34
+ backup_directory: "/backups"
35
+ {{- end }}
36
+ {{- end }}
37
+ {{- if .ZenML.database.poolSize }}
38
+ pool_size: {{ .ZenML.database.poolSize | quote }}
39
+ {{- end }}
40
+ {{- if .ZenML.database.maxOverflow }}
41
+ max_overflow: {{ .ZenML.database.maxOverflow | quote }}
42
+ {{- end }}
43
+ {{- end }}
44
+ {{- end }}
45
+
46
+
47
+ {{/*
48
+ ZenML store configuration options (secret values).
49
+
50
+ This template constructs a dictionary that is similar to the python values that
51
+ can be configured in the zenml.zen_store.sql_zen_store.SqlZenStoreConfiguration
52
+ class. Only secret values are included in this dictionary.
53
+
54
+ The dictionary is then converted into deployment environment variables by other
55
+ templates and inserted where it is needed.
56
+
57
+ The input is taken from a .ZenML dict that is passed to the template and
58
+ contains the values configured in the values.yaml file for the ZenML server.
59
+
60
+ Args:
61
+ .ZenML: A dictionary with the ZenML configuration values configured for the
62
+ ZenML server.
63
+ Returns:
64
+ A dictionary with the secret values configured for the ZenML store.
65
+ */}}
66
+ {{- define "zenml.storeSecretConfigurationAttrs" -}}
67
+ {{- if .ZenML.database.url }}
68
+ url: {{ .ZenML.database.url | quote }}
69
+ {{- if .ZenML.database.sslCa }}
70
+ ssl_ca: {{ .Files.Get .ZenML.database.sslCa }}
71
+ {{- end }}
72
+ {{- if .ZenML.database.sslCert }}
73
+ ssl_cert: {{ .Files.Get .ZenML.database.sslCert }}
74
+ {{- end }}
75
+ {{- if .ZenML.database.sslKey }}
76
+ ssl_key: {{ .Files.Get .ZenML.database.sslKey }}
77
+ {{- end }}
78
+ {{- end }}
79
+ {{- end }}
80
+
81
+
82
+ {{/*
83
+ Store configuration environment variables (non-secret values).
84
+
85
+ Passes the .Values.zenml dict as input to the `zenml.storeConfigurationAttrs`
86
+ template and converts the output into a dictionary of environment variables that
87
+ need to be configured for the store.
88
+
89
+ Args:
90
+ .Values: The values.yaml file for the ZenML deployment.
91
+ Returns:
92
+ A dictionary with the non-secret environment variables that are configured for
93
+ the store (i.e. keys starting with `ZENML_STORE_`).
94
+ */}}
95
+ {{- define "zenml.storeEnvVariables" -}}
96
+ {{ $zenml := dict "ZenML" .Values.zenml }}
97
+ {{- range $k, $v := include "zenml.storeConfigurationAttrs" $zenml | fromYaml }}
98
+ ZENML_STORE_{{ $k | upper }}: {{ $v | quote }}
99
+ {{- end }}
100
+ {{- end }}
101
+
102
+
103
+ {{/*
104
+ Store configuration environment variables (secret values).
105
+
106
+ Passes the .Values.zenml dict as input to the `zenml.storeSecretConfigurationAttrs`
107
+ template and converts the output into a dictionary of environment variables that
108
+ need to be configured for the store.
109
+
110
+ Args:
111
+ .Values: The values.yaml file for the ZenML deployment.
112
+ Returns:
113
+ A dictionary with the secret environment variables that are configured for
114
+ the store (i.e. keys starting with `ZENML_STORE_`).
115
+ */}}
116
+ {{- define "zenml.storeSecretEnvVariables" -}}
117
+ {{ $zenml := dict "ZenML" .Values.zenml }}
118
+ {{- range $k, $v := include "zenml.storeSecretConfigurationAttrs" $zenml | fromYaml }}
119
+ ZENML_STORE_{{ $k | upper }}: {{ $v | quote }}
120
+ {{- end }}
121
+ {{- end }}
122
+
6
123
  {{/*
7
124
  ZenML server configuration options (non-secret values).
8
125
 
@@ -79,20 +79,9 @@ spec:
79
79
  {{- end }}
80
80
  - name: ZENML_DEFAULT_PROJECT_NAME
81
81
  value: {{ .Values.zenml.defaultProject | quote }}
82
- - name: ZENML_STORE_TYPE
83
- value: sql
84
- - name: ZENML_STORE_SSL_VERIFY_SERVER_CERT
85
- value: {{ .Values.zenml.database.sslVerifyServerCert | default "false" | quote }}
86
- {{- if .Values.zenml.database.backupStrategy }}
87
- - name: ZENML_STORE_BACKUP_STRATEGY
88
- value: {{ .Values.zenml.database.backupStrategy | quote }}
89
- {{- if eq .Values.zenml.database.backupStrategy "database" }}
90
- - name: ZENML_STORE_BACKUP_DATABASE
91
- value: {{ .Values.zenml.database.backupDatabase | quote }}
92
- {{- else if eq .Values.zenml.database.backupStrategy "dump-file" }}
93
- - name: ZENML_STORE_BACKUP_DIRECTORY
94
- value: /backups
95
- {{- end }}
82
+ {{- range $k, $v := include "zenml.storeEnvVariables" . | fromYaml }}
83
+ - name: {{ $k }}
84
+ value: {{ $v | quote }}
96
85
  {{- end }}
97
86
  {{- range $k, $v := include "zenml.serverEnvVariables" . | fromYaml }}
98
87
  - name: {{ $k }}
@@ -63,14 +63,14 @@ spec:
63
63
  value: "True"
64
64
  {{- end }}
65
65
  {{- if .Values.zenml.database.url }}
66
- - name: ZENML_STORE_TYPE
67
- value: sql
68
66
  - name: DISABLE_DATABASE_MIGRATION
69
67
  value: "True"
70
- - name: ZENML_STORE_SSL_VERIFY_SERVER_CERT
71
- value: {{ .Values.zenml.database.sslVerifyServerCert | default "false" | quote }}
72
68
  {{- end }}
73
69
 
70
+ {{- range $k, $v := include "zenml.storeEnvVariables" . | fromYaml }}
71
+ - name: {{ $k }}
72
+ value: {{ $v | quote }}
73
+ {{- end }}
74
74
  {{- range $k, $v := include "zenml.serverEnvVariables" . | fromYaml }}
75
75
  - name: {{ $k }}
76
76
  value: {{ $v | quote }}
@@ -104,6 +104,18 @@ spec:
104
104
  httpGet:
105
105
  path: /health
106
106
  port: http
107
+ lifecycle:
108
+ preStop:
109
+ exec:
110
+ # Give the process 15 more seconds before the SIGTERM signal is
111
+ # sent. This allows the endpoint removal to reach the ingress
112
+ # controller in time and for traffic to be routed away from the
113
+ # pod before it is shut down. This eliminates the number of 502
114
+ # errors returned to the user.
115
+ #
116
+ # See https://learnk8s.io/graceful-shutdown for more information.
117
+ #
118
+ command: ["sleep", "15"]
107
119
  resources:
108
120
  {{- toYaml .Values.resources | nindent 12 }}
109
121
  {{- with .Values.nodeSelector }}
@@ -10,23 +10,8 @@ data:
10
10
  {{- else }}
11
11
  ZENML_SERVER_JWT_SECRET_KEY: {{ $prevServerSecret.data.ZENML_SERVER_JWT_SECRET_KEY | default (randAlphaNum 32 | b64enc | quote) }}
12
12
  {{- end }}
13
- {{- if .Values.zenml.database.url }}
14
- ZENML_STORE_URL: {{ .Values.zenml.database.url | b64enc | quote }}
15
- {{- if .Values.zenml.database.sslCa }}
16
- ZENML_STORE_SSL_CA: {{ .Files.Get .Values.zenml.database.sslCa | b64enc }}
17
- {{- end }}
18
- {{- if .Values.zenml.database.sslCert }}
19
- ZENML_STORE_SSL_CERT: {{ .Files.Get .Values.zenml.database.sslCert | b64enc }}
20
- {{- end }}
21
- {{- if .Values.zenml.database.sslKey }}
22
- ZENML_STORE_SSL_KEY: {{ .Files.Get .Values.zenml.database.sslKey | b64enc }}
23
- {{- end }}
24
- {{- if .Values.zenml.database.poolSize }}
25
- ZENML_STORE_POOL_SIZE: {{ .Values.zenml.database.poolSize | b64enc | quote }}
26
- {{- end }}
27
- {{- if .Values.zenml.database.maxOverflow }}
28
- ZENML_STORE_MAX_OVERFLOW: {{ .Values.zenml.database.maxOverflow | b64enc | quote }}
29
- {{- end }}
13
+ {{- range $k, $v := include "zenml.storeSecretEnvVariables" . | fromYaml}}
14
+ {{ $k }}: {{ $v | b64enc | quote }}
30
15
  {{- end }}
31
16
  {{- range $k, $v := include "zenml.secretsStoreSecretEnvVariables" . | fromYaml}}
32
17
  {{ $k }}: {{ $v | b64enc | quote }}
@@ -22,6 +22,7 @@ from zenml.constants import (
22
22
  ACTIVATE,
23
23
  API,
24
24
  INFO,
25
+ LOAD_INFO,
25
26
  ONBOARDING_STATE,
26
27
  SERVER_SETTINGS,
27
28
  VERSION_1,
@@ -30,6 +31,7 @@ from zenml.enums import AuthScheme
30
31
  from zenml.exceptions import IllegalOperationError
31
32
  from zenml.models import (
32
33
  ServerActivationRequest,
34
+ ServerLoadInfo,
33
35
  ServerModel,
34
36
  ServerSettingsResponse,
35
37
  ServerSettingsUpdate,
@@ -71,6 +73,51 @@ def server_info() -> ServerModel:
71
73
  return zen_store().get_store_info()
72
74
 
73
75
 
76
+ @router.get(
77
+ LOAD_INFO,
78
+ response_model=ServerLoadInfo,
79
+ )
80
+ @handle_exceptions
81
+ def server_load_info(_: AuthContext = Security(authorize)) -> ServerLoadInfo:
82
+ """Get information about the server load.
83
+
84
+ Returns:
85
+ Information about the server load.
86
+ """
87
+ import threading
88
+
89
+ # Get the current number of threads
90
+ num_threads = len(threading.enumerate())
91
+
92
+ store = zen_store()
93
+
94
+ if store.config.driver == "sqlite":
95
+ # SQLite doesn't have a connection pool
96
+ return ServerLoadInfo(
97
+ threads=num_threads,
98
+ db_connections_total=0,
99
+ db_connections_active=0,
100
+ db_connections_overflow=0,
101
+ )
102
+
103
+ from sqlalchemy.pool import QueuePool
104
+
105
+ # Get the number of connections
106
+ pool = store.engine.pool
107
+ assert isinstance(pool, QueuePool)
108
+ idle_conn = pool.checkedin()
109
+ active_conn = pool.checkedout()
110
+ overflow_conn = max(0, pool.overflow())
111
+ total_conn = idle_conn + active_conn
112
+
113
+ return ServerLoadInfo(
114
+ threads=num_threads,
115
+ db_connections_total=total_conn,
116
+ db_connections_active=active_conn,
117
+ db_connections_overflow=overflow_conn,
118
+ )
119
+
120
+
74
121
  @router.get(
75
122
  ONBOARDING_STATE,
76
123
  responses={
@@ -180,7 +180,15 @@ class RequestBodyLimit(BaseHTTPMiddleware):
180
180
  if content_length := request.headers.get("content-length"):
181
181
  if int(content_length) > self.max_bytes:
182
182
  return Response(status_code=413) # Request Entity Too Large
183
- return await call_next(request)
183
+
184
+ try:
185
+ return await call_next(request)
186
+ except Exception:
187
+ logger.exception("An error occurred while processing the request")
188
+ return JSONResponse(
189
+ status_code=500,
190
+ content={"detail": "An unexpected error occurred."},
191
+ )
184
192
 
185
193
 
186
194
  class RestrictFileUploadsMiddleware(BaseHTTPMiddleware):
@@ -220,7 +228,15 @@ class RestrictFileUploadsMiddleware(BaseHTTPMiddleware):
220
228
  "detail": "File uploads are not allowed on this endpoint."
221
229
  },
222
230
  )
223
- return await call_next(request)
231
+
232
+ try:
233
+ return await call_next(request)
234
+ except Exception:
235
+ logger.exception("An error occurred while processing the request")
236
+ return JSONResponse(
237
+ status_code=500,
238
+ content={"detail": "An unexpected error occurred."},
239
+ )
224
240
 
225
241
 
226
242
  ALLOWED_FOR_FILE_UPLOAD: Set[str] = set()
@@ -252,13 +268,21 @@ async def set_secure_headers(request: Request, call_next: Any) -> Any:
252
268
  Returns:
253
269
  The response with secure headers set.
254
270
  """
271
+ try:
272
+ response = await call_next(request)
273
+ except Exception:
274
+ logger.exception("An error occurred while processing the request")
275
+ response = JSONResponse(
276
+ status_code=500,
277
+ content={"detail": "An unexpected error occurred."},
278
+ )
279
+
255
280
  # If the request is for the openAPI docs, don't set secure headers
256
281
  if request.url.path.startswith("/docs") or request.url.path.startswith(
257
282
  "/redoc"
258
283
  ):
259
- return await call_next(request)
284
+ return response
260
285
 
261
- response = await call_next(request)
262
286
  secure_headers().framework.fastapi(response)
263
287
  return response
264
288
 
@@ -298,7 +322,15 @@ async def track_last_user_activity(request: Request, call_next: Any) -> Any:
298
322
  zen_store()._update_last_user_activity_timestamp(
299
323
  last_user_activity=last_user_activity
300
324
  )
301
- return await call_next(request)
325
+
326
+ try:
327
+ return await call_next(request)
328
+ except Exception:
329
+ logger.exception("An error occurred while processing the request")
330
+ return JSONResponse(
331
+ status_code=500,
332
+ content={"detail": "An unexpected error occurred."},
333
+ )
302
334
 
303
335
 
304
336
  @app.middleware("http")
@@ -330,7 +362,14 @@ async def infer_source_context(request: Request, call_next: Any) -> Any:
330
362
  )
331
363
  source_context.set(SourceContextTypes.API)
332
364
 
333
- return await call_next(request)
365
+ try:
366
+ return await call_next(request)
367
+ except Exception:
368
+ logger.exception("An error occurred while processing the request")
369
+ return JSONResponse(
370
+ status_code=500,
371
+ content={"detail": "An unexpected error occurred."},
372
+ )
334
373
 
335
374
 
336
375
  @app.on_event("startup")
@@ -273,30 +273,25 @@ class MigrationUtils(BaseModel):
273
273
  + "\n);"
274
274
  )
275
275
 
276
+ # Detect self-referential foreign keys from the table schema
277
+ has_self_referential_foreign_keys = False
278
+ for fk in table.foreign_keys:
279
+ # Check if the foreign key points to the same table
280
+ if fk.column.table == table:
281
+ has_self_referential_foreign_keys = True
282
+ break
283
+
276
284
  # Store the table schema
277
285
  store_db_info(
278
- dict(table=table.name, create_stmt=create_table_stmt)
286
+ dict(
287
+ table=table.name,
288
+ create_stmt=create_table_stmt,
289
+ self_references=has_self_referential_foreign_keys,
290
+ )
279
291
  )
280
292
 
281
293
  # 2. extract the table data in batches
282
-
283
- # If the table has a `created` column, we use it to sort
284
- # the rows in the table starting with the oldest rows.
285
- # This is to ensure that the rows are inserted in the
286
- # correct order, since some tables have inner foreign key
287
- # constraints.
288
- if "created" in table.columns:
289
- order_by = [table.columns["created"]]
290
- else:
291
- order_by = []
292
- if "id" in table.columns:
293
- # If the table has an `id` column, we also use it to sort
294
- # the rows in the table, even if we already use "created"
295
- # to sort the rows. We need a unique field to sort the rows,
296
- # to break the tie between rows with the same "created"
297
- # date, otherwise the same entry might end up multiple times
298
- # in subsequent pages.
299
- order_by.append(table.columns["id"])
294
+ order_by = [col for col in table.primary_key]
300
295
 
301
296
  # Fetch the number of rows in the table
302
297
  row_count = conn.scalar(
@@ -305,7 +300,7 @@ class MigrationUtils(BaseModel):
305
300
 
306
301
  # Fetch the data from the table in batches
307
302
  if row_count is not None:
308
- batch_size = 50
303
+ batch_size = 100
309
304
  for i in range(0, row_count, batch_size):
310
305
  rows = conn.execute(
311
306
  table.select()
@@ -349,6 +344,7 @@ class MigrationUtils(BaseModel):
349
344
 
350
345
  with self.engine.begin() as connection:
351
346
  # read the DB information one JSON object at a time
347
+ self_references: Dict[str, bool] = {}
352
348
  for table_dump in load_db_info():
353
349
  table_name = table_dump["table"]
354
350
  if "create_stmt" in table_dump:
@@ -356,10 +352,22 @@ class MigrationUtils(BaseModel):
356
352
  connection.execute(text(table_dump["create_stmt"]))
357
353
  # Reload the database metadata after creating the table
358
354
  metadata.reflect(bind=self.engine)
355
+ self_references[table_name] = table_dump.get(
356
+ "self_references", False
357
+ )
359
358
 
360
359
  if "data" in table_dump:
361
360
  # insert the data into the database
362
361
  table = metadata.tables[table_name]
362
+ if self_references.get(table_name, False):
363
+ # If the table has self-referential foreign keys, we
364
+ # need to disable the foreign key checks before inserting
365
+ # the rows and re-enable them afterwards. This is because
366
+ # the rows need to be inserted in the correct order to
367
+ # satisfy the foreign key constraints and we don't sort
368
+ # the rows by creation time in the backup.
369
+ connection.execute(text("SET FOREIGN_KEY_CHECKS = 0"))
370
+
363
371
  for row in table_dump["data"]:
364
372
  # Convert column values to the correct type
365
373
  for column in table.columns:
@@ -372,10 +380,18 @@ class MigrationUtils(BaseModel):
372
380
  row[column.name], "utf-8"
373
381
  )
374
382
 
375
- # Insert the rows into the table
376
- connection.execute(
377
- table.insert().values(table_dump["data"])
378
- )
383
+ # Insert the rows into the table in batches
384
+ batch_size = 100
385
+ for i in range(0, len(table_dump["data"]), batch_size):
386
+ connection.execute(
387
+ table.insert().values(
388
+ table_dump["data"][i : i + batch_size]
389
+ )
390
+ )
391
+
392
+ if table_dump.get("self_references", False):
393
+ # Re-enable the foreign key checks after inserting the rows
394
+ connection.execute(text("SET FOREIGN_KEY_CHECKS = 1"))
379
395
 
380
396
  def backup_database_to_file(self, dump_file: str) -> None:
381
397
  """Backup the database to a file.
@@ -4172,7 +4172,44 @@ class RestZenStore(BaseZenStore):
4172
4172
  )
4173
4173
 
4174
4174
  self._session = requests.Session()
4175
- retries = Retry(backoff_factor=0.1, connect=5)
4175
+ # Retries are triggered for idempotent HTTP methods (GET, HEAD, PUT,
4176
+ # OPTIONS and DELETE) on specific HTTP status codes:
4177
+ #
4178
+ # 500: Internal Server Error.
4179
+ # 502: Bad Gateway.
4180
+ # 503: Service Unavailable.
4181
+ # 504: Gateway Timeout.
4182
+ #
4183
+ # This also handles connection level errors, if a connection attempt
4184
+ # fails due to transient issues like:
4185
+ #
4186
+ # DNS resolution errors.
4187
+ # Connection timeouts.
4188
+ # Network disruptions.
4189
+ #
4190
+ # Additional errors retried:
4191
+ #
4192
+ # Read Timeouts: If the server does not send a response within
4193
+ # the timeout period.
4194
+ # Connection Refused: If the server refuses the connection.
4195
+ #
4196
+ retries = Retry(
4197
+ connect=5,
4198
+ read=8,
4199
+ redirect=3,
4200
+ status=10,
4201
+ allowed_methods=["HEAD", "GET", "PUT", "DELETE", "OPTIONS"],
4202
+ status_forcelist=[
4203
+ 408, # Request Timeout
4204
+ 429, # Too Many Requests
4205
+ 500, # Internal Server Error
4206
+ 502, # Bad Gateway
4207
+ 503, # Service Unavailable
4208
+ 504, # Gateway Timeout
4209
+ ],
4210
+ other=3,
4211
+ backoff_factor=0.5,
4212
+ )
4176
4213
  self._session.mount("https://", HTTPAdapter(max_retries=retries))
4177
4214
  self._session.mount("http://", HTTPAdapter(max_retries=retries))
4178
4215
  self._session.verify = self.config.verify_ssl
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zenml-nightly
3
- Version: 0.70.0.dev20241121
3
+ Version: 0.70.0.dev20241123
4
4
  Summary: ZenML: Write production-ready ML code.
5
5
  Home-page: https://zenml.io
6
6
  License: Apache-2.0
@@ -6,7 +6,7 @@ RELEASE_NOTES.md,sha256=DleauURHESDrTrcVzCVLqPiSM9NIAk5vldvEFMc7qlk,389375
6
6
  ROADMAP.md,sha256=hiLSmr16BH8Dfx7SaQM4JcXCGCVl6mFZPFAwJeDTrJU,407
7
7
  SECURITY.md,sha256=9DepA8y03yvCZLHEfcXLTDH4lUyKHquAdukBsccNN7c,682
8
8
  zenml/README.md,sha256=827dekbOWAs1BpW7VF1a4d7EbwPbjwccX-2zdXBENZo,1777
9
- zenml/VERSION,sha256=U9A6JmZhhVaPCdj0aOCf-zsjD-I3GNwCUbZgWqoUzcs,19
9
+ zenml/VERSION,sha256=1pkGnXXN0MI-JgdzWePG_NTdxMEH6ZiGUAgvqKjMt8I,19
10
10
  zenml/__init__.py,sha256=SkMObQA41ajqdZqGErN00S1Vf3KAxpLvbZ-OBy5uYoo,2130
11
11
  zenml/actions/__init__.py,sha256=mrt6wPo73iKRxK754_NqsGyJ3buW7RnVeIGXr1xEw8Y,681
12
12
  zenml/actions/base_action.py,sha256=UcaHev6BTuLDwuswnyaPjdA8AgUqB5xPZ-lRtuvf2FU,25553
@@ -92,7 +92,7 @@ zenml/config/step_run_info.py,sha256=KiVRSTtKmZ1GbvseDTap2imr7XwMHD3jSFVpyLNEK1I
92
92
  zenml/config/store_config.py,sha256=Cla5p5dTB6nNlo8_OZDs9hod5hspi64vxwtZj882XgU,3559
93
93
  zenml/config/strict_base_model.py,sha256=iHnO9qOmLUP_eiy9IjRr3JjIs1l1I_CsRQ76EyAneYU,860
94
94
  zenml/console.py,sha256=hj_KerPQKwnyKACj0ehSqUQX0mGVCJBKE1QvCt6ik3A,1160
95
- zenml/constants.py,sha256=BECrnvYZz00baqIZXu_B2pvw8nFg7iiK4oeopXRaRBg,15470
95
+ zenml/constants.py,sha256=3q5HCgYG314SRiLhlfZuXr50G42REjEDEdg2N1r4kjs,15495
96
96
  zenml/container_registries/__init__.py,sha256=ZSPbBIOnzhg88kQSpYgKe_POLuru14m629665-kAVAA,2200
97
97
  zenml/container_registries/azure_container_registry.py,sha256=t1sfDa94Vzbyqtb1iPFNutJ2EXV5_p9CUNITasoiQ70,2667
98
98
  zenml/container_registries/base_container_registry.py,sha256=6c2e32wuqxYHJXm5OV2LY1MtX9yopB7WZtes9fmTAz0,7625
@@ -337,15 +337,15 @@ zenml/integrations/kubernetes/flavors/__init__.py,sha256=a5gU45qCj3FkLwl_uVjlIkL
337
337
  zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py,sha256=HkCyDWqv1lDd8W6GeXE6PeHQiUrHPfSkfw3sB0B2xuA,7911
338
338
  zenml/integrations/kubernetes/flavors/kubernetes_step_operator_flavor.py,sha256=ILN-H4cl7z3i4ltb4UBs55wbtIo871b4ib28pYkQoyQ,5605
339
339
  zenml/integrations/kubernetes/orchestrators/__init__.py,sha256=TJID3OTieZBox36WpQpzD0jdVRA_aZVcs_bNtfXS8ik,811
340
- zenml/integrations/kubernetes/orchestrators/kube_utils.py,sha256=o5yfxHt3hPGc6ki5Pzr_FRcUk-KNUh2PTxRUlVnUVCI,10639
341
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py,sha256=CSnnZ3EgUcsPFHtRAezWgdRuJUrKqQGlKE-TTjl0uUQ,20340
342
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py,sha256=Jbi32O6tOHxRpIBxRMVNsiniHzALHkggOUf6STCZy38,5835
340
+ zenml/integrations/kubernetes/orchestrators/kube_utils.py,sha256=9PSr1wAR7qGjrtsSrIT00P-5c3eFcVV2tzXzTbH9WOc,10615
341
+ zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py,sha256=ElvTfgDEKnhFKLy1TL7v-34Paq9v5rXkXN4Otzonvig,22418
342
+ zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py,sha256=hGvBUnUPhpjudDfumiLLSDsNU2fJR1C-BEPJ671h-VY,6383
343
343
  zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint_configuration.py,sha256=Y7uGU8eksMluGyXYsf688CwpiXwI_W6WYLscYwRZXRY,2494
344
- zenml/integrations/kubernetes/orchestrators/manifest_utils.py,sha256=LZwhoQDXrklD9p1Esx4yEWVQaZmrnXmkQ5CxgzjRXGg,11388
344
+ zenml/integrations/kubernetes/orchestrators/manifest_utils.py,sha256=HS8FDu8m9bDFpnmJ5RCe0ZH57F__xqIuo6Fo7wJkL7E,11365
345
345
  zenml/integrations/kubernetes/pod_settings.py,sha256=NMp4aHKRG29mh1Nq5uvV78Hzj1cMZj93poWCBiwov-M,4898
346
346
  zenml/integrations/kubernetes/serialization_utils.py,sha256=cPSe4szdBLzDnUZT9nQc2CCA8h84aj5oTA8vsUE36ig,7000
347
347
  zenml/integrations/kubernetes/service_connectors/__init__.py,sha256=Uf6zlHIapYrRDl3xOPWQ2jA7jt85SXx1U7DmSxzxTvQ,818
348
- zenml/integrations/kubernetes/service_connectors/kubernetes_service_connector.py,sha256=IbVWwKEXG7PZay1lj3Q1VNAlap4qGxjhE4yIW9_0tIc,19525
348
+ zenml/integrations/kubernetes/service_connectors/kubernetes_service_connector.py,sha256=kgdh25dOBNTxLAFft_cknwHoWRAGrdzUu9fLsm4ZlfY,19579
349
349
  zenml/integrations/kubernetes/step_operators/__init__.py,sha256=40utDPYAezxHsFgO0UUIT_6XpCDzDapje6OH951XsTs,806
350
350
  zenml/integrations/kubernetes/step_operators/kubernetes_step_operator.py,sha256=sEz8IZkzo0qarnPCr8zarBPHR0T0i6HL8r9nSNHQBxI,8310
351
351
  zenml/integrations/label_studio/__init__.py,sha256=tXmK0Wu_bFgtL7CqPPubSK99PaBZSyAu90aghHlXAek,1520
@@ -610,7 +610,7 @@ zenml/model_deployers/__init__.py,sha256=oVBLtTfrNenl5OI1iqtQUvJ0vpocRVUN_HIt8qp
610
610
  zenml/model_deployers/base_model_deployer.py,sha256=Xg5lxBFYM41vqxQhaB54Dxu_zLCyPDgqwrTyMcAxiS4,24609
611
611
  zenml/model_registries/__init__.py,sha256=wA9Vzo0w_e9zuXOVURB9w8oMLSnTaimXcxg_Nb7O3b0,1238
612
612
  zenml/model_registries/base_model_registry.py,sha256=nK__C6IfoIRxnOHA9qyPErLvIsbakyac4ZltUZ8t3tk,17526
613
- zenml/models/__init__.py,sha256=aqBc6ajFfwqfDDwJ7HdAmM3Bf0EaQAaJyvG9mdITO80,21411
613
+ zenml/models/__init__.py,sha256=qvtG0rL4g_CawBAjqsrqkPJ8RcISGJwk6Cd0nIlwGhE,21466
614
614
  zenml/models/v2/__init__.py,sha256=LGMIUJi19sOsvo54roZSQwDp_czNQYtenqd_frTLIhU,613
615
615
  zenml/models/v2/base/__init__.py,sha256=knhroJ2h0uHBCGzAiBBGJEiuhEA3cwI6XYBRIyXdbkQ,613
616
616
  zenml/models/v2/base/base.py,sha256=tXzNTIwGNz7MEgfii3-6ASBNFg4SkR9D9ZM48tlNr84,16242
@@ -648,7 +648,7 @@ zenml/models/v2/core/secret.py,sha256=HK6nTCPDzgS9qXPqWR6YxKEPaLzYQpLypHbHfy63gV
648
648
  zenml/models/v2/core/server_settings.py,sha256=al6LAXhoQHsBiTv2qlwFn1AlI2F8miogGB4xjDE6KeA,6267
649
649
  zenml/models/v2/core/service.py,sha256=KDdnlITBqM0Rq-vEoxGLcerS6bOqAWCMFC4qE6Z71iY,15251
650
650
  zenml/models/v2/core/service_account.py,sha256=-1c9Et9Ma4_OHOZxIHjVnLJAaLLxhpoLEyGKkwc1Yx8,6619
651
- zenml/models/v2/core/service_connector.py,sha256=aCWWtEhFCaxlfTl9M9y6JhBb2501RnVDLS7O45FJyD0,37575
651
+ zenml/models/v2/core/service_connector.py,sha256=NNTSG1pSSMjM1u7eagBdQ4dxVNfpIBLEZNxTK6vHU8Y,37730
652
652
  zenml/models/v2/core/stack.py,sha256=1Cc3bE8KhcBNA-jprTs5iARdQlIAYTM0UcTIYfYPBo0,12699
653
653
  zenml/models/v2/core/step_run.py,sha256=48_nWoXxq5W8h6u04ummFQFcFAA9vQ8qNS69hUAHyEI,19195
654
654
  zenml/models/v2/core/tag.py,sha256=gQNkxmcksMxx5RJf1U_ug5-VxPhfaS11j--J3dl6muk,3534
@@ -663,7 +663,7 @@ zenml/models/v2/misc/build_item.py,sha256=66Fywatv8bDY86pf0k530fsHTk_L4IkHL6uJL7
663
663
  zenml/models/v2/misc/external_user.py,sha256=_prXznyVA3Dc5pCK7nVE72K3tjxslG_e3JxIXLIikBo,944
664
664
  zenml/models/v2/misc/info_models.py,sha256=3X6HFIlFcz5uuT7qgU18HqZBPkgrGZQ7QcM2yBT0qeU,2645
665
665
  zenml/models/v2/misc/loaded_visualization.py,sha256=u6lapDNZDtU9eS-_EMzl00urj0yPNhiqhZcvjIz7DSg,946
666
- zenml/models/v2/misc/server_models.py,sha256=1T18aaclRBKuZ5pEHSCCNIPaTAWKcLC60M48wC6xDew,3732
666
+ zenml/models/v2/misc/server_models.py,sha256=cRm_ItouirAPgCfX2YxrQrRSL2ABDmpqKtFEXKIQH8w,4474
667
667
  zenml/models/v2/misc/service_connector_type.py,sha256=jGJLvIsBB87ZIEeZCLLueUf28H1QJFqXOJYtiRVvZ4M,28748
668
668
  zenml/models/v2/misc/stack_deployment.py,sha256=PgQevLjvHTpsecY_rzrXesr7jiGms7rH_QbFtI2ZIaA,3768
669
669
  zenml/models/v2/misc/user_auth.py,sha256=1-yafNA9qK4wL8ToROjaklTVI7Mj9va0t80_4wm7w3U,6988
@@ -982,15 +982,15 @@ zenml/zen_server/deploy/helm/.helmignore,sha256=u5h-ao70WpklXR1jKBJILV8PMlXqhBUg
982
982
  zenml/zen_server/deploy/helm/Chart.yaml,sha256=1q33ZrjALQdB8w-InBShRPnL4fcKfHRo_YwktZX5H54,333
983
983
  zenml/zen_server/deploy/helm/README.md,sha256=x6_gW8BZXSusNp_XzafZ2i5XaYUDJl2xgZ9kvv5sXb8,1777
984
984
  zenml/zen_server/deploy/helm/templates/NOTES.txt,sha256=1APbGHYNf5cKDyDXkTYE3ybVBSPrYiSJh4dKCUOtH2c,1977
985
- zenml/zen_server/deploy/helm/templates/_environment.tpl,sha256=4tPmEJZc2V1grGuxZQCPvfMUdn4iVt4sNnA8AZlxrEs,14494
985
+ zenml/zen_server/deploy/helm/templates/_environment.tpl,sha256=yZd8zNaWqaYjJOf19P_dfPBxyeAubGxJYt86U4LLcTA,18578
986
986
  zenml/zen_server/deploy/helm/templates/_helpers.tpl,sha256=SuPztyigDEA00ftUfQtDCNK25RWZB4x58BXthNLJKJA,2042
987
987
  zenml/zen_server/deploy/helm/templates/cert-secret.yaml,sha256=VYA-0FfdF4hACYAsww8NjFL9JTuDUJTUbO8ud_Dveqo,1565
988
988
  zenml/zen_server/deploy/helm/templates/hpa.yaml,sha256=wORGNZ7-vL89PHPmyx5bR5TpDXECbyiqu0py1uOWsds,987
989
- zenml/zen_server/deploy/helm/templates/server-db-job.yaml,sha256=GeN2nr5Uo-xwpotutfMBwlETnNGV62uxu_lc-ZHCPHg,5047
989
+ zenml/zen_server/deploy/helm/templates/server-db-job.yaml,sha256=r4-mnxwuPpXtpg-_O9T_dhw0iMkVg7R4Do07pIsVoFE,4425
990
990
  zenml/zen_server/deploy/helm/templates/server-db-pvc.yaml,sha256=ghpBSOtjxL6aoVzYphTytAojCD0T5lP3c3dwIB-1SLw,820
991
- zenml/zen_server/deploy/helm/templates/server-deployment.yaml,sha256=d9IGRIKi3ejWs20XjblmQ57NIGnhSEfPurfihoPjSyE,4147
991
+ zenml/zen_server/deploy/helm/templates/server-deployment.yaml,sha256=cbVqp3dah5rsQFol1gqLU8asTj4-m3-Oz8utLChPDmw,4692
992
992
  zenml/zen_server/deploy/helm/templates/server-ingress.yaml,sha256=cgbxnKLPwzJyFqTW9GfT7nKRxG2LYPTsGBVnfrM7r3E,2274
993
- zenml/zen_server/deploy/helm/templates/server-secret.yaml,sha256=2lHBqmsD7zT5DjNAE-dN-bbcdip-APCW-fzGO3YWlSc,2551
993
+ zenml/zen_server/deploy/helm/templates/server-secret.yaml,sha256=VBObN90vWC8z5iQq6uwLS2YnMlU_30MfRJ-A32WAzuQ,1873
994
994
  zenml/zen_server/deploy/helm/templates/server-service.yaml,sha256=PEYcze_4pKINKW_PbTv0vAvcXRctXuZ9jN0axqLfPFI,367
995
995
  zenml/zen_server/deploy/helm/templates/serviceaccount.yaml,sha256=4qX970F0O_SR1HSAMugyYAvwSN_63CqQofU4jV0YJO4,826
996
996
  zenml/zen_server/deploy/helm/templates/tests/test-connection.yaml,sha256=DPuf5tBRFLlxGLi8XgIbTG9nxaGn-8Z_oIkYJKjFBNs,379
@@ -1028,7 +1028,7 @@ zenml/zen_server/routers/run_templates_endpoints.py,sha256=2l5WCMo-kaGi0pxsAjvIz
1028
1028
  zenml/zen_server/routers/runs_endpoints.py,sha256=G0BXeAiYsbND5ddJcUNV8qu1lpNwRZy47x7g2b61Dj8,9322
1029
1029
  zenml/zen_server/routers/schedule_endpoints.py,sha256=1JtCV2VEZOnN_QriVyMccqStZueEfeY8A1jhCTzfBXM,3870
1030
1030
  zenml/zen_server/routers/secrets_endpoints.py,sha256=kvSGDLczeTBK8mXOisjEKsti1dudeUsIGkiY0ABhgo0,8242
1031
- zenml/zen_server/routers/server_endpoints.py,sha256=HH4guJQUspZ9PhqqqeaV9FyM3Z6i2mqYmmSnuMwupGA,5306
1031
+ zenml/zen_server/routers/server_endpoints.py,sha256=W0EIZURFgJbMqWjpgqn8cIfyeSz-EXw0t1i4H5DK86I,6519
1032
1032
  zenml/zen_server/routers/service_accounts_endpoints.py,sha256=CJOMngUPGnVILQr3fsjlgzCqnA02uYkUQzOLikI1sd4,12166
1033
1033
  zenml/zen_server/routers/service_connectors_endpoints.py,sha256=D8Y5-OSo9OpO0P6ugom1_pqxfxayiZ9kZfWIuOP79CU,14696
1034
1034
  zenml/zen_server/routers/service_endpoints.py,sha256=PyAxQLewVnpotfQI_OmyUTl7ohTCrWrteA9nfvxDRyU,5055
@@ -1047,7 +1047,7 @@ zenml/zen_server/template_execution/runner_entrypoint_configuration.py,sha256=Y8
1047
1047
  zenml/zen_server/template_execution/utils.py,sha256=4pCh2aw6uLzbIDT3WE0QLbXvtlmA-eqmK0vKMkdv92w,16075
1048
1048
  zenml/zen_server/template_execution/workload_manager_interface.py,sha256=CL9c7z8ajuZE01DaHmdCDCZmsroDcTarvN-nE8jv6qQ,2590
1049
1049
  zenml/zen_server/utils.py,sha256=zJDG2xiZucbbreN7Ziqy8qXw9XdS2iYRm4kZhfxnHj0,17163
1050
- zenml/zen_server/zen_server_api.py,sha256=BQpLs_8vccn4KT_AzV4aNpVEHRWbtSHQLXIcOYmCgkU,16203
1050
+ zenml/zen_server/zen_server_api.py,sha256=NzwRCqZTTdzhCrFy2u1Rt5fbHEr_Wojw6z7Xto_JdGE,17466
1051
1051
  zenml/zen_stores/__init__.py,sha256=6LTgH6XwDeDxKqVJ1JTfGhmS8II1NLopPloINGmdyI0,691
1052
1052
  zenml/zen_stores/base_zen_store.py,sha256=ULUuDiymnbdKOPkg1qPZdaojDtJ5le3L9znFOKqk25U,15592
1053
1053
  zenml/zen_stores/migrations/README.md,sha256=x04jsb6EOP6PBEGMQlDELiqKEham2O-iztAs9AylMFc,4898
@@ -1055,7 +1055,7 @@ zenml/zen_stores/migrations/__init__.py,sha256=N9CHfdz0AZ6KniQ450VCIV3H0CuWtx83A
1055
1055
  zenml/zen_stores/migrations/alembic.py,sha256=JDqx7Md6DxnHtP3xrZG1I0cNv6NyTR0oO3tPRUPaS2I,7455
1056
1056
  zenml/zen_stores/migrations/env.py,sha256=hN6GqD2toKL-r9y0FFAf2seJfr79Mzaeqslh5kObcos,1730
1057
1057
  zenml/zen_stores/migrations/script.py.mako,sha256=wTJhgE4DA8I2iVA29sfx74WLfbi3GBnXEwGnH5nNj4s,695
1058
- zenml/zen_stores/migrations/utils.py,sha256=WuZ7cHmMkUViBU3QkVCwg69ZB-hcy6jE2BfTYZcrwBk,26446
1058
+ zenml/zen_stores/migrations/utils.py,sha256=DLPqkVpk3Pli1lEMpcPxRQInQaogEr1iri6vUyLK2YE,27280
1059
1059
  zenml/zen_stores/migrations/versions/0.21.0_release.py,sha256=5FoOdsRLifIC10GQBx3C7cSthPM3wtuzO4heMXgTbcY,444
1060
1060
  zenml/zen_stores/migrations/versions/0.21.1_release.py,sha256=SLWTKX1s6yN2xUEDe2-9_sRMqBjJPr1Je_I7JZTf1r8,432
1061
1061
  zenml/zen_stores/migrations/versions/0.22.0_release.py,sha256=bxpLvwzqSin2RuT-uYK4DWl1D92ldvhJ_QVdRFub8DE,444
@@ -1223,7 +1223,7 @@ zenml/zen_stores/migrations/versions/ec6307720f92_simplify_model_version_links.p
1223
1223
  zenml/zen_stores/migrations/versions/f3b3964e3a0f_add_oauth_devices.py,sha256=2CR4R-7Vx6j_AXxo-e5Guy6OX-ZnS47HSKSGfqlO-y0,3065
1224
1224
  zenml/zen_stores/migrations/versions/f49904a80aa7_increase_length_of_artifact_table_sources.py,sha256=kLgfDUnQdAb5_SyFx3VKXDLC0YbuBKf9iXRDNeBin7Q,1618
1225
1225
  zenml/zen_stores/migrations/versions/fbd7f18ced1e_increase_step_run_field_lengths.py,sha256=kn-ng5EHe_mmLfffIFbz7T59z-to3oMx8III_4wOsz4,1956
1226
- zenml/zen_stores/rest_zen_store.py,sha256=kwxTjYg4MmM-_m64sCbn49bwh9JgRrSy9W_FIafO8dQ,156021
1226
+ zenml/zen_stores/rest_zen_store.py,sha256=0gnuy7iz_5mGVYsTs0NY9qlljTvAG9FaT9Fq70INwjk,157455
1227
1227
  zenml/zen_stores/schemas/__init__.py,sha256=D0T3cSqZ1wIewUI181WD76iY2pLyKX4HWCbx6JjXR7I,4266
1228
1228
  zenml/zen_stores/schemas/action_schemas.py,sha256=vNnDF4zRy0eWgNwtcU7yY0JXyqe4I3Nns2LHRHWwiDs,6293
1229
1229
  zenml/zen_stores/schemas/api_key_schemas.py,sha256=pCvoTSXSHz-im6aRt-opSBnmIhw3wDRIsi-NJP5WtCQ,7243
@@ -1269,8 +1269,8 @@ zenml/zen_stores/secrets_stores/sql_secrets_store.py,sha256=Bq1djrUP9saoD7vECjS7
1269
1269
  zenml/zen_stores/sql_zen_store.py,sha256=v9aIoBght-Pjivr2OYxvANBOhSqx8cUOzZh0G_oJOnw,404327
1270
1270
  zenml/zen_stores/template_utils.py,sha256=EKYBgmDLTS_PSMWaIO5yvHPLiQvMqHcsAe6NUCrv-i4,9068
1271
1271
  zenml/zen_stores/zen_store_interface.py,sha256=vf2gKBWfUUPtcGZC35oQB6pPNVzWVyQC8nWxVLjfrxM,92692
1272
- zenml_nightly-0.70.0.dev20241121.dist-info/LICENSE,sha256=wbnfEnXnafPbqwANHkV6LUsPKOtdpsd-SNw37rogLtc,11359
1273
- zenml_nightly-0.70.0.dev20241121.dist-info/METADATA,sha256=Ne0aSwSkHDL9NdqpSzjpDKUTitWOiOe3pB8b6eCJRyM,21208
1274
- zenml_nightly-0.70.0.dev20241121.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
1275
- zenml_nightly-0.70.0.dev20241121.dist-info/entry_points.txt,sha256=QK3ETQE0YswAM2mWypNMOv8TLtr7EjnqAFq1br_jEFE,43
1276
- zenml_nightly-0.70.0.dev20241121.dist-info/RECORD,,
1272
+ zenml_nightly-0.70.0.dev20241123.dist-info/LICENSE,sha256=wbnfEnXnafPbqwANHkV6LUsPKOtdpsd-SNw37rogLtc,11359
1273
+ zenml_nightly-0.70.0.dev20241123.dist-info/METADATA,sha256=NYFNgPuwPNlWcIrFfTQ6o-Kw6t42VBpzmInvJDOAnpI,21208
1274
+ zenml_nightly-0.70.0.dev20241123.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
1275
+ zenml_nightly-0.70.0.dev20241123.dist-info/entry_points.txt,sha256=QK3ETQE0YswAM2mWypNMOv8TLtr7EjnqAFq1br_jEFE,43
1276
+ zenml_nightly-0.70.0.dev20241123.dist-info/RECORD,,