zenml-nightly 0.61.0.dev20240712__py3-none-any.whl → 0.61.0.dev20240713__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.
zenml/VERSION CHANGED
@@ -1 +1 @@
1
- 0.61.0.dev20240712
1
+ 0.61.0.dev20240713
zenml/constants.py CHANGED
@@ -392,6 +392,7 @@ STEPS = "/steps"
392
392
  TAGS = "/tags"
393
393
  TRIGGERS = "/triggers"
394
394
  TRIGGER_EXECUTIONS = "/trigger_executions"
395
+ ONBOARDING_STATE = "/onboarding_state"
395
396
  USERS = "/users"
396
397
  URL = "/url"
397
398
  VERSION_1 = "/v1"
zenml/enums.py CHANGED
@@ -386,6 +386,21 @@ class PluginSubType(StrEnum):
386
386
  PIPELINE_RUN = "pipeline_run"
387
387
 
388
388
 
389
+ class OnboardingStep(StrEnum):
390
+ """All onboarding steps."""
391
+
392
+ DEVICE_VERIFIED = "device_verified"
393
+ PIPELINE_RUN = "pipeline_run"
394
+ STARTER_SETUP_COMPLETED = "starter_setup_completed"
395
+ STACK_WITH_REMOTE_ORCHESTRATOR_CREATED = (
396
+ "stack_with_remote_orchestrator_created"
397
+ )
398
+ PIPELINE_RUN_WITH_REMOTE_ORCHESTRATOR = (
399
+ "pipeline_run_with_remote_orchestrator"
400
+ )
401
+ PRODUCTION_SETUP_COMPLETED = "production_setup_completed"
402
+
403
+
389
404
  class StackDeploymentProvider(StrEnum):
390
405
  """All possible stack deployment providers."""
391
406
 
@@ -240,8 +240,6 @@ class StepLogsStorage:
240
240
 
241
241
  # Immutable filesystems state
242
242
  self.last_merge_time = time.time()
243
- self.log_files_not_merged: List[str] = []
244
- self.next_merged_file_name: str = self._get_timestamped_filename()
245
243
 
246
244
  @property
247
245
  def artifact_store(self) -> "BaseArtifactStore":
@@ -279,13 +277,16 @@ class StepLogsStorage:
279
277
  or time.time() - self.last_save_time >= self.time_interval
280
278
  )
281
279
 
282
- def _get_timestamped_filename(self) -> str:
280
+ def _get_timestamped_filename(self, suffix: str = "") -> str:
283
281
  """Returns a timestamped filename.
284
282
 
283
+ Args:
284
+ suffix: optional suffix for the file name
285
+
285
286
  Returns:
286
287
  The timestamped filename.
287
288
  """
288
- return f"{time.time()}{LOGS_EXTENSION}"
289
+ return f"{time.time()}{suffix}{LOGS_EXTENSION}"
289
290
 
290
291
  def save_to_file(self, force: bool = False) -> None:
291
292
  """Method to save the buffer to the given URI.
@@ -302,12 +303,7 @@ class StepLogsStorage:
302
303
  try:
303
304
  if self.buffer:
304
305
  if self.artifact_store.config.IS_IMMUTABLE_FILESYSTEM:
305
- if not self.log_files_not_merged:
306
- self.next_merged_file_name = (
307
- self._get_timestamped_filename()
308
- )
309
306
  _logs_uri = self._get_timestamped_filename()
310
- self.log_files_not_merged.append(_logs_uri)
311
307
  with self.artifact_store.open(
312
308
  os.path.join(
313
309
  self.logs_uri,
@@ -346,42 +342,40 @@ class StepLogsStorage:
346
342
  and time.time() - self.last_merge_time > self.merge_files_interval
347
343
  ):
348
344
  try:
349
- self.merge_log_files(
350
- self.next_merged_file_name, self.log_files_not_merged
351
- )
345
+ self.merge_log_files()
352
346
  except (OSError, IOError) as e:
353
347
  logger.error(f"Error while trying to roll up logs: {e}")
354
- else:
355
- self.log_files_not_merged = []
356
348
  finally:
357
349
  self.last_merge_time = time.time()
358
350
 
359
- def merge_log_files(
360
- self,
361
- file_name: Optional[str] = None,
362
- files: Optional[List[str]] = None,
363
- ) -> None:
351
+ def merge_log_files(self, merge_all_files: bool = False) -> None:
364
352
  """Merges all log files into one in the given URI.
365
353
 
366
354
  Called on the logging context exit.
367
355
 
368
356
  Args:
369
- file_name: The name of the merged log file.
370
- files: The list of log files to merge.
357
+ merge_all_files: whether to merge all files or only raw files
371
358
  """
372
359
  if self.artifact_store.config.IS_IMMUTABLE_FILESYSTEM:
373
- files_ = files or self.artifact_store.listdir(self.logs_uri)
374
- file_name_ = file_name or self._get_timestamped_filename()
360
+ merged_file_suffix = "_merged"
361
+ files_ = self.artifact_store.listdir(self.logs_uri)
362
+ if not merge_all_files:
363
+ # already merged files will not be merged again
364
+ files_ = [f for f in files_ if merged_file_suffix not in f]
365
+ file_name_ = self._get_timestamped_filename(
366
+ suffix=merged_file_suffix
367
+ )
375
368
  if len(files_) > 1:
376
369
  files_.sort()
377
370
  logger.debug("Log files count: %s", len(files_))
378
371
 
379
- try:
380
- # dump all logs to a local file first
381
- with self.artifact_store.open(
382
- os.path.join(self.logs_uri, file_name_), "w"
383
- ) as merged_file:
384
- for file in files_:
372
+ missing_files = set()
373
+ # dump all logs to a local file first
374
+ with self.artifact_store.open(
375
+ os.path.join(self.logs_uri, file_name_), "w"
376
+ ) as merged_file:
377
+ for file in files_:
378
+ try:
385
379
  merged_file.write(
386
380
  str(
387
381
  _load_file_from_artifact_store(
@@ -391,11 +385,12 @@ class StepLogsStorage:
391
385
  )
392
386
  )
393
387
  )
394
- except Exception as e:
395
- logger.warning(f"Failed to merge log files. {e}")
396
- else:
397
- # clean up left over files
398
- for file in files_:
388
+ except DoesNotExistException:
389
+ missing_files.add(file)
390
+
391
+ # clean up left over files
392
+ for file in files_:
393
+ if file not in missing_files:
399
394
  self.artifact_store.remove(
400
395
  os.path.join(self.logs_uri, str(file))
401
396
  )
@@ -452,7 +447,6 @@ class StepLogsStorageContext:
452
447
  Restores the `write` method of both stderr and stdout.
453
448
  """
454
449
  self.storage.save_to_file(force=True)
455
- self.storage.merge_log_files()
456
450
 
457
451
  setattr(sys.stdout, "write", self.stdout_write)
458
452
  setattr(sys.stdout, "flush", self.stdout_flush)
@@ -462,6 +456,11 @@ class StepLogsStorageContext:
462
456
 
463
457
  redirected.set(False)
464
458
 
459
+ try:
460
+ self.storage.merge_log_files(merge_all_files=True)
461
+ except (OSError, IOError) as e:
462
+ logger.warning(f"Step logs roll-up failed: {e}")
463
+
465
464
  def _wrap_write(self, method: Callable[..., Any]) -> Callable[..., Any]:
466
465
  """Wrapper function that utilizes the storage object to store logs.
467
466
 
@@ -15,8 +15,6 @@
15
15
 
16
16
  from datetime import datetime
17
17
  from typing import (
18
- Any,
19
- Dict,
20
18
  Optional,
21
19
  )
22
20
  from uuid import UUID
@@ -57,10 +55,6 @@ class ServerSettingsUpdate(BaseZenModel):
57
55
  default=None,
58
56
  title="Whether to display notifications about ZenML updates in the dashboard.",
59
57
  )
60
- onboarding_state: Optional[Dict[str, Any]] = Field(
61
- default=None,
62
- title="The server's onboarding state.",
63
- )
64
58
 
65
59
 
66
60
  # ------------------ Response Model ------------------
@@ -96,11 +90,6 @@ class ServerSettingsResponseBody(BaseResponseBody):
96
90
  class ServerSettingsResponseMetadata(BaseResponseMetadata):
97
91
  """Response metadata for server settings."""
98
92
 
99
- onboarding_state: Dict[str, Any] = Field(
100
- default={},
101
- title="The server's onboarding state.",
102
- )
103
-
104
93
 
105
94
  class ServerSettingsResponseResources(BaseResponseResources):
106
95
  """Response resources for server settings."""
@@ -199,15 +188,6 @@ class ServerSettingsResponse(
199
188
  """
200
189
  return self.get_body().updated
201
190
 
202
- @property
203
- def onboarding_state(self) -> Dict[str, Any]:
204
- """The `onboarding_state` property.
205
-
206
- Returns:
207
- the value of the property.
208
- """
209
- return self.get_metadata().onboarding_state
210
-
211
191
 
212
192
  # ------------------ Filter Model ------------------
213
193
 
@@ -291,6 +291,7 @@ class StepLauncher:
291
291
  logger.error(
292
292
  f"Failed to run step `{self._step_name}` after {max_retries} retries. Exiting."
293
293
  )
294
+ logger.exception(e)
294
295
  publish_utils.publish_failed_step_run(
295
296
  step_run_response.id
296
297
  )
@@ -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
@@ -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 ###
@@ -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()
@@ -33,6 +33,7 @@ from typing import (
33
33
  NoReturn,
34
34
  Optional,
35
35
  Sequence,
36
+ Set,
36
37
  Tuple,
37
38
  Type,
38
39
  TypeVar,
@@ -107,6 +108,7 @@ from zenml.enums import (
107
108
  ExecutionStatus,
108
109
  LoggingLevels,
109
110
  ModelStages,
111
+ OnboardingStep,
110
112
  SecretScope,
111
113
  SecretsStoreType,
112
114
  SorterOps,
@@ -797,6 +799,7 @@ class SqlZenStore(BaseZenStore):
797
799
  _secrets_store: Optional[BaseSecretsStore] = None
798
800
  _backup_secrets_store: Optional[BaseSecretsStore] = None
799
801
  _should_send_user_enriched_events: bool = False
802
+ _cached_onboarding_state: Optional[Set[str]] = None
800
803
 
801
804
  @property
802
805
  def secrets_store(self) -> "BaseSecretsStore":
@@ -1688,6 +1691,60 @@ class SqlZenStore(BaseZenStore):
1688
1691
 
1689
1692
  return settings.to_model(include_metadata=True)
1690
1693
 
1694
+ def get_onboarding_state(self) -> List[str]:
1695
+ """Get the server onboarding state.
1696
+
1697
+ Returns:
1698
+ The server onboarding state.
1699
+ """
1700
+ with Session(self.engine) as session:
1701
+ settings = self._get_server_settings(session=session)
1702
+ if settings.onboarding_state:
1703
+ self._cached_onboarding_state = set(
1704
+ json.loads(settings.onboarding_state)
1705
+ )
1706
+ return list(self._cached_onboarding_state)
1707
+ else:
1708
+ return []
1709
+
1710
+ def _update_onboarding_state(
1711
+ self, completed_steps: Set[str], session: Session
1712
+ ) -> None:
1713
+ """Update the server onboarding state.
1714
+
1715
+ Args:
1716
+ completed_steps: Newly completed onboarding steps.
1717
+ session: DB session.
1718
+ """
1719
+ if self._cached_onboarding_state and completed_steps.issubset(
1720
+ self._cached_onboarding_state
1721
+ ):
1722
+ # All the onboarding steps are already completed, no need to query
1723
+ # the DB
1724
+ return
1725
+
1726
+ settings = self._get_server_settings(session=session)
1727
+ settings.update_onboarding_state(completed_steps=completed_steps)
1728
+ session.add(settings)
1729
+ session.commit()
1730
+ session.refresh(settings)
1731
+
1732
+ assert settings.onboarding_state
1733
+ self._cached_onboarding_state = set(
1734
+ json.loads(settings.onboarding_state)
1735
+ )
1736
+
1737
+ def update_onboarding_state(self, completed_steps: Set[str]) -> None:
1738
+ """Update the server onboarding state.
1739
+
1740
+ Args:
1741
+ completed_steps: Newly completed onboarding steps.
1742
+ """
1743
+ with Session(self.engine) as session:
1744
+ self._update_onboarding_state(
1745
+ completed_steps=completed_steps, session=session
1746
+ )
1747
+
1691
1748
  def activate_server(
1692
1749
  self, request: ServerActivationRequest
1693
1750
  ) -> Optional[UserResponse]:
@@ -6156,6 +6213,7 @@ class SqlZenStore(BaseZenStore):
6156
6213
 
6157
6214
  connector = new_service_connector.to_model(include_metadata=True)
6158
6215
  self._populate_connector_type(connector)
6216
+
6159
6217
  return connector
6160
6218
 
6161
6219
  def get_service_connector(
@@ -6931,6 +6989,16 @@ class SqlZenStore(BaseZenStore):
6931
6989
  session.commit()
6932
6990
  session.refresh(new_stack_schema)
6933
6991
 
6992
+ for component in defined_components:
6993
+ if component.type == StackComponentType.ORCHESTRATOR:
6994
+ if component.flavor not in {"local", "local_docker"}:
6995
+ self._update_onboarding_state(
6996
+ completed_steps={
6997
+ OnboardingStep.STACK_WITH_REMOTE_ORCHESTRATOR_CREATED
6998
+ },
6999
+ session=session,
7000
+ )
7001
+
6934
7002
  return new_stack_schema.to_model(include_metadata=True)
6935
7003
 
6936
7004
  def create_full_stack(self, full_stack: FullStackRequest) -> StackResponse:
@@ -7965,6 +8033,25 @@ class SqlZenStore(BaseZenStore):
7965
8033
  "duration_seconds": duration_seconds,
7966
8034
  **stack_metadata,
7967
8035
  }
8036
+
8037
+ completed_onboarding_steps: Set[str] = {
8038
+ OnboardingStep.PIPELINE_RUN,
8039
+ OnboardingStep.STARTER_SETUP_COMPLETED,
8040
+ }
8041
+ if stack_metadata["orchestrator"] not in {
8042
+ "local",
8043
+ "local_docker",
8044
+ }:
8045
+ completed_onboarding_steps.update(
8046
+ {
8047
+ OnboardingStep.PIPELINE_RUN_WITH_REMOTE_ORCHESTRATOR,
8048
+ OnboardingStep.PRODUCTION_SETUP_COMPLETED,
8049
+ }
8050
+ )
8051
+
8052
+ self._update_onboarding_state(
8053
+ completed_steps=completed_onboarding_steps, session=session
8054
+ )
7968
8055
  pipeline_run.update(run_update)
7969
8056
  session.add(pipeline_run)
7970
8057
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zenml-nightly
3
- Version: 0.61.0.dev20240712
3
+ Version: 0.61.0.dev20240713
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=QX-qMBwv_5sgXDWCD4qm_tDuS40koSG9_DcurceMbbs,346147
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=J_ZbgQP040774BQrgFlpNpaT5fgN135ofVCMkhs-La4,19
9
+ zenml/VERSION,sha256=zdDg4SeQ8mwdeK2Q8EeO9An9CEJbh0Sp53nB8w5CTo8,19
10
10
  zenml/__init__.py,sha256=qT3QHiuTgUwk05sOiML0Gcjre3pugvDAw84_br9Psvo,2394
11
11
  zenml/_hub/__init__.py,sha256=6qDzpQAAZa__Aiiz0mC1qM-9dw9_jk_v_aXeJknxbDE,644
12
12
  zenml/_hub/client.py,sha256=Um2df1JO7-BmNm65efHSPpV5e0GITuoQJmod_wkdvbw,9136
@@ -98,7 +98,7 @@ zenml/config/step_run_info.py,sha256=KiVRSTtKmZ1GbvseDTap2imr7XwMHD3jSFVpyLNEK1I
98
98
  zenml/config/store_config.py,sha256=Cla5p5dTB6nNlo8_OZDs9hod5hspi64vxwtZj882XgU,3559
99
99
  zenml/config/strict_base_model.py,sha256=iHnO9qOmLUP_eiy9IjRr3JjIs1l1I_CsRQ76EyAneYU,860
100
100
  zenml/console.py,sha256=hj_KerPQKwnyKACj0ehSqUQX0mGVCJBKE1QvCt6ik3A,1160
101
- zenml/constants.py,sha256=TXabPTaskDcyOS8ae066RPjCfifIPLHAqa2Sdat2z_o,16165
101
+ zenml/constants.py,sha256=a3yTgw2_KOCDDE-9bOOU6XApNR5Wrfo_LobBUVhCY-A,16204
102
102
  zenml/container_registries/__init__.py,sha256=ZSPbBIOnzhg88kQSpYgKe_POLuru14m629665-kAVAA,2200
103
103
  zenml/container_registries/azure_container_registry.py,sha256=t1sfDa94Vzbyqtb1iPFNutJ2EXV5_p9CUNITasoiQ70,2667
104
104
  zenml/container_registries/base_container_registry.py,sha256=6c2e32wuqxYHJXm5OV2LY1MtX9yopB7WZtes9fmTAz0,7625
@@ -113,7 +113,7 @@ zenml/entrypoints/base_entrypoint_configuration.py,sha256=8dD_TRMUAXbRj6XNboQjyz
113
113
  zenml/entrypoints/entrypoint.py,sha256=XNgXBCMKoidmP0_AYgMpqo-neG8Y8jG0rj43ofTDZ9E,2033
114
114
  zenml/entrypoints/pipeline_entrypoint_configuration.py,sha256=To-vTP29qAE36ndJDF1fRw9wL2Nk2bsBuO-ayAwvSmo,1646
115
115
  zenml/entrypoints/step_entrypoint_configuration.py,sha256=NskQF6OFFCIoD7v0JxR_cZRVXBRaKl3R0fwqpaQCPLM,6571
116
- zenml/enums.py,sha256=6UJkKnk4gS5SHLCs7-ETs13uV6fSjttRjKOrMT2qTyk,9573
116
+ zenml/enums.py,sha256=3_SpffPCzk0MRPUiqKl20qGyq6UOBHzK6F58we7pEDo,10033
117
117
  zenml/environment.py,sha256=xqsj8G-qr_W2KyyWnJABMsNQ7Tl32MUhFir7kUDPpKc,20276
118
118
  zenml/event_hub/__init__.py,sha256=-fD9mPOslf4J-_XFBPp5gYlPz7-6ZaAKHa5jxf_nyAo,757
119
119
  zenml/event_hub/base_event_hub.py,sha256=jqVdy2ix5JyaVV08DHTqyFn1NP03GWtBQXgbjQdm_fo,6574
@@ -533,7 +533,7 @@ zenml/lineage_graph/node/base_node.py,sha256=-eH0CcxXkrfF_F1NhV1jMFzbjHvolpjl_od
533
533
  zenml/lineage_graph/node/step_node.py,sha256=Tr9HbkBgcvpjKamX5cwPZM7i5LE66kU84_ATzVmKeMg,1300
534
534
  zenml/logger.py,sha256=5K5csgOLAecvUOYWWSaqirgkC1sZkZ4Ka7JALAGL_Ik,6131
535
535
  zenml/logging/__init__.py,sha256=lnqbOa31wAHwPP5f8vZazOrUwnP2QviLiIVwxoAefD8,975
536
- zenml/logging/step_logging.py,sha256=dDl0uWtH6Z4rFB94f0BfsPIuSxGmPu6sdlWIhqYYMDI,17297
536
+ zenml/logging/step_logging.py,sha256=2wy2yNiFScV2Bnj6alN9gmgDpM2NxekfShuGsWumhig,17165
537
537
  zenml/materializers/__init__.py,sha256=YE4Eh-ftvnfKaqbwz4TylODPCGHBdMj2lJFjNtmjoko,1767
538
538
  zenml/materializers/base_materializer.py,sha256=zvuden4-YQ1SO_lgwuenmt54xuUyFg-dw0aKqXKDDKg,10291
539
539
  zenml/materializers/built_in_materializer.py,sha256=HrnsqirUnYI-f1MV8sr6YSVqkBdEfYJsjSLkf5CHUsE,14963
@@ -591,7 +591,7 @@ zenml/models/v2/core/pipeline_run.py,sha256=Vf3JSBnSAtGaYf4p2nTwQrmeJmh5pdUykqvZ
591
591
  zenml/models/v2/core/run_metadata.py,sha256=u7c3LtZikb6EY6uwhXuqSIcaOgb0jDfGU8tQt3Ccerk,7863
592
592
  zenml/models/v2/core/schedule.py,sha256=QE6_2KFmamGMClS7-sE43hyNBfkVnml6rDqvmRmyiB8,10215
593
593
  zenml/models/v2/core/secret.py,sha256=HK6nTCPDzgS9qXPqWR6YxKEPaLzYQpLypHbHfy63gVc,11815
594
- zenml/models/v2/core/server_settings.py,sha256=-1CW5waT22MuaGVkMRkBgtZx8TOLSiGuPbfUYfA1a_M,6422
594
+ zenml/models/v2/core/server_settings.py,sha256=19d5N7KnR-bOX6pIs2qorXzN36K_yzmL73m8Mbsy6ec,5920
595
595
  zenml/models/v2/core/service.py,sha256=KDdnlITBqM0Rq-vEoxGLcerS6bOqAWCMFC4qE6Z71iY,15251
596
596
  zenml/models/v2/core/service_account.py,sha256=-1c9Et9Ma4_OHOZxIHjVnLJAaLLxhpoLEyGKkwc1Yx8,6619
597
597
  zenml/models/v2/core/service_connector.py,sha256=aCWWtEhFCaxlfTl9M9y6JhBb2501RnVDLS7O45FJyD0,37575
@@ -639,7 +639,7 @@ zenml/orchestrators/local_docker/__init__.py,sha256=k8J68ydy6HmmvE9tWo32g761H8P_
639
639
  zenml/orchestrators/local_docker/local_docker_orchestrator.py,sha256=kzxvmKwEi7ihXfeoopIUwipSorvpB4Lw2pdCAOcZaZ0,9190
640
640
  zenml/orchestrators/output_utils.py,sha256=Gz7SX2cbQ3w4eyfU0XuhKEKGtalQGBoc6moDRNVHN8M,3311
641
641
  zenml/orchestrators/publish_utils.py,sha256=aNwgTDmVSq9qCDP3Ldk77YNXnWx_YHjYNTEJwYeZo9s,4579
642
- zenml/orchestrators/step_launcher.py,sha256=uEJ55LtE_oVT8jp6seiifRaj5wkBPAzG1pGgliD6KbM,21241
642
+ zenml/orchestrators/step_launcher.py,sha256=oP7n4q3VAPo_fWaae8c9ZWYlSRPQXO8fumG88chIKg0,21293
643
643
  zenml/orchestrators/step_runner.py,sha256=xOBaR7NOClzhZivMN-mjhLEvt309jE5XagFC9tyOwjI,26457
644
644
  zenml/orchestrators/topsort.py,sha256=D8evz3X47zwpXd90NMLsJD-_uCeXtV6ClzNfDUrq7cM,5784
645
645
  zenml/orchestrators/utils.py,sha256=NhmN2nCSOAfAvFOa6V4iPgGnXh6xJTIwnuUzqG5g1GM,10504
@@ -1093,7 +1093,7 @@ zenml/zen_server/routers/artifact_endpoint.py,sha256=XhbOat2pddDluiT0a_QH2RfNcql
1093
1093
  zenml/zen_server/routers/artifact_version_endpoints.py,sha256=o9RVrnzuiY-AV6Nj10YwXQ_jy-OqCVMk1hEKfmihPEQ,7751
1094
1094
  zenml/zen_server/routers/auth_endpoints.py,sha256=Xc-RHTfZ3HT_o7IhR2HQSSGKKh97w70lNI_mOHhx2Ys,19301
1095
1095
  zenml/zen_server/routers/code_repositories_endpoints.py,sha256=WFCRPsv3Qrm8QtCr5zxfSdgCS5WI1DPNCF4Y6vLXGow,4747
1096
- zenml/zen_server/routers/devices_endpoints.py,sha256=2YoVb_a3fEjsYs8wMQYkzz9qM0n3ylHB6yTVNmhIVRU,10598
1096
+ zenml/zen_server/routers/devices_endpoints.py,sha256=luqj7owGuQ-2LyAC6Pka7GjEVpYpfi_QDdFKXhWlXek,10712
1097
1097
  zenml/zen_server/routers/event_source_endpoints.py,sha256=dXupWrySV3LtxsqMVoYpUJ-OK7q6o6ehfuYW_RU1JlA,10379
1098
1098
  zenml/zen_server/routers/flavors_endpoints.py,sha256=6NDfPmPyhtCqUhGc-moYFRugJNp7gjxbSN479iJ4gTI,5462
1099
1099
  zenml/zen_server/routers/model_versions_endpoints.py,sha256=9F2np2xbZJqvg_Rla0R0Pt_l-5dLpLMIoLnh7NU-tnI,11190
@@ -1106,7 +1106,7 @@ zenml/zen_server/routers/run_metadata_endpoints.py,sha256=qWIk_Vh7WA-oOU1hZdf8bl
1106
1106
  zenml/zen_server/routers/runs_endpoints.py,sha256=32T6bcQDpaVD17ilHQ4ga1gA5hTgCjInuHl1ciJ3q78,7320
1107
1107
  zenml/zen_server/routers/schedule_endpoints.py,sha256=1JtCV2VEZOnN_QriVyMccqStZueEfeY8A1jhCTzfBXM,3870
1108
1108
  zenml/zen_server/routers/secrets_endpoints.py,sha256=kvSGDLczeTBK8mXOisjEKsti1dudeUsIGkiY0ABhgo0,8242
1109
- zenml/zen_server/routers/server_endpoints.py,sha256=jF_FUIE5vhhzt_rCySSvCfCOEL3WqT5XPkLj5RYUS4Y,4842
1109
+ zenml/zen_server/routers/server_endpoints.py,sha256=HH4guJQUspZ9PhqqqeaV9FyM3Z6i2mqYmmSnuMwupGA,5306
1110
1110
  zenml/zen_server/routers/service_accounts_endpoints.py,sha256=CJOMngUPGnVILQr3fsjlgzCqnA02uYkUQzOLikI1sd4,12166
1111
1111
  zenml/zen_server/routers/service_connectors_endpoints.py,sha256=Imf1WAKUiATPiQsiWl_LLUlcAQ8EnlIOyLEArpLT1OQ,12734
1112
1112
  zenml/zen_server/routers/service_endpoints.py,sha256=PyAxQLewVnpotfQI_OmyUTl7ohTCrWrteA9nfvxDRyU,5055
@@ -1260,6 +1260,7 @@ zenml/zen_stores/migrations/versions/a91762e6be36_artifact_version_table.py,sha2
1260
1260
  zenml/zen_stores/migrations/versions/ade72effebaf_added_logs_table.py,sha256=BP-WuS8xSM0fUARtTxzge3g9AyznNPU7OX3N3tgx6Sw,1963
1261
1261
  zenml/zen_stores/migrations/versions/alembic_start.py,sha256=707q8fI4cwfLzBqVcVqqt5aF_H9i5eI5AHWkjrt_sb0,15702
1262
1262
  zenml/zen_stores/migrations/versions/b4eccf34dfa3_add_hub_token_to_user_model.py,sha256=j9ifD7KC18pgzyCIL6tDa4rRpWi7uDY97pFvV-abTpc,1075
1263
+ zenml/zen_stores/migrations/versions/b4fca5241eea_migrate_onboarding_state.py,sha256=LMBNtkegu2nPJaxAm8Ko7YLk_9RwPiB4p5dN_go6NSs,5518
1263
1264
  zenml/zen_stores/migrations/versions/bea8a6ce3015_port_flavors_into_database.py,sha256=HjSbEr-6MG-7HFeOiwaPPU6L9x1n5TqqA5oP0Z8tqNs,1759
1264
1265
  zenml/zen_stores/migrations/versions/c1b18cec3a48_increase_length_on_flavor_config_schema.py,sha256=dT8Syk1RosuMjy-686xQusb_n0qMIUtXD_gNLwkKvE8,1295
1265
1266
  zenml/zen_stores/migrations/versions/cc9894cb58aa_add_user_metadata.py,sha256=68aSlpqz3lzXvtxmZOKL5SFvF8VIpf5Gb8a3wdgZ0Ic,1100
@@ -1296,7 +1297,7 @@ zenml/zen_stores/schemas/run_metadata_schemas.py,sha256=pWu-WO0PCITPY5gcIB1uqGBW
1296
1297
  zenml/zen_stores/schemas/schedule_schema.py,sha256=w3tAHt2mEQ7ILPz4ogRdLV4KivB7E2LtIZWkzXLzAIU,7354
1297
1298
  zenml/zen_stores/schemas/schema_utils.py,sha256=2qPNPfasnTmCW1RPeViXoTAp6oO-uRnUpEZ_rugcoNw,2612
1298
1299
  zenml/zen_stores/schemas/secret_schemas.py,sha256=nRzFkgR940BbS1nlBs4H3YuvFCiGGYZ1vQIsu3Y0Mvk,9884
1299
- zenml/zen_stores/schemas/server_settings_schemas.py,sha256=G9SILXlsqBa7NTPIeFv8XWzlfzQpdNqHk0XwWKuUGUY,3772
1300
+ zenml/zen_stores/schemas/server_settings_schemas.py,sha256=HTw0cmHqRz1p2gPJH7okx1LH9bgHHcHvaU7Da_n85lQ,4060
1300
1301
  zenml/zen_stores/schemas/service_connector_schemas.py,sha256=yDDpgRRkghlrzNS-fIGCmffZoSuvi_w0ItIVu1asHU8,10061
1301
1302
  zenml/zen_stores/schemas/service_schemas.py,sha256=YCcp0sD4C9vPzCxND83AerkNR5adG6fHostGtaq9yr8,9583
1302
1303
  zenml/zen_stores/schemas/stack_schemas.py,sha256=PakmqLso3c-xS4dHtDm5GteaZt1mcap_12i7uSaMWFU,5579
@@ -1315,10 +1316,10 @@ zenml/zen_stores/secrets_stores/hashicorp_secrets_store.py,sha256=NfW1EHIA99lseb
1315
1316
  zenml/zen_stores/secrets_stores/secrets_store_interface.py,sha256=Q2Jbnt2Pp7NGlR-u1YBfRZV2g8su2Fd0ArBMdksAE-Q,2819
1316
1317
  zenml/zen_stores/secrets_stores/service_connector_secrets_store.py,sha256=kPYX-Z_OOhZCI1CP77ncfV7IsV4e8brklnTXmKxZYNc,7078
1317
1318
  zenml/zen_stores/secrets_stores/sql_secrets_store.py,sha256=Bq1djrUP9saoD7vECjS7-TlA_7sjJGgw1talri4spjU,8656
1318
- zenml/zen_stores/sql_zen_store.py,sha256=MBj7YrXBGnvKSJiLeOPsQWiot5XZD6890zdFFg8gD9c,375538
1319
+ zenml/zen_stores/sql_zen_store.py,sha256=K4FAR764dyEKFwDZTCHgnfseTx_tBtvHNSdnTWywGx8,378688
1319
1320
  zenml/zen_stores/zen_store_interface.py,sha256=ZcgPtlAMdO5die42Hwd6l8glxHYsxFjzuCBewIu5Hrs,91984
1320
- zenml_nightly-0.61.0.dev20240712.dist-info/LICENSE,sha256=wbnfEnXnafPbqwANHkV6LUsPKOtdpsd-SNw37rogLtc,11359
1321
- zenml_nightly-0.61.0.dev20240712.dist-info/METADATA,sha256=IzT-VTOUswnu1zTuc8eMvAwjGZlAHjn_gRnEBwQ1eoo,21026
1322
- zenml_nightly-0.61.0.dev20240712.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1323
- zenml_nightly-0.61.0.dev20240712.dist-info/entry_points.txt,sha256=QK3ETQE0YswAM2mWypNMOv8TLtr7EjnqAFq1br_jEFE,43
1324
- zenml_nightly-0.61.0.dev20240712.dist-info/RECORD,,
1321
+ zenml_nightly-0.61.0.dev20240713.dist-info/LICENSE,sha256=wbnfEnXnafPbqwANHkV6LUsPKOtdpsd-SNw37rogLtc,11359
1322
+ zenml_nightly-0.61.0.dev20240713.dist-info/METADATA,sha256=nFmlH7fqGw_3DTUrXZniESS-3SNhzwR9tTtW4HYLfds,21026
1323
+ zenml_nightly-0.61.0.dev20240713.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1324
+ zenml_nightly-0.61.0.dev20240713.dist-info/entry_points.txt,sha256=QK3ETQE0YswAM2mWypNMOv8TLtr7EjnqAFq1br_jEFE,43
1325
+ zenml_nightly-0.61.0.dev20240713.dist-info/RECORD,,