mlrun 1.4.0rc25__py3-none-any.whl → 1.5.0rc2__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.

Potentially problematic release.


This version of mlrun might be problematic. Click here for more details.

Files changed (184) hide show
  1. mlrun/__init__.py +2 -35
  2. mlrun/__main__.py +3 -41
  3. mlrun/api/api/api.py +6 -0
  4. mlrun/api/api/endpoints/feature_store.py +0 -4
  5. mlrun/api/api/endpoints/files.py +14 -2
  6. mlrun/api/api/endpoints/frontend_spec.py +2 -1
  7. mlrun/api/api/endpoints/functions.py +95 -59
  8. mlrun/api/api/endpoints/grafana_proxy.py +9 -9
  9. mlrun/api/api/endpoints/logs.py +17 -3
  10. mlrun/api/api/endpoints/model_endpoints.py +3 -2
  11. mlrun/api/api/endpoints/pipelines.py +1 -5
  12. mlrun/api/api/endpoints/projects.py +88 -0
  13. mlrun/api/api/endpoints/runs.py +48 -6
  14. mlrun/api/api/endpoints/submit.py +2 -1
  15. mlrun/api/api/endpoints/workflows.py +355 -0
  16. mlrun/api/api/utils.py +3 -4
  17. mlrun/api/crud/__init__.py +1 -0
  18. mlrun/api/crud/client_spec.py +6 -2
  19. mlrun/api/crud/feature_store.py +5 -0
  20. mlrun/api/crud/model_monitoring/__init__.py +1 -0
  21. mlrun/api/crud/model_monitoring/deployment.py +497 -0
  22. mlrun/api/crud/model_monitoring/grafana.py +96 -42
  23. mlrun/api/crud/model_monitoring/helpers.py +159 -0
  24. mlrun/api/crud/model_monitoring/model_endpoints.py +202 -476
  25. mlrun/api/crud/notifications.py +9 -4
  26. mlrun/api/crud/pipelines.py +6 -11
  27. mlrun/api/crud/projects.py +2 -2
  28. mlrun/api/crud/runtime_resources.py +4 -3
  29. mlrun/api/crud/runtimes/nuclio/helpers.py +5 -1
  30. mlrun/api/crud/secrets.py +21 -0
  31. mlrun/api/crud/workflows.py +352 -0
  32. mlrun/api/db/base.py +16 -1
  33. mlrun/api/db/init_db.py +2 -4
  34. mlrun/api/db/session.py +1 -1
  35. mlrun/api/db/sqldb/db.py +129 -31
  36. mlrun/api/db/sqldb/models/models_mysql.py +15 -1
  37. mlrun/api/db/sqldb/models/models_sqlite.py +16 -2
  38. mlrun/api/launcher.py +38 -6
  39. mlrun/api/main.py +3 -2
  40. mlrun/api/rundb/__init__.py +13 -0
  41. mlrun/{db → api/rundb}/sqldb.py +36 -84
  42. mlrun/api/runtime_handlers/__init__.py +56 -0
  43. mlrun/api/runtime_handlers/base.py +1247 -0
  44. mlrun/api/runtime_handlers/daskjob.py +209 -0
  45. mlrun/api/runtime_handlers/kubejob.py +37 -0
  46. mlrun/api/runtime_handlers/mpijob.py +147 -0
  47. mlrun/api/runtime_handlers/remotesparkjob.py +29 -0
  48. mlrun/api/runtime_handlers/sparkjob.py +148 -0
  49. mlrun/api/schemas/__init__.py +17 -6
  50. mlrun/api/utils/builder.py +1 -4
  51. mlrun/api/utils/clients/chief.py +14 -0
  52. mlrun/api/utils/clients/iguazio.py +33 -33
  53. mlrun/api/utils/clients/nuclio.py +2 -2
  54. mlrun/api/utils/periodic.py +9 -2
  55. mlrun/api/utils/projects/follower.py +14 -7
  56. mlrun/api/utils/projects/leader.py +2 -1
  57. mlrun/api/utils/projects/remotes/nop_follower.py +2 -2
  58. mlrun/api/utils/projects/remotes/nop_leader.py +2 -2
  59. mlrun/api/utils/runtimes/__init__.py +14 -0
  60. mlrun/api/utils/runtimes/nuclio.py +43 -0
  61. mlrun/api/utils/scheduler.py +98 -15
  62. mlrun/api/utils/singletons/db.py +5 -1
  63. mlrun/api/utils/singletons/project_member.py +4 -1
  64. mlrun/api/utils/singletons/scheduler.py +1 -1
  65. mlrun/artifacts/base.py +6 -6
  66. mlrun/artifacts/dataset.py +4 -4
  67. mlrun/artifacts/manager.py +2 -3
  68. mlrun/artifacts/model.py +2 -2
  69. mlrun/artifacts/plots.py +8 -8
  70. mlrun/common/db/__init__.py +14 -0
  71. mlrun/common/helpers.py +37 -0
  72. mlrun/{mlutils → common/model_monitoring}/__init__.py +3 -2
  73. mlrun/common/model_monitoring/helpers.py +69 -0
  74. mlrun/common/schemas/__init__.py +13 -1
  75. mlrun/common/schemas/auth.py +4 -1
  76. mlrun/common/schemas/client_spec.py +1 -1
  77. mlrun/common/schemas/function.py +17 -0
  78. mlrun/common/schemas/model_monitoring/__init__.py +48 -0
  79. mlrun/common/{model_monitoring.py → schemas/model_monitoring/constants.py} +11 -23
  80. mlrun/common/schemas/model_monitoring/grafana.py +55 -0
  81. mlrun/common/schemas/{model_endpoints.py → model_monitoring/model_endpoints.py} +32 -65
  82. mlrun/common/schemas/notification.py +1 -0
  83. mlrun/common/schemas/object.py +4 -0
  84. mlrun/common/schemas/project.py +1 -0
  85. mlrun/common/schemas/regex.py +1 -1
  86. mlrun/common/schemas/runs.py +1 -8
  87. mlrun/common/schemas/schedule.py +1 -8
  88. mlrun/common/schemas/workflow.py +54 -0
  89. mlrun/config.py +45 -42
  90. mlrun/datastore/__init__.py +21 -0
  91. mlrun/datastore/base.py +1 -1
  92. mlrun/datastore/datastore.py +9 -0
  93. mlrun/datastore/dbfs_store.py +168 -0
  94. mlrun/datastore/helpers.py +18 -0
  95. mlrun/datastore/sources.py +1 -0
  96. mlrun/datastore/store_resources.py +2 -5
  97. mlrun/datastore/v3io.py +1 -2
  98. mlrun/db/__init__.py +4 -68
  99. mlrun/db/base.py +12 -0
  100. mlrun/db/factory.py +65 -0
  101. mlrun/db/httpdb.py +175 -20
  102. mlrun/db/nopdb.py +4 -2
  103. mlrun/execution.py +4 -2
  104. mlrun/feature_store/__init__.py +1 -0
  105. mlrun/feature_store/api.py +1 -2
  106. mlrun/feature_store/common.py +2 -1
  107. mlrun/feature_store/feature_set.py +1 -11
  108. mlrun/feature_store/feature_vector.py +340 -2
  109. mlrun/feature_store/ingestion.py +5 -10
  110. mlrun/feature_store/retrieval/base.py +118 -104
  111. mlrun/feature_store/retrieval/dask_merger.py +17 -10
  112. mlrun/feature_store/retrieval/job.py +4 -1
  113. mlrun/feature_store/retrieval/local_merger.py +18 -18
  114. mlrun/feature_store/retrieval/spark_merger.py +21 -14
  115. mlrun/feature_store/retrieval/storey_merger.py +22 -16
  116. mlrun/kfpops.py +3 -9
  117. mlrun/launcher/base.py +57 -53
  118. mlrun/launcher/client.py +5 -4
  119. mlrun/launcher/factory.py +24 -13
  120. mlrun/launcher/local.py +6 -6
  121. mlrun/launcher/remote.py +4 -4
  122. mlrun/lists.py +0 -11
  123. mlrun/model.py +11 -17
  124. mlrun/model_monitoring/__init__.py +2 -22
  125. mlrun/model_monitoring/features_drift_table.py +1 -1
  126. mlrun/model_monitoring/helpers.py +22 -210
  127. mlrun/model_monitoring/model_endpoint.py +1 -1
  128. mlrun/model_monitoring/model_monitoring_batch.py +127 -50
  129. mlrun/model_monitoring/prometheus.py +219 -0
  130. mlrun/model_monitoring/stores/__init__.py +16 -11
  131. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +95 -23
  132. mlrun/model_monitoring/stores/models/mysql.py +47 -29
  133. mlrun/model_monitoring/stores/models/sqlite.py +47 -29
  134. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +31 -19
  135. mlrun/model_monitoring/{stream_processing_fs.py → stream_processing.py} +206 -64
  136. mlrun/model_monitoring/tracking_policy.py +104 -0
  137. mlrun/package/packager.py +6 -8
  138. mlrun/package/packagers/default_packager.py +121 -10
  139. mlrun/package/packagers/numpy_packagers.py +1 -1
  140. mlrun/platforms/__init__.py +0 -2
  141. mlrun/platforms/iguazio.py +0 -56
  142. mlrun/projects/pipelines.py +53 -159
  143. mlrun/projects/project.py +10 -37
  144. mlrun/render.py +1 -1
  145. mlrun/run.py +8 -124
  146. mlrun/runtimes/__init__.py +6 -42
  147. mlrun/runtimes/base.py +29 -1249
  148. mlrun/runtimes/daskjob.py +2 -198
  149. mlrun/runtimes/funcdoc.py +0 -9
  150. mlrun/runtimes/function.py +25 -29
  151. mlrun/runtimes/kubejob.py +5 -29
  152. mlrun/runtimes/local.py +1 -1
  153. mlrun/runtimes/mpijob/__init__.py +2 -2
  154. mlrun/runtimes/mpijob/abstract.py +10 -1
  155. mlrun/runtimes/mpijob/v1.py +0 -76
  156. mlrun/runtimes/mpijob/v1alpha1.py +1 -74
  157. mlrun/runtimes/nuclio.py +3 -2
  158. mlrun/runtimes/pod.py +28 -18
  159. mlrun/runtimes/remotesparkjob.py +1 -15
  160. mlrun/runtimes/serving.py +14 -6
  161. mlrun/runtimes/sparkjob/__init__.py +0 -1
  162. mlrun/runtimes/sparkjob/abstract.py +4 -131
  163. mlrun/runtimes/utils.py +0 -26
  164. mlrun/serving/routers.py +7 -7
  165. mlrun/serving/server.py +11 -8
  166. mlrun/serving/states.py +7 -1
  167. mlrun/serving/v2_serving.py +6 -6
  168. mlrun/utils/helpers.py +23 -42
  169. mlrun/utils/notifications/notification/__init__.py +4 -0
  170. mlrun/utils/notifications/notification/webhook.py +61 -0
  171. mlrun/utils/notifications/notification_pusher.py +5 -25
  172. mlrun/utils/regex.py +7 -2
  173. mlrun/utils/version/version.json +2 -2
  174. {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/METADATA +26 -25
  175. {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/RECORD +180 -158
  176. {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/WHEEL +1 -1
  177. mlrun/mlutils/data.py +0 -160
  178. mlrun/mlutils/models.py +0 -78
  179. mlrun/mlutils/plots.py +0 -902
  180. mlrun/utils/model_monitoring.py +0 -249
  181. /mlrun/{api/db/sqldb/session.py → common/db/sql_session.py} +0 -0
  182. {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/LICENSE +0 -0
  183. {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/entry_points.txt +0 -0
  184. {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/top_level.txt +0 -0
@@ -34,13 +34,18 @@ class Notifications(
34
34
  notification_objects: typing.List[mlrun.model.Notification],
35
35
  run_uid: str,
36
36
  project: str = None,
37
+ mask_params: bool = True,
37
38
  ):
38
39
  project = project or mlrun.mlconf.default_project
39
- notification_objects_to_store = (
40
- mlrun.api.api.utils.validate_and_mask_notification_list(
41
- notification_objects, run_uid, project
40
+
41
+ # we don't mask the notification params when it's a status update as they are already masked
42
+ notification_objects_to_store = notification_objects
43
+ if mask_params:
44
+ notification_objects_to_store = (
45
+ mlrun.api.api.utils.validate_and_mask_notification_list(
46
+ notification_objects, run_uid, project
47
+ )
42
48
  )
43
- )
44
49
 
45
50
  mlrun.api.utils.singletons.db.get_db().store_run_notifications(
46
51
  session, notification_objects_to_store, run_uid, project
@@ -25,6 +25,7 @@ import sqlalchemy.orm
25
25
 
26
26
  import mlrun
27
27
  import mlrun.api.api.utils
28
+ import mlrun.common.helpers
28
29
  import mlrun.common.schemas
29
30
  import mlrun.errors
30
31
  import mlrun.kfpops
@@ -94,7 +95,7 @@ class Pipelines(
94
95
  runs = [run.to_dict() for run in response.runs or []]
95
96
  total_size = response.total_size
96
97
  next_page_token = response.next_page_token
97
- runs = self._format_runs(db_session, runs, format_)
98
+ runs = self._format_runs(runs, format_)
98
99
 
99
100
  return total_size, next_page_token, runs
100
101
 
@@ -130,7 +131,6 @@ class Pipelines(
130
131
 
131
132
  def get_pipeline(
132
133
  self,
133
- db_session: sqlalchemy.orm.Session,
134
134
  run_id: str,
135
135
  project: typing.Optional[str] = None,
136
136
  namespace: typing.Optional[str] = None,
@@ -148,9 +148,7 @@ class Pipelines(
148
148
  raise mlrun.errors.MLRunNotFoundError(
149
149
  f"Pipeline run with id {run_id} is not of project {project}"
150
150
  )
151
- run = self._format_run(
152
- db_session, run, format_, api_run_detail.to_dict()
153
- )
151
+ run = self._format_run(run, format_, api_run_detail.to_dict())
154
152
  except kfp_server_api.ApiException as exc:
155
153
  mlrun.errors.raise_for_status_code(int(exc.status), err_to_str(exc))
156
154
  except mlrun.errors.MLRunHTTPStatusError:
@@ -227,18 +225,16 @@ class Pipelines(
227
225
 
228
226
  def _format_runs(
229
227
  self,
230
- db_session: sqlalchemy.orm.Session,
231
228
  runs: typing.List[dict],
232
229
  format_: mlrun.common.schemas.PipelinesFormat = mlrun.common.schemas.PipelinesFormat.metadata_only,
233
230
  ) -> typing.List[dict]:
234
231
  formatted_runs = []
235
232
  for run in runs:
236
- formatted_runs.append(self._format_run(db_session, run, format_))
233
+ formatted_runs.append(self._format_run(run, format_))
237
234
  return formatted_runs
238
235
 
239
236
  def _format_run(
240
237
  self,
241
- db_session: sqlalchemy.orm.Session,
242
238
  run: dict,
243
239
  format_: mlrun.common.schemas.PipelinesFormat = mlrun.common.schemas.PipelinesFormat.metadata_only,
244
240
  api_run_detail: typing.Optional[dict] = None,
@@ -257,7 +253,7 @@ class Pipelines(
257
253
  "The full kfp api_run_detail object is needed to generate the summary format"
258
254
  )
259
255
  return mlrun.kfpops.format_summary_from_kfp_run(
260
- api_run_detail, run["project"], db_session
256
+ api_run_detail, run["project"]
261
257
  )
262
258
  else:
263
259
  raise NotImplementedError(
@@ -290,7 +286,7 @@ class Pipelines(
290
286
  _,
291
287
  _,
292
288
  _,
293
- ) = mlrun.utils.helpers.parse_versioned_object_uri(
289
+ ) = mlrun.common.helpers.parse_versioned_object_uri(
294
290
  function_url[len("db://") :]
295
291
  )
296
292
  if project:
@@ -316,7 +312,6 @@ class Pipelines(
316
312
  return None
317
313
 
318
314
  def resolve_project_from_pipeline(self, pipeline):
319
-
320
315
  workflow_manifest = json.loads(
321
316
  pipeline.get("pipeline_spec", {}).get("workflow_manifest") or "{}"
322
317
  )
@@ -24,7 +24,7 @@ import sqlalchemy.orm
24
24
  import mlrun.api.crud
25
25
  import mlrun.api.db.session
26
26
  import mlrun.api.utils.events.events_factory as events_factory
27
- import mlrun.api.utils.projects.remotes.follower
27
+ import mlrun.api.utils.projects.remotes.follower as project_follower
28
28
  import mlrun.api.utils.singletons.db
29
29
  import mlrun.api.utils.singletons.k8s
30
30
  import mlrun.api.utils.singletons.scheduler
@@ -35,7 +35,7 @@ from mlrun.utils import logger
35
35
 
36
36
 
37
37
  class Projects(
38
- mlrun.api.utils.projects.remotes.follower.Member,
38
+ project_follower.Member,
39
39
  metaclass=mlrun.utils.singleton.AbstractSingleton,
40
40
  ):
41
41
  def __init__(self) -> None:
@@ -18,6 +18,7 @@ import mergedeep
18
18
  import sqlalchemy.orm
19
19
 
20
20
  import mlrun.api.api.utils
21
+ import mlrun.api.runtime_handlers
21
22
  import mlrun.api.utils.projects.remotes.follower
22
23
  import mlrun.api.utils.singletons.db
23
24
  import mlrun.common.schemas
@@ -50,7 +51,7 @@ class RuntimeResources(
50
51
  self.validate_runtime_resources_kind(kind)
51
52
  kinds = [kind]
52
53
  for kind in kinds:
53
- runtime_handler = mlrun.runtimes.get_runtime_handler(kind)
54
+ runtime_handler = mlrun.api.runtime_handlers.get_runtime_handler(kind)
54
55
  resources = runtime_handler.list_resources(
55
56
  project, object_id, label_selector, group_by
56
57
  )
@@ -88,7 +89,7 @@ class RuntimeResources(
88
89
  )
89
90
  runtimes_resources_output = [] if group_by is None else {}
90
91
  for kind, runtime_resources_list in runtime_resources_by_kind.items():
91
- runtime_handler = mlrun.runtimes.get_runtime_handler(kind)
92
+ runtime_handler = mlrun.api.runtime_handlers.get_runtime_handler(kind)
92
93
  resources = runtime_handler.build_output_from_runtime_resources(
93
94
  runtime_resources_list, group_by
94
95
  )
@@ -122,7 +123,7 @@ class RuntimeResources(
122
123
  self.validate_runtime_resources_kind(kind)
123
124
  kinds = [kind]
124
125
  for kind in kinds:
125
- runtime_handler = mlrun.runtimes.get_runtime_handler(kind)
126
+ runtime_handler = mlrun.api.runtime_handlers.get_runtime_handler(kind)
126
127
  if object_id:
127
128
  runtime_handler.delete_runtime_object_resources(
128
129
  mlrun.api.utils.singletons.db.get_db(),
@@ -17,6 +17,8 @@ import urllib.parse
17
17
  import semver
18
18
 
19
19
  import mlrun
20
+ import mlrun.api.utils.clients.nuclio
21
+ import mlrun.api.utils.runtimes.nuclio
20
22
  import mlrun.api.utils.singletons.k8s
21
23
  import mlrun.runtimes
22
24
  from mlrun.utils import logger
@@ -190,7 +192,9 @@ def is_nuclio_version_in_range(min_version: str, max_version: str) -> bool:
190
192
  try:
191
193
  parsed_min_version = semver.VersionInfo.parse(min_version)
192
194
  parsed_max_version = semver.VersionInfo.parse(max_version)
193
- resolved_nuclio_version = mlrun.runtimes.utils.resolve_nuclio_version()
195
+ resolved_nuclio_version = (
196
+ mlrun.api.utils.runtimes.nuclio.resolve_nuclio_version()
197
+ )
194
198
  parsed_current_version = semver.VersionInfo.parse(resolved_nuclio_version)
195
199
  except ValueError:
196
200
  logger.warning(
mlrun/api/crud/secrets.py CHANGED
@@ -17,9 +17,11 @@ import json
17
17
  import typing
18
18
  import uuid
19
19
 
20
+ import mlrun.api
20
21
  import mlrun.api.utils.clients.iguazio
21
22
  import mlrun.api.utils.events.events_factory as events_factory
22
23
  import mlrun.api.utils.singletons.k8s
24
+ import mlrun.common
23
25
  import mlrun.common.schemas
24
26
  import mlrun.errors
25
27
  import mlrun.utils.helpers
@@ -531,3 +533,22 @@ class Secrets(
531
533
  @staticmethod
532
534
  def _generate_uuid() -> str:
533
535
  return str(uuid.uuid4())
536
+
537
+
538
+ def get_project_secret_provider(project: str) -> typing.Callable:
539
+ """Implement secret provider for handle the related project secret on the API side.
540
+
541
+ :param project: Project name.
542
+
543
+ :return: A secret provider function.
544
+ """
545
+
546
+ def secret_provider(key: str):
547
+ return mlrun.api.crud.secrets.Secrets().get_project_secret(
548
+ project=project,
549
+ provider=mlrun.common.schemas.secret.SecretProviderName.kubernetes,
550
+ allow_secrets_from_k8s=True,
551
+ secret_key=key,
552
+ )
553
+
554
+ return secret_provider
@@ -0,0 +1,352 @@
1
+ # Copyright 2018 Iguazio
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ import uuid
16
+ from typing import Dict
17
+
18
+ from sqlalchemy.orm import Session
19
+
20
+ import mlrun.common.schemas
21
+ import mlrun.utils.singleton
22
+ from mlrun.api.api.utils import (
23
+ apply_enrichment_and_validation_on_function,
24
+ get_run_db_instance,
25
+ get_scheduler,
26
+ )
27
+ from mlrun.config import config
28
+ from mlrun.model import Credentials, RunMetadata, RunObject, RunSpec
29
+
30
+
31
+ class WorkflowRunners(
32
+ metaclass=mlrun.utils.singleton.Singleton,
33
+ ):
34
+ @staticmethod
35
+ def create_runner(
36
+ run_name: str,
37
+ project: str,
38
+ db_session: Session,
39
+ auth_info: mlrun.common.schemas.AuthInfo,
40
+ image: str,
41
+ ) -> mlrun.run.KubejobRuntime:
42
+ """
43
+ Creating the base object for the workflow runner function with
44
+ all the necessary metadata to create it on server-side.
45
+
46
+ :param run_name: workflow-runner function name
47
+ :param project: project name
48
+ :param db_session: session that manages the current dialog with the database
49
+ :param auth_info: auth info of the request
50
+ :param image: image for the workflow runner job
51
+
52
+ :returns: workflow runner object
53
+ """
54
+ runner = mlrun.new_function(
55
+ name=run_name,
56
+ project=project,
57
+ kind=mlrun.runtimes.RuntimeKinds.job,
58
+ # For preventing deployment:
59
+ image=image,
60
+ )
61
+
62
+ runner.set_db_connection(get_run_db_instance(db_session))
63
+
64
+ # Enrichment and validation requires access key
65
+ runner.metadata.credentials.access_key = Credentials.generate_access_key
66
+
67
+ apply_enrichment_and_validation_on_function(
68
+ function=runner,
69
+ auth_info=auth_info,
70
+ )
71
+
72
+ runner.save()
73
+ return runner
74
+
75
+ def schedule(
76
+ self,
77
+ runner: mlrun.run.KubejobRuntime,
78
+ project: mlrun.common.schemas.Project,
79
+ workflow_request: mlrun.common.schemas.WorkflowRequest,
80
+ db_session: Session = None,
81
+ auth_info: mlrun.common.schemas.AuthInfo = None,
82
+ ):
83
+ """
84
+ Schedule workflow runner.
85
+
86
+ :param runner: workflow runner function object
87
+ :param project: MLRun project
88
+ :param workflow_request: contains the workflow spec, that will be scheduled
89
+ :param db_session: session that manages the current dialog with the database
90
+ :param auth_info: auth info of the request
91
+ """
92
+ labels = {
93
+ "job-type": "workflow-runner",
94
+ "workflow": workflow_request.spec.name,
95
+ }
96
+
97
+ run_spec = self._prepare_run_object_for_scheduling(
98
+ project=project,
99
+ workflow_request=workflow_request,
100
+ labels=labels,
101
+ )
102
+ # this includes filling the spec.function which is required for submit run
103
+ runner._store_function(
104
+ runspec=run_spec, meta=run_spec.metadata, db=runner._get_db()
105
+ )
106
+ workflow_spec = workflow_request.spec
107
+ schedule = workflow_spec.schedule
108
+ scheduled_object = {
109
+ "task": run_spec.to_dict(),
110
+ "schedule": schedule,
111
+ }
112
+
113
+ get_scheduler().store_schedule(
114
+ db_session=db_session,
115
+ auth_info=auth_info,
116
+ project=project.metadata.name,
117
+ name=workflow_spec.name,
118
+ scheduled_object=scheduled_object,
119
+ cron_trigger=schedule,
120
+ labels=runner.metadata.labels,
121
+ kind=mlrun.common.schemas.ScheduleKinds.job,
122
+ )
123
+
124
+ def _prepare_run_object_for_scheduling(
125
+ self,
126
+ project: mlrun.common.schemas.Project,
127
+ workflow_request: mlrun.common.schemas.WorkflowRequest,
128
+ labels: Dict[str, str],
129
+ ) -> mlrun.run.RunObject:
130
+ """
131
+ Preparing all the necessary metadata and specifications for scheduling workflow from server-side.
132
+
133
+ :param project: MLRun project
134
+ :param workflow_request: contains the workflow spec and extra data for the run object
135
+ :param labels: dict of the task labels
136
+
137
+ :returns: RunObject ready for schedule.
138
+ """
139
+ meta_uid = uuid.uuid4().hex
140
+
141
+ save = self._set_source(project, workflow_request.source)
142
+ workflow_spec = workflow_request.spec
143
+ run_object = RunObject(
144
+ spec=RunSpec(
145
+ parameters=dict(
146
+ url=project.spec.source,
147
+ project_name=project.metadata.name,
148
+ workflow_name=workflow_spec.name,
149
+ workflow_path=workflow_spec.path,
150
+ workflow_arguments=workflow_spec.args,
151
+ artifact_path=workflow_request.artifact_path,
152
+ workflow_handler=workflow_spec.handler,
153
+ namespace=workflow_request.namespace,
154
+ ttl=workflow_spec.ttl,
155
+ engine=workflow_spec.engine,
156
+ local=workflow_spec.run_local,
157
+ save=save,
158
+ subpath=project.spec.subpath,
159
+ ),
160
+ handler="mlrun.projects.load_and_run",
161
+ scrape_metrics=config.scrape_metrics,
162
+ output_path=(
163
+ workflow_request.artifact_path or config.artifact_path
164
+ ).replace("{{run.uid}}", meta_uid),
165
+ ),
166
+ metadata=RunMetadata(
167
+ uid=meta_uid, name=workflow_spec.name, project=project.metadata.name
168
+ ),
169
+ )
170
+
171
+ # Setting labels:
172
+ return self._label_run_object(run_object, labels)
173
+
174
+ def run(
175
+ self,
176
+ runner: mlrun.run.KubejobRuntime,
177
+ project: mlrun.common.schemas.Project,
178
+ workflow_request: mlrun.common.schemas.WorkflowRequest = None,
179
+ load_only: bool = False,
180
+ ) -> RunObject:
181
+ """
182
+ Run workflow runner.
183
+
184
+ :param runner: workflow runner function object
185
+ :param project: MLRun project
186
+ :param workflow_request: contains the workflow spec, that will be executed
187
+ :param load_only: If True, will only load the project remotely (without running workflow)
188
+
189
+ :returns: run context object (RunObject) with run metadata, results and status
190
+ """
191
+ labels = {"project": project.metadata.name}
192
+ if load_only:
193
+ labels["job-type"] = "project-loader"
194
+ else:
195
+ labels["job-type"] = "workflow-runner"
196
+ labels["workflow"] = runner.metadata.name
197
+
198
+ run_spec = self._prepare_run_object_for_single_run(
199
+ project=project,
200
+ labels=labels,
201
+ workflow_request=workflow_request,
202
+ run_name=runner.metadata.name,
203
+ load_only=load_only,
204
+ )
205
+
206
+ artifact_path = workflow_request.artifact_path if workflow_request else ""
207
+ return runner.run(
208
+ runspec=run_spec,
209
+ artifact_path=artifact_path,
210
+ local=False,
211
+ watch=False,
212
+ )
213
+
214
+ @staticmethod
215
+ def get_workflow_id(
216
+ uid: str, project: str, engine: str, db_session: Session
217
+ ) -> mlrun.common.schemas.GetWorkflowResponse:
218
+ """
219
+ Retrieving the actual workflow id form the workflow runner
220
+
221
+ :param uid: the id of the workflow runner job
222
+ :param project: name of the project
223
+ :param engine: pipeline runner, for example: "kfp"
224
+ :param db_session: session that manages the current dialog with the database
225
+
226
+ :return: The id of the workflow.
227
+ """
228
+ # Reading run:
229
+ run = mlrun.api.crud.Runs().get_run(
230
+ db_session=db_session, uid=uid, iter=0, project=project
231
+ )
232
+ run_object = RunObject.from_dict(run)
233
+ state = run_object.status.state
234
+ workflow_id = None
235
+ if isinstance(run_object.status.results, dict):
236
+ workflow_id = run_object.status.results.get("workflow_id", None)
237
+
238
+ if workflow_id is None:
239
+ if (
240
+ engine == "local"
241
+ and state.casefold() == mlrun.run.RunStatuses.running.casefold()
242
+ ):
243
+ workflow_id = ""
244
+ else:
245
+ raise mlrun.errors.MLRunNotFoundError(
246
+ f"workflow id of run {project}:{uid} not found"
247
+ )
248
+
249
+ return mlrun.common.schemas.GetWorkflowResponse(workflow_id=workflow_id)
250
+
251
+ def _prepare_run_object_for_single_run(
252
+ self,
253
+ project: mlrun.common.schemas.Project,
254
+ labels: Dict[str, str],
255
+ workflow_request: mlrun.common.schemas.WorkflowRequest = None,
256
+ run_name: str = None,
257
+ load_only: bool = False,
258
+ ) -> mlrun.run.RunObject:
259
+ """
260
+ Preparing all the necessary metadata and specifications for running workflow from server-side.
261
+
262
+ :param project: MLRun project
263
+ :param labels: dict of the task labels
264
+ :param workflow_request: contains the workflow spec and extra data for the run object
265
+ :param run_name: workflow-runner function name
266
+ :param load_only: if True, will only load the project remotely (without running workflow)
267
+
268
+ :returns: RunObject ready for execution.
269
+ """
270
+ source = workflow_request.source if workflow_request else ""
271
+ save = self._set_source(project, source, load_only)
272
+ run_object = RunObject(
273
+ spec=RunSpec(
274
+ parameters=dict(
275
+ url=project.spec.source,
276
+ project_name=project.metadata.name,
277
+ load_only=load_only,
278
+ save=save,
279
+ ),
280
+ handler="mlrun.projects.load_and_run",
281
+ ),
282
+ metadata=RunMetadata(name=run_name),
283
+ )
284
+
285
+ if not load_only:
286
+ workflow_spec = workflow_request.spec
287
+ run_object.spec.parameters.update(
288
+ dict(
289
+ workflow_name=workflow_spec.name,
290
+ workflow_path=workflow_spec.path,
291
+ workflow_arguments=workflow_spec.args,
292
+ artifact_path=workflow_request.artifact_path,
293
+ workflow_handler=workflow_spec.handler,
294
+ namespace=workflow_request.namespace,
295
+ ttl=workflow_spec.ttl,
296
+ engine=workflow_spec.engine,
297
+ local=workflow_spec.run_local,
298
+ subpath=project.spec.subpath,
299
+ )
300
+ )
301
+
302
+ # Setting labels:
303
+ return self._label_run_object(run_object, labels)
304
+
305
+ @staticmethod
306
+ def _set_source(
307
+ project: mlrun.common.schemas.Project, source: str, load_only: bool = False
308
+ ) -> bool:
309
+ """
310
+ Setting the project source.
311
+ In case the user provided a source we want to load the project from the source
312
+ (like from a specific commit/branch from git repo) without changing the source of the project (save=False).
313
+
314
+ :param project: MLRun project
315
+ :param source: the source of the project, needs to be a remote URL that contains the project yaml file.
316
+ :param load_only: if we only load the project, it must be saved to ensure we are not running a pipeline
317
+ without a project as it's not supported.
318
+
319
+ :returns: True if the project need to be saved afterward.
320
+ """
321
+
322
+ save = True
323
+ if source and not load_only:
324
+ save = False
325
+ project.spec.source = source
326
+
327
+ if "://" not in project.spec.source:
328
+ raise mlrun.errors.MLRunInvalidArgumentError(
329
+ f"Remote workflows can only be performed by a project with remote source (e.g git:// or http://),"
330
+ f" but the specified source '{project.spec.source}' is not remote. "
331
+ f"Either put your code in Git, or archive it and then set a source to it."
332
+ f" For more details, read"
333
+ f" https://docs.mlrun.org/en/latest/concepts/scheduled-jobs.html#scheduling-a-workflow"
334
+ )
335
+ return save
336
+
337
+ @staticmethod
338
+ def _label_run_object(
339
+ run_object: mlrun.run.RunObject,
340
+ labels: Dict[str, str],
341
+ ) -> mlrun.run.RunObject:
342
+ """
343
+ Setting labels to the task
344
+
345
+ :param run_object: run object to set labels on
346
+ :param labels: dict of labels
347
+
348
+ :returns: labeled RunObject
349
+ """
350
+ for key, value in labels.items():
351
+ run_object = run_object.set_label(key, value)
352
+ return run_object
mlrun/api/db/base.py CHANGED
@@ -259,6 +259,21 @@ class DBInterface(ABC):
259
259
  ):
260
260
  pass
261
261
 
262
+ def store_schedule(
263
+ self,
264
+ session,
265
+ project: str,
266
+ name: str,
267
+ kind: mlrun.common.schemas.ScheduleKinds = None,
268
+ scheduled_object: Any = None,
269
+ cron_trigger: mlrun.common.schemas.ScheduleCronTrigger = None,
270
+ labels: Dict = None,
271
+ last_run_uri: str = None,
272
+ concurrency_limit: int = None,
273
+ next_run_time: datetime = None,
274
+ ):
275
+ pass
276
+
262
277
  @abstractmethod
263
278
  def list_schedules(
264
279
  self,
@@ -272,7 +287,7 @@ class DBInterface(ABC):
272
287
 
273
288
  @abstractmethod
274
289
  def get_schedule(
275
- self, session, project: str, name: str
290
+ self, session, project: str, name: str, raise_on_not_found: bool = True
276
291
  ) -> mlrun.common.schemas.ScheduleRecord:
277
292
  pass
278
293
 
mlrun/api/db/init_db.py CHANGED
@@ -14,10 +14,8 @@
14
14
  #
15
15
 
16
16
  from mlrun.api.db.sqldb.models import Base
17
- from mlrun.api.db.sqldb.session import get_engine
18
- from mlrun.config import config
17
+ from mlrun.common.db.sql_session import get_engine
19
18
 
20
19
 
21
20
  def init_db() -> None:
22
- if config.httpdb.db_type != "filedb":
23
- Base.metadata.create_all(bind=get_engine())
21
+ Base.metadata.create_all(bind=get_engine())
mlrun/api/db/session.py CHANGED
@@ -14,7 +14,7 @@
14
14
  #
15
15
  from sqlalchemy.orm import Session
16
16
 
17
- from mlrun.api.db.sqldb.session import create_session as sqldb_create_session
17
+ from mlrun.common.db.sql_session import create_session as sqldb_create_session
18
18
 
19
19
 
20
20
  def create_session() -> Session: