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
@@ -16,16 +16,123 @@ import inspect
16
16
  from types import MethodType
17
17
  from typing import Any, List, Tuple, Type, Union
18
18
 
19
+ import docstring_parser
20
+
19
21
  from mlrun.artifacts import Artifact
20
22
  from mlrun.datastore import DataItem
21
23
  from mlrun.utils import logger
22
24
 
23
25
  from ..errors import MLRunPackagePackingError, MLRunPackageUnpackingError
24
- from ..packager import Packager
26
+ from ..packager import Packager, _PackagerMeta
25
27
  from ..utils import DEFAULT_PICKLE_MODULE, ArtifactType, Pickler, TypeHintUtils
26
28
 
27
29
 
28
- class DefaultPackager(Packager):
30
+ class _DefaultPackagerMeta(_PackagerMeta):
31
+ """
32
+ Metaclass for `DefaultPackager` to override `__doc__` attribute into a class property. This way sphinx will get a
33
+ dynamically generated docstring that will include a summary of the packager.
34
+ """
35
+
36
+ def __new__(mcls, name: str, bases: tuple, namespace: dict, **kwargs):
37
+ """
38
+ Create a new DefaultPackager metaclass that saves the original packager docstring to another attribute named
39
+ `_packager_doc`.
40
+
41
+ :param name: A string representing the name of the class being instantiated.
42
+ :param bases: A tuple of classes from which the class will inherit.
43
+ :param namespace: The namespace of the class holding its attributes (from here the docstring will be taken).
44
+ """
45
+ # Save the original doc string to a separate class variable as it will be overriden later on by the metaclass
46
+ # property `__doc__`:
47
+ namespace["_packager_doc"] = namespace.get("__doc__", "")
48
+
49
+ # Continue creating the metaclass:
50
+ return super().__new__(mcls, name, bases, namespace, **kwargs)
51
+
52
+ @property
53
+ def __doc__(cls) -> str:
54
+ """
55
+ Override the `__doc__` attribute of a `DefaultPackager` to be a property in order to auto-summarize the
56
+ packager's class docstring. The summary is concatenated after the original class doc string.
57
+
58
+ The summary will be in the following structure:
59
+
60
+ <cls._packager_doc>
61
+
62
+ .. rubric:: Packager Summary
63
+
64
+ **Packing Type**: ``<cls.PACKABLE_OBJECT_TYPE>``
65
+
66
+ **Packing Sub-Classes**: True / False
67
+
68
+ **Artifact Types**:
69
+
70
+ * **type 1**: ...
71
+
72
+ * configuration 1 - ...
73
+ * configuration 2 - ...
74
+
75
+ * **type 2**: ...
76
+
77
+ * configuration 1: ...
78
+ * configuration 2: ...
79
+
80
+ :returns: The original docstring with the generated packager summary.
81
+ """
82
+ # Get the original packager class doc string:
83
+ packager_doc_string = cls._packager_doc.split("\n")
84
+ packager_doc_string = "\n".join(line[4:] for line in packager_doc_string)
85
+
86
+ # Parse the packable type section:
87
+ type_name = (
88
+ "Any type"
89
+ if cls.PACKABLE_OBJECT_TYPE is ...
90
+ else (
91
+ f"``{str(cls.PACKABLE_OBJECT_TYPE)}``"
92
+ if TypeHintUtils.is_typing_type(type_hint=cls.PACKABLE_OBJECT_TYPE)
93
+ else f"``{cls.PACKABLE_OBJECT_TYPE.__module__}.{cls.PACKABLE_OBJECT_TYPE.__name__}``"
94
+ )
95
+ )
96
+ packing_type = f"**Packing Type**: {type_name}"
97
+
98
+ # Subclasses support section:
99
+ packing_sub_classes = f"**Packing Sub-Classes**: {cls.PACK_SUBCLASSES}"
100
+
101
+ # Artifact types section:
102
+ artifact_types = "**Artifact Types**:"
103
+ for artifact_type in cls.get_supported_artifact_types():
104
+ # Get the packing method docstring:
105
+ method_doc = docstring_parser.parse(
106
+ getattr(cls, f"pack_{artifact_type}").__doc__
107
+ )
108
+ # Add the artifact type bullet:
109
+ artifact_type_doc = f"{method_doc.short_description or ''}{method_doc.long_description or ''}".replace(
110
+ "\n", ""
111
+ )
112
+ artifact_types += f"\n\n* **{artifact_type}** - " + artifact_type_doc
113
+ # Add the artifact type configurations (ignoring the `obj` and `key` parameters):
114
+ configurations_doc = "\n\n * ".join(
115
+ "{} - {}".format(
116
+ parameter.arg_name, parameter.description.replace("\n", "")
117
+ )
118
+ for parameter in method_doc.params[2:]
119
+ )
120
+ if configurations_doc:
121
+ artifact_types += f"\n\n * {configurations_doc}"
122
+
123
+ # Construct the final doc string and return:
124
+ doc = (
125
+ f"{packager_doc_string}"
126
+ "\n\n.. rubric:: Packager Summary"
127
+ f"\n\n{packing_type}"
128
+ f"\n\n{packing_sub_classes}"
129
+ f"\n\n{artifact_types}"
130
+ f"\n\n"
131
+ )
132
+ return doc
133
+
134
+
135
+ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
29
136
  """
30
137
  A default packager that handles all types and pack them as pickle files.
31
138
 
@@ -89,7 +196,7 @@ class DefaultPackager(Packager):
89
196
 
90
197
  Important to remember (from the ``Packager`` docstring):
91
198
 
92
- * Linking artifacts ("extra data"): In order to link between packages (using the extra data or metrics spec
199
+ * **Linking artifacts** ("extra data"): In order to link between packages (using the extra data or metrics spec
93
200
  attributes of an artifact), you should use the key as if it exists and as value ellipses (...). The manager will
94
201
  link all packages once it is done packing.
95
202
 
@@ -98,9 +205,9 @@ class DefaultPackager(Packager):
98
205
  artifact = Artifact(key="my_artifact")
99
206
  artifact.spec.extra_data = {key: ... for key in extra_data}
100
207
 
101
- * Clearing outputs: Some packagers may produce files and temporary directories that should be deleted once done with
102
- logging the artifact. The packager can mark paths of files and directories to delete after logging using the class
103
- method ``future_clear``.
208
+ * **Clearing outputs**: Some packagers may produce files and temporary directories that should be deleted once done
209
+ with logging the artifact. The packager can mark paths of files and directories to delete after logging using the
210
+ class method ``future_clear``.
104
211
 
105
212
  For example, in the following packager's ``pack`` method we can write a text file, create an Artifact and then
106
213
  mark the text file to be deleted once the artifact is logged::
@@ -110,15 +217,19 @@ class DefaultPackager(Packager):
110
217
  artifact = Artifact(key="my_artifact")
111
218
  cls.future_clear(path="./some_file.txt")
112
219
  return artifact, None
220
+
113
221
  """
114
222
 
115
- # The type of object this packager can pack and unpack:
223
+ #: The type of object this packager can pack and unpack.
116
224
  PACKABLE_OBJECT_TYPE: Type = ...
117
- # A flag for indicating whether to pack all subclasses of the `PACKABLE_OBJECT_TYPE` as well:
225
+
226
+ #: A flag for indicating whether to pack all subclasses of the `PACKABLE_OBJECT_TYPE` as well.
118
227
  PACK_SUBCLASSES = False
119
- # The default artifact type to pack as:
228
+
229
+ #: The default artifact type to pack as.
120
230
  DEFAULT_PACKING_ARTIFACT_TYPE = ArtifactType.OBJECT
121
- # The default artifact type to unpack from:
231
+
232
+ #: The default artifact type to unpack from.
122
233
  DEFAULT_UNPACKING_ARTIFACT_TYPE = ArtifactType.OBJECT
123
234
 
124
235
  @classmethod
@@ -600,7 +600,7 @@ class NumPyNDArrayListPackager(_NumPyNDArrayCollectionPackager):
600
600
 
601
601
  class NumPyNumberPackager(DefaultPackager):
602
602
  """
603
- ``numpy.number`` packager. It is also used for all `number` inheriting numpy objects (`float32`, uint8, etc).
603
+ ``numpy.number`` packager. It is also used for all `number` inheriting numpy objects (`float32`, uint8, etc.).
604
604
  """
605
605
 
606
606
  PACKABLE_OBJECT_TYPE = np.number
@@ -23,8 +23,6 @@ from .iguazio import (
23
23
  add_or_refresh_credentials,
24
24
  is_iguazio_session_cookie,
25
25
  mount_v3io,
26
- mount_v3io_extended,
27
- mount_v3io_legacy,
28
26
  v3io_cred,
29
27
  )
30
28
  from .other import (
@@ -25,7 +25,6 @@ import requests
25
25
  import semver
26
26
  import urllib3
27
27
  import v3io
28
- from deprecated import deprecated
29
28
 
30
29
  import mlrun.errors
31
30
  from mlrun.config import config as mlconf
@@ -37,34 +36,6 @@ _cached_control_session = None
37
36
  VolumeMount = namedtuple("Mount", ["path", "sub_path"])
38
37
 
39
38
 
40
- # TODO: Remove in 1.5.0
41
- @deprecated(
42
- version="1.3.0",
43
- reason="'mount_v3io_extended' will be removed in 1.5.0, use 'mount_v3io' instead",
44
- category=FutureWarning,
45
- )
46
- def mount_v3io_extended(
47
- name="v3io", remote="", mounts=None, access_key="", user="", secret=None
48
- ):
49
- """Modifier function to apply to a Container Op to volume mount a v3io path
50
- :param name: the volume name
51
- :param remote: the v3io path to use for the volume. ~/ prefix will be replaced with /users/<username>/
52
- :param mounts: list of mount & volume sub paths (type VolumeMount).
53
- empty mounts & remote will default to mount /v3io & /User.
54
- :param access_key: the access key used to auth against v3io. if not given V3IO_ACCESS_KEY env var will be used
55
- :param user: the username used to auth against v3io. if not given V3IO_USERNAME env var will be used
56
- :param secret: k8s secret name which would be used to get the username and access key to auth against v3io.
57
- """
58
- return mount_v3io(
59
- name=name,
60
- remote=remote,
61
- volume_mounts=mounts,
62
- access_key=access_key,
63
- user=user,
64
- secret=secret,
65
- )
66
-
67
-
68
39
  def mount_v3io(
69
40
  name="v3io",
70
41
  remote="",
@@ -109,33 +80,6 @@ def mount_v3io(
109
80
  return _attach_volume_mounts_and_creds
110
81
 
111
82
 
112
- # TODO: Remove in 1.5.0
113
- @deprecated(
114
- version="1.3.0",
115
- reason="'mount_v3io_legacy' will be removed in 1.5.0, use 'mount_v3io' instead",
116
- category=FutureWarning,
117
- )
118
- def mount_v3io_legacy(
119
- name="v3io", remote="~/", mount_path="/User", access_key="", user="", secret=None
120
- ):
121
- """Modifier function to apply to a Container Op to volume mount a v3io path
122
- :param name: the volume name
123
- :param remote: the v3io path to use for the volume. ~/ prefix will be replaced with /users/<username>/
124
- :param mount_path: the volume mount path
125
- :param access_key: the access key used to auth against v3io. if not given V3IO_ACCESS_KEY env var will be used
126
- :param user: the username used to auth against v3io. if not given V3IO_USERNAME env var will be used
127
- :param secret: k8s secret name which would be used to get the username and access key to auth against v3io.
128
- """
129
- return mount_v3io(
130
- name=name,
131
- remote=remote,
132
- volume_mounts=[VolumeMount(path=mount_path, sub_path="")],
133
- access_key=access_key,
134
- user=user,
135
- secret=secret,
136
- )
137
-
138
-
139
83
  def _enrich_and_validate_v3io_mounts(remote="", volume_mounts=None, user=""):
140
84
  if remote and not volume_mounts:
141
85
  raise mlrun.errors.MLRunInvalidArgumentError(
@@ -16,11 +16,9 @@ import builtins
16
16
  import importlib.util as imputil
17
17
  import os
18
18
  import tempfile
19
- import time
20
19
  import traceback
21
20
  import typing
22
21
  import uuid
23
- import warnings
24
22
 
25
23
  import kfp.compiler
26
24
  from kfp import dsl
@@ -34,9 +32,11 @@ from mlrun.utils import (
34
32
  get_ui_url,
35
33
  logger,
36
34
  new_pipe_metadata,
37
- parse_versioned_object_uri,
35
+ normalize_workflow_name,
36
+ retry_until_successful,
38
37
  )
39
38
 
39
+ from ..common.helpers import parse_versioned_object_uri
40
40
  from ..config import config
41
41
  from ..run import _run_pipeline, wait_for_pipeline_completion
42
42
  from ..runtimes.pod import AutoMountType
@@ -76,32 +76,23 @@ class WorkflowSpec(mlrun.model.ModelObj):
76
76
  args=None,
77
77
  name=None,
78
78
  handler=None,
79
- # TODO: deprecated, remove in 1.5.0
80
- ttl=None,
81
79
  args_schema: dict = None,
82
80
  schedule: typing.Union[str, mlrun.common.schemas.ScheduleCronTrigger] = None,
83
81
  cleanup_ttl: int = None,
82
+ image: str = None,
84
83
  ):
85
- if ttl:
86
- warnings.warn(
87
- "'ttl' is deprecated, use 'cleanup_ttl' instead. "
88
- "This will be removed in 1.5.0",
89
- # TODO: Remove this in 1.5.0
90
- FutureWarning,
91
- )
92
-
93
84
  self.engine = engine
94
85
  self.code = code
95
86
  self.path = path
96
87
  self.args = args
97
88
  self.name = name
98
89
  self.handler = handler
99
- self.ttl = cleanup_ttl or ttl
100
- self.cleanup_ttl = cleanup_ttl or ttl
90
+ self.cleanup_ttl = cleanup_ttl
101
91
  self.args_schema = args_schema
102
92
  self.run_local = False
103
93
  self._tmp_path = None
104
94
  self.schedule = schedule
95
+ self.image = image
105
96
 
106
97
  def get_source_file(self, context=""):
107
98
  if not self.code and not self.path:
@@ -557,7 +548,7 @@ class _KFPRunner(_PipelineRunner):
557
548
 
558
549
  conf = new_pipe_metadata(
559
550
  artifact_path=artifact_path,
560
- cleanup_ttl=workflow_spec.cleanup_ttl or workflow_spec.ttl,
551
+ cleanup_ttl=workflow_spec.cleanup_ttl,
561
552
  )
562
553
  compiler.Compiler().compile(pipeline, target, pipeline_conf=conf)
563
554
  workflow_spec.clear_tmp()
@@ -590,7 +581,7 @@ class _KFPRunner(_PipelineRunner):
590
581
  experiment=name or workflow_spec.name,
591
582
  namespace=namespace,
592
583
  artifact_path=artifact_path,
593
- cleanup_ttl=workflow_spec.cleanup_ttl or workflow_spec.ttl,
584
+ cleanup_ttl=workflow_spec.cleanup_ttl,
594
585
  )
595
586
  project.notifiers.push_pipeline_start_message(
596
587
  project.metadata.name,
@@ -751,137 +742,56 @@ class _RemoteRunner(_PipelineRunner):
751
742
 
752
743
  engine = "remote"
753
744
 
754
- @staticmethod
755
- def _prepare_load_and_run_function(
756
- source: str,
757
- project_name: str,
758
- save: bool,
759
- workflow_name: str,
760
- workflow_spec: WorkflowSpec,
761
- artifact_path: str,
762
- workflow_handler: str,
763
- namespace: str,
764
- subpath: str,
765
- ) -> typing.Tuple[mlrun.runtimes.RemoteRuntime, "mlrun.RunObject"]:
766
- """
767
- Helper function for creating the runspec of the load and run function.
768
- For internal use only.
769
- :param source: The source of the project.
770
- :param project_name: project name
771
- :param save: either to save the project in the DB
772
- :param workflow_name: workflow name
773
- :param workflow_spec: workflow to run
774
- :param artifact_path: path to store artifacts
775
- :param workflow_handler: workflow function handler (for running workflow function directly)
776
- :param namespace: kubernetes namespace if other than default
777
- :param subpath: project subpath (within the archive)
778
- :return:
779
- """
780
- # Creating the load project and workflow running function:
781
- load_and_run_fn = mlrun.new_function(
782
- name=mlrun.mlconf.default_workflow_runner_name.format(workflow_name),
783
- project=project_name,
784
- kind="job",
785
- image=mlrun.mlconf.default_base_image,
786
- )
787
- runspec = mlrun.RunObject(
788
- spec=mlrun.model.RunSpec(
789
- parameters={
790
- "url": source,
791
- "project_name": project_name,
792
- "save": save,
793
- "workflow_name": workflow_name or workflow_spec.name,
794
- "workflow_path": workflow_spec.path,
795
- "workflow_arguments": workflow_spec.args,
796
- "artifact_path": artifact_path,
797
- "workflow_handler": workflow_handler or workflow_spec.handler,
798
- "namespace": namespace,
799
- "ttl": workflow_spec.cleanup_ttl or workflow_spec.ttl,
800
- "engine": workflow_spec.engine,
801
- "local": workflow_spec.run_local,
802
- "schedule": workflow_spec.schedule,
803
- "subpath": subpath,
804
- },
805
- handler="mlrun.projects.load_and_run",
806
- ),
807
- metadata=mlrun.model.RunMetadata(name=workflow_name),
808
- )
809
-
810
- runspec = runspec.set_label("job-type", "workflow-runner").set_label(
811
- "workflow", workflow_name
812
- )
813
- return load_and_run_fn, runspec
814
-
815
745
  @classmethod
816
746
  def run(
817
747
  cls,
818
- project,
748
+ project: "mlrun.projects.MlrunProject",
819
749
  workflow_spec: WorkflowSpec,
820
- name=None,
821
- workflow_handler=None,
822
- secrets=None,
823
- artifact_path=None,
824
- namespace=None,
825
- source=None,
750
+ name: str = None,
751
+ workflow_handler: typing.Union[str, typing.Callable] = None,
752
+ secrets: mlrun.secrets.SecretsStore = None,
753
+ artifact_path: str = None,
754
+ namespace: str = None,
755
+ source: str = None,
826
756
  ) -> typing.Optional[_PipelineRunStatus]:
827
- workflow_name = name.split("-")[-1] if f"{project.name}-" in name else name
828
-
829
- run_id = None
830
-
831
- # If the user provided a source we want to load the project from the source
832
- # (like from a specific commit/branch from git repo) without changing the source of the project (save=False).
833
- save, current_source = (
834
- (False, source) if source else (True, project.spec.source)
835
- )
836
- if "://" not in current_source:
837
- raise mlrun.errors.MLRunInvalidArgumentError(
838
- f"Remote workflows can only be performed by a project with remote source (e.g git:// or http://),"
839
- f" but the specified source '{current_source}' is not remote. "
840
- f"Either put your code in Git, or archive it and then set a source to it."
841
- f" For more details, read"
842
- f" https://docs.mlrun.org/en/latest/concepts/scheduled-jobs.html#scheduling-a-workflow"
843
- )
844
-
845
- # Creating the load project and workflow running function:
846
- load_and_run_fn, runspec = cls._prepare_load_and_run_function(
847
- source=current_source,
848
- project_name=project.name,
849
- save=save,
850
- workflow_name=workflow_name,
851
- workflow_spec=workflow_spec,
852
- artifact_path=artifact_path,
853
- workflow_handler=workflow_handler,
854
- namespace=namespace,
855
- subpath=project.spec.subpath,
856
- )
757
+ workflow_name = normalize_workflow_name(name=name, project_name=project.name)
758
+ workflow_id = None
857
759
 
858
760
  # The returned engine for this runner is the engine of the workflow.
859
761
  # In this way wait_for_completion/get_run_status would be executed by the correct pipeline runner.
860
762
  inner_engine = get_workflow_engine(workflow_spec.engine)
861
-
862
- msg = "executing workflow"
863
- if workflow_spec.schedule:
864
- msg += " scheduling"
865
- logger.info(
866
- f"{msg} '{load_and_run_fn.metadata.name}' remotely with {workflow_spec.engine} engine"
867
- )
868
-
763
+ run_db = mlrun.get_run_db()
869
764
  try:
870
- run = load_and_run_fn.run(
871
- runspec=runspec,
872
- local=False,
873
- schedule=workflow_spec.schedule,
765
+ workflow_response = run_db.submit_workflow(
766
+ project=project.name,
767
+ name=workflow_name,
768
+ workflow_spec=workflow_spec,
874
769
  artifact_path=artifact_path,
770
+ source=source,
771
+ run_name=config.workflows.default_workflow_runner_name.format(
772
+ workflow_name
773
+ ),
774
+ namespace=namespace,
875
775
  )
876
776
  if workflow_spec.schedule:
877
777
  return
878
- # Fetching workflow id:
879
- while not run_id:
880
- run.refresh()
881
- run_id = run.status.results.get("workflow_id", None)
882
- time.sleep(1)
778
+
779
+ # Getting workflow id from run:
780
+ response = retry_until_successful(
781
+ 1,
782
+ getattr(mlrun.mlconf.workflows.timeouts, inner_engine.engine),
783
+ logger,
784
+ False,
785
+ run_db.get_workflow_id,
786
+ project=project.name,
787
+ name=workflow_response.name,
788
+ run_id=workflow_response.run_id,
789
+ engine=workflow_spec.engine,
790
+ )
791
+ workflow_id = response.workflow_id
883
792
  # After fetching the workflow_id the workflow executed successfully
884
793
  state = mlrun.run.RunStatuses.succeeded
794
+ pipeline_context.clear()
885
795
 
886
796
  except Exception as e:
887
797
  trace = traceback.format_exc()
@@ -892,8 +802,8 @@ class _RemoteRunner(_PipelineRunner):
892
802
  )
893
803
  state = mlrun.run.RunStatuses.failed
894
804
  return _PipelineRunStatus(
895
- run_id,
896
- inner_engine,
805
+ run_id=workflow_id,
806
+ engine=inner_engine,
897
807
  project=project,
898
808
  workflow=workflow_spec,
899
809
  state=state,
@@ -904,8 +814,8 @@ class _RemoteRunner(_PipelineRunner):
904
814
  )
905
815
  pipeline_context.clear()
906
816
  return _PipelineRunStatus(
907
- run_id,
908
- inner_engine,
817
+ run_id=workflow_id,
818
+ engine=inner_engine,
909
819
  project=project,
910
820
  workflow=workflow_spec,
911
821
  state=state,
@@ -923,16 +833,6 @@ def create_pipeline(project, pipeline, functions, secrets=None, handler=None):
923
833
  setattr(mod, "functions", functions)
924
834
  setattr(mod, "this_project", project)
925
835
 
926
- if hasattr(mod, "init_functions"):
927
-
928
- # TODO: remove in 1.5.0
929
- warnings.warn(
930
- "'init_functions' is deprecated in 1.3.0 and will be removed in 1.5.0. "
931
- "Place function initialization in the pipeline code.",
932
- FutureWarning,
933
- )
934
- getattr(mod, "init_functions")(functions, project, secrets)
935
-
936
836
  # verify all functions are in this project (init_functions may add new functions)
937
837
  for f in functions.values():
938
838
  f.metadata.project = project.metadata.name
@@ -981,12 +881,11 @@ def load_and_run(
981
881
  namespace: str = None,
982
882
  sync: bool = False,
983
883
  dirty: bool = False,
984
- # TODO: deprecated, remove in 1.5.0
985
- ttl: int = None,
986
884
  engine: str = None,
987
885
  local: bool = None,
988
886
  schedule: typing.Union[str, mlrun.common.schemas.ScheduleCronTrigger] = None,
989
887
  cleanup_ttl: int = None,
888
+ load_only: bool = False,
990
889
  ):
991
890
  """
992
891
  Auxiliary function that the RemoteRunner run once or run every schedule.
@@ -1009,23 +908,14 @@ def load_and_run(
1009
908
  :param namespace: kubernetes namespace if other than default
1010
909
  :param sync: force functions sync before run
1011
910
  :param dirty: allow running the workflow when the git repo is dirty
1012
- :param ttl: pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
1013
- workflow and all its resources are deleted) (deprecated, use cleanup_ttl instead)
1014
911
  :param engine: workflow engine running the workflow.
1015
912
  supported values are 'kfp' (default) or 'local'
1016
913
  :param local: run local pipeline with local functions (set local=True in function.run())
1017
914
  :param schedule: ScheduleCronTrigger class instance or a standard crontab expression string
1018
915
  :param cleanup_ttl: pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
1019
916
  workflow and all its resources are deleted)
917
+ :param load_only: for just loading the project, inner use.
1020
918
  """
1021
- if ttl:
1022
- warnings.warn(
1023
- "'ttl' is deprecated, use 'cleanup_ttl' instead. "
1024
- "This will be removed in 1.5.0",
1025
- # TODO: Remove this in 1.5.0
1026
- FutureWarning,
1027
- )
1028
-
1029
919
  try:
1030
920
  project = mlrun.load_project(
1031
921
  context=f"./{project_name}",
@@ -1035,6 +925,7 @@ def load_and_run(
1035
925
  subpath=subpath,
1036
926
  clone=clone,
1037
927
  save=save,
928
+ sync_functions=True,
1038
929
  )
1039
930
  except Exception as error:
1040
931
  if schedule:
@@ -1061,6 +952,9 @@ def load_and_run(
1061
952
 
1062
953
  context.logger.info(f"Loaded project {project.name} from remote successfully")
1063
954
 
955
+ if load_only:
956
+ return
957
+
1064
958
  workflow_log_message = workflow_name or workflow_path
1065
959
  context.logger.info(f"Running workflow {workflow_log_message} from remote")
1066
960
  run = project.run(
@@ -1073,7 +967,7 @@ def load_and_run(
1073
967
  sync=sync,
1074
968
  watch=False, # Required for fetching the workflow_id
1075
969
  dirty=dirty,
1076
- cleanup_ttl=cleanup_ttl or ttl,
970
+ cleanup_ttl=cleanup_ttl,
1077
971
  engine=engine,
1078
972
  local=local,
1079
973
  )