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.
- mlrun/__init__.py +2 -35
- mlrun/__main__.py +3 -41
- mlrun/api/api/api.py +6 -0
- mlrun/api/api/endpoints/feature_store.py +0 -4
- mlrun/api/api/endpoints/files.py +14 -2
- mlrun/api/api/endpoints/frontend_spec.py +2 -1
- mlrun/api/api/endpoints/functions.py +95 -59
- mlrun/api/api/endpoints/grafana_proxy.py +9 -9
- mlrun/api/api/endpoints/logs.py +17 -3
- mlrun/api/api/endpoints/model_endpoints.py +3 -2
- mlrun/api/api/endpoints/pipelines.py +1 -5
- mlrun/api/api/endpoints/projects.py +88 -0
- mlrun/api/api/endpoints/runs.py +48 -6
- mlrun/api/api/endpoints/submit.py +2 -1
- mlrun/api/api/endpoints/workflows.py +355 -0
- mlrun/api/api/utils.py +3 -4
- mlrun/api/crud/__init__.py +1 -0
- mlrun/api/crud/client_spec.py +6 -2
- mlrun/api/crud/feature_store.py +5 -0
- mlrun/api/crud/model_monitoring/__init__.py +1 -0
- mlrun/api/crud/model_monitoring/deployment.py +497 -0
- mlrun/api/crud/model_monitoring/grafana.py +96 -42
- mlrun/api/crud/model_monitoring/helpers.py +159 -0
- mlrun/api/crud/model_monitoring/model_endpoints.py +202 -476
- mlrun/api/crud/notifications.py +9 -4
- mlrun/api/crud/pipelines.py +6 -11
- mlrun/api/crud/projects.py +2 -2
- mlrun/api/crud/runtime_resources.py +4 -3
- mlrun/api/crud/runtimes/nuclio/helpers.py +5 -1
- mlrun/api/crud/secrets.py +21 -0
- mlrun/api/crud/workflows.py +352 -0
- mlrun/api/db/base.py +16 -1
- mlrun/api/db/init_db.py +2 -4
- mlrun/api/db/session.py +1 -1
- mlrun/api/db/sqldb/db.py +129 -31
- mlrun/api/db/sqldb/models/models_mysql.py +15 -1
- mlrun/api/db/sqldb/models/models_sqlite.py +16 -2
- mlrun/api/launcher.py +38 -6
- mlrun/api/main.py +3 -2
- mlrun/api/rundb/__init__.py +13 -0
- mlrun/{db → api/rundb}/sqldb.py +36 -84
- mlrun/api/runtime_handlers/__init__.py +56 -0
- mlrun/api/runtime_handlers/base.py +1247 -0
- mlrun/api/runtime_handlers/daskjob.py +209 -0
- mlrun/api/runtime_handlers/kubejob.py +37 -0
- mlrun/api/runtime_handlers/mpijob.py +147 -0
- mlrun/api/runtime_handlers/remotesparkjob.py +29 -0
- mlrun/api/runtime_handlers/sparkjob.py +148 -0
- mlrun/api/schemas/__init__.py +17 -6
- mlrun/api/utils/builder.py +1 -4
- mlrun/api/utils/clients/chief.py +14 -0
- mlrun/api/utils/clients/iguazio.py +33 -33
- mlrun/api/utils/clients/nuclio.py +2 -2
- mlrun/api/utils/periodic.py +9 -2
- mlrun/api/utils/projects/follower.py +14 -7
- mlrun/api/utils/projects/leader.py +2 -1
- mlrun/api/utils/projects/remotes/nop_follower.py +2 -2
- mlrun/api/utils/projects/remotes/nop_leader.py +2 -2
- mlrun/api/utils/runtimes/__init__.py +14 -0
- mlrun/api/utils/runtimes/nuclio.py +43 -0
- mlrun/api/utils/scheduler.py +98 -15
- mlrun/api/utils/singletons/db.py +5 -1
- mlrun/api/utils/singletons/project_member.py +4 -1
- mlrun/api/utils/singletons/scheduler.py +1 -1
- mlrun/artifacts/base.py +6 -6
- mlrun/artifacts/dataset.py +4 -4
- mlrun/artifacts/manager.py +2 -3
- mlrun/artifacts/model.py +2 -2
- mlrun/artifacts/plots.py +8 -8
- mlrun/common/db/__init__.py +14 -0
- mlrun/common/helpers.py +37 -0
- mlrun/{mlutils → common/model_monitoring}/__init__.py +3 -2
- mlrun/common/model_monitoring/helpers.py +69 -0
- mlrun/common/schemas/__init__.py +13 -1
- mlrun/common/schemas/auth.py +4 -1
- mlrun/common/schemas/client_spec.py +1 -1
- mlrun/common/schemas/function.py +17 -0
- mlrun/common/schemas/model_monitoring/__init__.py +48 -0
- mlrun/common/{model_monitoring.py → schemas/model_monitoring/constants.py} +11 -23
- mlrun/common/schemas/model_monitoring/grafana.py +55 -0
- mlrun/common/schemas/{model_endpoints.py → model_monitoring/model_endpoints.py} +32 -65
- mlrun/common/schemas/notification.py +1 -0
- mlrun/common/schemas/object.py +4 -0
- mlrun/common/schemas/project.py +1 -0
- mlrun/common/schemas/regex.py +1 -1
- mlrun/common/schemas/runs.py +1 -8
- mlrun/common/schemas/schedule.py +1 -8
- mlrun/common/schemas/workflow.py +54 -0
- mlrun/config.py +45 -42
- mlrun/datastore/__init__.py +21 -0
- mlrun/datastore/base.py +1 -1
- mlrun/datastore/datastore.py +9 -0
- mlrun/datastore/dbfs_store.py +168 -0
- mlrun/datastore/helpers.py +18 -0
- mlrun/datastore/sources.py +1 -0
- mlrun/datastore/store_resources.py +2 -5
- mlrun/datastore/v3io.py +1 -2
- mlrun/db/__init__.py +4 -68
- mlrun/db/base.py +12 -0
- mlrun/db/factory.py +65 -0
- mlrun/db/httpdb.py +175 -20
- mlrun/db/nopdb.py +4 -2
- mlrun/execution.py +4 -2
- mlrun/feature_store/__init__.py +1 -0
- mlrun/feature_store/api.py +1 -2
- mlrun/feature_store/common.py +2 -1
- mlrun/feature_store/feature_set.py +1 -11
- mlrun/feature_store/feature_vector.py +340 -2
- mlrun/feature_store/ingestion.py +5 -10
- mlrun/feature_store/retrieval/base.py +118 -104
- mlrun/feature_store/retrieval/dask_merger.py +17 -10
- mlrun/feature_store/retrieval/job.py +4 -1
- mlrun/feature_store/retrieval/local_merger.py +18 -18
- mlrun/feature_store/retrieval/spark_merger.py +21 -14
- mlrun/feature_store/retrieval/storey_merger.py +22 -16
- mlrun/kfpops.py +3 -9
- mlrun/launcher/base.py +57 -53
- mlrun/launcher/client.py +5 -4
- mlrun/launcher/factory.py +24 -13
- mlrun/launcher/local.py +6 -6
- mlrun/launcher/remote.py +4 -4
- mlrun/lists.py +0 -11
- mlrun/model.py +11 -17
- mlrun/model_monitoring/__init__.py +2 -22
- mlrun/model_monitoring/features_drift_table.py +1 -1
- mlrun/model_monitoring/helpers.py +22 -210
- mlrun/model_monitoring/model_endpoint.py +1 -1
- mlrun/model_monitoring/model_monitoring_batch.py +127 -50
- mlrun/model_monitoring/prometheus.py +219 -0
- mlrun/model_monitoring/stores/__init__.py +16 -11
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +95 -23
- mlrun/model_monitoring/stores/models/mysql.py +47 -29
- mlrun/model_monitoring/stores/models/sqlite.py +47 -29
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +31 -19
- mlrun/model_monitoring/{stream_processing_fs.py → stream_processing.py} +206 -64
- mlrun/model_monitoring/tracking_policy.py +104 -0
- mlrun/package/packager.py +6 -8
- mlrun/package/packagers/default_packager.py +121 -10
- mlrun/package/packagers/numpy_packagers.py +1 -1
- mlrun/platforms/__init__.py +0 -2
- mlrun/platforms/iguazio.py +0 -56
- mlrun/projects/pipelines.py +53 -159
- mlrun/projects/project.py +10 -37
- mlrun/render.py +1 -1
- mlrun/run.py +8 -124
- mlrun/runtimes/__init__.py +6 -42
- mlrun/runtimes/base.py +29 -1249
- mlrun/runtimes/daskjob.py +2 -198
- mlrun/runtimes/funcdoc.py +0 -9
- mlrun/runtimes/function.py +25 -29
- mlrun/runtimes/kubejob.py +5 -29
- mlrun/runtimes/local.py +1 -1
- mlrun/runtimes/mpijob/__init__.py +2 -2
- mlrun/runtimes/mpijob/abstract.py +10 -1
- mlrun/runtimes/mpijob/v1.py +0 -76
- mlrun/runtimes/mpijob/v1alpha1.py +1 -74
- mlrun/runtimes/nuclio.py +3 -2
- mlrun/runtimes/pod.py +28 -18
- mlrun/runtimes/remotesparkjob.py +1 -15
- mlrun/runtimes/serving.py +14 -6
- mlrun/runtimes/sparkjob/__init__.py +0 -1
- mlrun/runtimes/sparkjob/abstract.py +4 -131
- mlrun/runtimes/utils.py +0 -26
- mlrun/serving/routers.py +7 -7
- mlrun/serving/server.py +11 -8
- mlrun/serving/states.py +7 -1
- mlrun/serving/v2_serving.py +6 -6
- mlrun/utils/helpers.py +23 -42
- mlrun/utils/notifications/notification/__init__.py +4 -0
- mlrun/utils/notifications/notification/webhook.py +61 -0
- mlrun/utils/notifications/notification_pusher.py +5 -25
- mlrun/utils/regex.py +7 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/METADATA +26 -25
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/RECORD +180 -158
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/WHEEL +1 -1
- mlrun/mlutils/data.py +0 -160
- mlrun/mlutils/models.py +0 -78
- mlrun/mlutils/plots.py +0 -902
- mlrun/utils/model_monitoring.py +0 -249
- /mlrun/{api/db/sqldb/session.py → common/db/sql_session.py} +0 -0
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/LICENSE +0 -0
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/entry_points.txt +0 -0
- {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
|
|
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
|
|
102
|
-
logging the artifact. The packager can mark paths of files and directories to delete after logging using the
|
|
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
|
-
|
|
223
|
+
#: The type of object this packager can pack and unpack.
|
|
116
224
|
PACKABLE_OBJECT_TYPE: Type = ...
|
|
117
|
-
|
|
225
|
+
|
|
226
|
+
#: A flag for indicating whether to pack all subclasses of the `PACKABLE_OBJECT_TYPE` as well.
|
|
118
227
|
PACK_SUBCLASSES = False
|
|
119
|
-
|
|
228
|
+
|
|
229
|
+
#: The default artifact type to pack as.
|
|
120
230
|
DEFAULT_PACKING_ARTIFACT_TYPE = ArtifactType.OBJECT
|
|
121
|
-
|
|
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
|
mlrun/platforms/__init__.py
CHANGED
mlrun/platforms/iguazio.py
CHANGED
|
@@ -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(
|
mlrun/projects/pipelines.py
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
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
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
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
|
|
970
|
+
cleanup_ttl=cleanup_ttl,
|
|
1077
971
|
engine=engine,
|
|
1078
972
|
local=local,
|
|
1079
973
|
)
|