mlrun 1.7.0rc15__py3-none-any.whl → 1.7.0rc17__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 +10 -1
- mlrun/__main__.py +18 -4
- mlrun/alerts/__init__.py +15 -0
- mlrun/alerts/alert.py +144 -0
- mlrun/artifacts/__init__.py +7 -1
- mlrun/artifacts/base.py +28 -3
- mlrun/artifacts/dataset.py +8 -0
- mlrun/artifacts/manager.py +18 -0
- mlrun/artifacts/model.py +8 -1
- mlrun/artifacts/plots.py +13 -0
- mlrun/common/schemas/__init__.py +10 -2
- mlrun/common/schemas/alert.py +64 -5
- mlrun/common/schemas/api_gateway.py +4 -0
- mlrun/common/schemas/artifact.py +15 -0
- mlrun/common/schemas/auth.py +2 -0
- mlrun/common/schemas/model_monitoring/__init__.py +4 -1
- mlrun/common/schemas/model_monitoring/constants.py +17 -1
- mlrun/common/schemas/model_monitoring/model_endpoints.py +60 -1
- mlrun/common/schemas/project.py +5 -1
- mlrun/config.py +11 -4
- mlrun/datastore/datastore_profile.py +10 -7
- mlrun/db/base.py +24 -4
- mlrun/db/httpdb.py +97 -43
- mlrun/db/nopdb.py +25 -4
- mlrun/errors.py +5 -0
- mlrun/launcher/base.py +3 -2
- mlrun/lists.py +4 -0
- mlrun/model.py +15 -8
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/applications/_application_steps.py +1 -2
- mlrun/model_monitoring/applications/context.py +1 -1
- mlrun/model_monitoring/applications/histogram_data_drift.py +64 -38
- mlrun/model_monitoring/db/__init__.py +2 -0
- mlrun/model_monitoring/db/stores/base/store.py +9 -36
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +63 -110
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +56 -202
- mlrun/model_monitoring/db/tsdb/__init__.py +71 -0
- mlrun/model_monitoring/db/tsdb/base.py +135 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +442 -0
- mlrun/model_monitoring/db/v3io_tsdb_reader.py +134 -0
- mlrun/model_monitoring/stream_processing.py +46 -210
- mlrun/model_monitoring/writer.py +50 -100
- mlrun/platforms/__init__.py +10 -9
- mlrun/platforms/iguazio.py +19 -200
- mlrun/projects/operations.py +11 -7
- mlrun/projects/pipelines.py +13 -76
- mlrun/projects/project.py +62 -17
- mlrun/render.py +9 -3
- mlrun/run.py +5 -38
- mlrun/runtimes/__init__.py +1 -0
- mlrun/runtimes/base.py +3 -3
- mlrun/runtimes/kubejob.py +2 -1
- mlrun/runtimes/nuclio/api_gateway.py +163 -77
- mlrun/runtimes/nuclio/application/application.py +160 -7
- mlrun/runtimes/nuclio/function.py +25 -45
- mlrun/runtimes/pod.py +16 -36
- mlrun/runtimes/remotesparkjob.py +1 -1
- mlrun/runtimes/sparkjob/spark3job.py +1 -1
- mlrun/runtimes/utils.py +0 -38
- mlrun/track/tracker.py +2 -1
- mlrun/utils/helpers.py +51 -31
- mlrun/utils/logger.py +11 -6
- mlrun/utils/notifications/notification/base.py +1 -1
- mlrun/utils/notifications/notification/slack.py +9 -4
- mlrun/utils/notifications/notification/webhook.py +1 -1
- mlrun/utils/notifications/notification_pusher.py +21 -14
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/METADATA +4 -3
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/RECORD +75 -69
- mlrun/kfpops.py +0 -860
- mlrun/platforms/other.py +0 -305
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/WHEEL +0 -0
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/top_level.txt +0 -0
mlrun/__init__.py
CHANGED
|
@@ -22,11 +22,16 @@ __all__ = [
|
|
|
22
22
|
"handler",
|
|
23
23
|
"ArtifactType",
|
|
24
24
|
"get_secret_or_env",
|
|
25
|
+
"mount_v3io",
|
|
26
|
+
"v3io_cred",
|
|
27
|
+
"auto_mount",
|
|
28
|
+
"VolumeMount",
|
|
25
29
|
]
|
|
26
30
|
|
|
27
31
|
from os import environ, path
|
|
28
32
|
|
|
29
33
|
import dotenv
|
|
34
|
+
import mlrun_pipelines
|
|
30
35
|
|
|
31
36
|
from .config import config as mlconf
|
|
32
37
|
from .datastore import DataItem, store_manager
|
|
@@ -35,7 +40,6 @@ from .errors import MLRunInvalidArgumentError, MLRunNotFoundError
|
|
|
35
40
|
from .execution import MLClientCtx
|
|
36
41
|
from .model import RunObject, RunTemplate, new_task
|
|
37
42
|
from .package import ArtifactType, DefaultPackager, Packager, handler
|
|
38
|
-
from .platforms import VolumeMount, auto_mount, mount_v3io, v3io_cred
|
|
39
43
|
from .projects import (
|
|
40
44
|
ProjectMetadata,
|
|
41
45
|
build_function,
|
|
@@ -65,6 +69,11 @@ from .utils.version import Version
|
|
|
65
69
|
|
|
66
70
|
__version__ = Version().get()["version"]
|
|
67
71
|
|
|
72
|
+
VolumeMount = mlrun_pipelines.common.mounts.VolumeMount
|
|
73
|
+
mount_v3io = mlrun_pipelines.mounts.mount_v3io
|
|
74
|
+
v3io_cred = mlrun_pipelines.mounts.v3io_cred
|
|
75
|
+
auto_mount = mlrun_pipelines.mounts.auto_mount
|
|
76
|
+
|
|
68
77
|
|
|
69
78
|
def get_version():
|
|
70
79
|
"""get current mlrun version"""
|
mlrun/__main__.py
CHANGED
|
@@ -27,6 +27,7 @@ import click
|
|
|
27
27
|
import dotenv
|
|
28
28
|
import pandas as pd
|
|
29
29
|
import yaml
|
|
30
|
+
from mlrun_pipelines.mounts import auto_mount as auto_mount_modifier
|
|
30
31
|
from tabulate import tabulate
|
|
31
32
|
|
|
32
33
|
import mlrun
|
|
@@ -37,7 +38,6 @@ from .config import config as mlconf
|
|
|
37
38
|
from .db import get_run_db
|
|
38
39
|
from .errors import err_to_str
|
|
39
40
|
from .model import RunTemplate
|
|
40
|
-
from .platforms import auto_mount as auto_mount_modifier
|
|
41
41
|
from .projects import load_project
|
|
42
42
|
from .run import (
|
|
43
43
|
get_object,
|
|
@@ -466,6 +466,17 @@ def run(
|
|
|
466
466
|
is_flag=True,
|
|
467
467
|
help="ensure the project exists, if not, create project",
|
|
468
468
|
)
|
|
469
|
+
@click.option(
|
|
470
|
+
"--state-file-path", default="/tmp/state", help="path to file with state data"
|
|
471
|
+
)
|
|
472
|
+
@click.option(
|
|
473
|
+
"--image-file-path", default="/tmp/image", help="path to file with image data"
|
|
474
|
+
)
|
|
475
|
+
@click.option(
|
|
476
|
+
"--full-image-file-path",
|
|
477
|
+
default="/tmp/fullimage",
|
|
478
|
+
help="path to file with full image data",
|
|
479
|
+
)
|
|
469
480
|
def build(
|
|
470
481
|
func_url,
|
|
471
482
|
name,
|
|
@@ -485,6 +496,9 @@ def build(
|
|
|
485
496
|
skip,
|
|
486
497
|
env_file,
|
|
487
498
|
ensure_project,
|
|
499
|
+
state_file_path,
|
|
500
|
+
image_file_path,
|
|
501
|
+
full_image_file_path,
|
|
488
502
|
):
|
|
489
503
|
"""Build a container image from code and requirements."""
|
|
490
504
|
|
|
@@ -574,12 +588,12 @@ def build(
|
|
|
574
588
|
state = func.status.state
|
|
575
589
|
image = func.spec.image
|
|
576
590
|
if kfp:
|
|
577
|
-
with open(
|
|
591
|
+
with open(state_file_path, "w") as fp:
|
|
578
592
|
fp.write(state or "none")
|
|
579
593
|
full_image = func.full_image_path(image) or ""
|
|
580
|
-
with open(
|
|
594
|
+
with open(image_file_path, "w") as fp:
|
|
581
595
|
fp.write(image)
|
|
582
|
-
with open(
|
|
596
|
+
with open(full_image_file_path, "w") as fp:
|
|
583
597
|
fp.write(full_image)
|
|
584
598
|
print("Full image path = ", full_image)
|
|
585
599
|
|
mlrun/alerts/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2024 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
|
+
from .alert import AlertConfig
|
mlrun/alerts/alert.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Copyright 2024 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
|
+
from typing import Union
|
|
16
|
+
|
|
17
|
+
import mlrun
|
|
18
|
+
import mlrun.common.schemas.alert as alert_objects
|
|
19
|
+
from mlrun.model import ModelObj
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AlertConfig(ModelObj):
|
|
23
|
+
_dict_fields = [
|
|
24
|
+
"project",
|
|
25
|
+
"name",
|
|
26
|
+
"description",
|
|
27
|
+
"summary",
|
|
28
|
+
"severity",
|
|
29
|
+
"criteria",
|
|
30
|
+
"reset_policy",
|
|
31
|
+
"state",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
project: str = None,
|
|
37
|
+
name: str = None,
|
|
38
|
+
template: Union[alert_objects.AlertTemplate, str] = None,
|
|
39
|
+
description: str = None,
|
|
40
|
+
summary: str = None,
|
|
41
|
+
severity: alert_objects.AlertSeverity = None,
|
|
42
|
+
trigger: alert_objects.AlertTrigger = None,
|
|
43
|
+
criteria: alert_objects.AlertCriteria = None,
|
|
44
|
+
reset_policy: alert_objects.ResetPolicy = None,
|
|
45
|
+
notifications: list[alert_objects.AlertNotification] = None,
|
|
46
|
+
entities: alert_objects.EventEntities = None,
|
|
47
|
+
id: int = None,
|
|
48
|
+
state: alert_objects.AlertActiveState = None,
|
|
49
|
+
created: str = None,
|
|
50
|
+
count: int = None,
|
|
51
|
+
):
|
|
52
|
+
self.project = project
|
|
53
|
+
self.name = name
|
|
54
|
+
self.description = description
|
|
55
|
+
self.summary = summary
|
|
56
|
+
self.severity = severity
|
|
57
|
+
self.trigger = trigger
|
|
58
|
+
self.criteria = criteria
|
|
59
|
+
self.reset_policy = reset_policy
|
|
60
|
+
self.notifications = notifications or []
|
|
61
|
+
self.entities = entities
|
|
62
|
+
self.id = id
|
|
63
|
+
self.state = state
|
|
64
|
+
self.created = created
|
|
65
|
+
self.count = count
|
|
66
|
+
|
|
67
|
+
if template:
|
|
68
|
+
self._apply_template(template)
|
|
69
|
+
|
|
70
|
+
def validate_required_fields(self):
|
|
71
|
+
if not self.project or not self.name:
|
|
72
|
+
raise mlrun.errors.MLRunBadRequestError("Project and name must be provided")
|
|
73
|
+
|
|
74
|
+
def to_dict(self, fields: list = None, exclude: list = None, strip: bool = False):
|
|
75
|
+
data = super().to_dict(self._dict_fields)
|
|
76
|
+
|
|
77
|
+
data["entities"] = (
|
|
78
|
+
self.entities.dict()
|
|
79
|
+
if not isinstance(self.entities, dict)
|
|
80
|
+
else self.entities
|
|
81
|
+
)
|
|
82
|
+
data["notifications"] = [
|
|
83
|
+
notification_data.dict()
|
|
84
|
+
if not isinstance(notification_data, dict)
|
|
85
|
+
else notification_data
|
|
86
|
+
for notification_data in self.notifications
|
|
87
|
+
]
|
|
88
|
+
data["trigger"] = (
|
|
89
|
+
self.trigger.dict() if not isinstance(self.trigger, dict) else self.trigger
|
|
90
|
+
)
|
|
91
|
+
return data
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def from_dict(cls, struct=None, fields=None, deprecated_fields: dict = None):
|
|
95
|
+
new_obj = super().from_dict(struct, fields=fields)
|
|
96
|
+
|
|
97
|
+
entity_data = struct.get("entities")
|
|
98
|
+
if entity_data:
|
|
99
|
+
entity_obj = alert_objects.EventEntities.parse_obj(entity_data)
|
|
100
|
+
new_obj.entities = entity_obj
|
|
101
|
+
|
|
102
|
+
notifications_data = struct.get("notifications")
|
|
103
|
+
if notifications_data:
|
|
104
|
+
notifications_objs = [
|
|
105
|
+
alert_objects.AlertNotification.parse_obj(notification)
|
|
106
|
+
for notification in notifications_data
|
|
107
|
+
]
|
|
108
|
+
new_obj.notifications = notifications_objs
|
|
109
|
+
|
|
110
|
+
trigger_data = struct.get("trigger")
|
|
111
|
+
if trigger_data:
|
|
112
|
+
trigger_obj = alert_objects.AlertTrigger.parse_obj(trigger_data)
|
|
113
|
+
new_obj.trigger = trigger_obj
|
|
114
|
+
|
|
115
|
+
return new_obj
|
|
116
|
+
|
|
117
|
+
def with_notifications(self, notifications: list[alert_objects.AlertNotification]):
|
|
118
|
+
if not isinstance(notifications, list) or not all(
|
|
119
|
+
isinstance(item, alert_objects.AlertNotification) for item in notifications
|
|
120
|
+
):
|
|
121
|
+
raise ValueError(
|
|
122
|
+
"Notifications parameter must be a list of AlertNotification"
|
|
123
|
+
)
|
|
124
|
+
for notification_data in notifications:
|
|
125
|
+
self.notifications.append(notification_data)
|
|
126
|
+
return self
|
|
127
|
+
|
|
128
|
+
def with_entities(self, entities: alert_objects.EventEntities):
|
|
129
|
+
if not isinstance(entities, alert_objects.EventEntities):
|
|
130
|
+
raise ValueError("Entities parameter must be of type: EventEntities")
|
|
131
|
+
self.entities = entities
|
|
132
|
+
return self
|
|
133
|
+
|
|
134
|
+
def _apply_template(self, template):
|
|
135
|
+
if isinstance(template, str):
|
|
136
|
+
db = mlrun.get_run_db()
|
|
137
|
+
template = db.get_alert_template(template)
|
|
138
|
+
|
|
139
|
+
# Extract parameters from the template and apply them to the AlertConfig object
|
|
140
|
+
self.description = template.description
|
|
141
|
+
self.severity = template.severity
|
|
142
|
+
self.criteria = template.criteria
|
|
143
|
+
self.trigger = template.trigger
|
|
144
|
+
self.reset_policy = template.reset_policy
|
mlrun/artifacts/__init__.py
CHANGED
|
@@ -17,7 +17,13 @@
|
|
|
17
17
|
# Don't remove this, used by sphinx documentation
|
|
18
18
|
__all__ = ["get_model", "update_model"]
|
|
19
19
|
|
|
20
|
-
from .base import
|
|
20
|
+
from .base import (
|
|
21
|
+
Artifact,
|
|
22
|
+
ArtifactMetadata,
|
|
23
|
+
ArtifactSpec,
|
|
24
|
+
DirArtifact,
|
|
25
|
+
get_artifact_meta,
|
|
26
|
+
)
|
|
21
27
|
from .dataset import DatasetArtifact, TableArtifact, update_dataset_meta
|
|
22
28
|
from .manager import (
|
|
23
29
|
ArtifactManager,
|
mlrun/artifacts/base.py
CHANGED
|
@@ -191,12 +191,30 @@ class Artifact(ModelObj):
|
|
|
191
191
|
format=None,
|
|
192
192
|
size=None,
|
|
193
193
|
target_path=None,
|
|
194
|
-
# All params up until here are legacy params for compatibility with legacy artifacts.
|
|
195
194
|
project=None,
|
|
195
|
+
src_path: str = None,
|
|
196
|
+
# All params up until here are legacy params for compatibility with legacy artifacts.
|
|
197
|
+
# TODO: remove them in 1.9.0.
|
|
196
198
|
metadata: ArtifactMetadata = None,
|
|
197
199
|
spec: ArtifactSpec = None,
|
|
198
|
-
src_path: str = None,
|
|
199
200
|
):
|
|
201
|
+
if (
|
|
202
|
+
key
|
|
203
|
+
or body
|
|
204
|
+
or viewer
|
|
205
|
+
or is_inline
|
|
206
|
+
or format
|
|
207
|
+
or size
|
|
208
|
+
or target_path
|
|
209
|
+
or project
|
|
210
|
+
or src_path
|
|
211
|
+
):
|
|
212
|
+
warnings.warn(
|
|
213
|
+
"Artifact constructor parameters are deprecated and will be removed in 1.9.0. "
|
|
214
|
+
"Use the metadata and spec parameters instead.",
|
|
215
|
+
DeprecationWarning,
|
|
216
|
+
)
|
|
217
|
+
|
|
200
218
|
self._metadata = None
|
|
201
219
|
self.metadata = metadata
|
|
202
220
|
self._spec = None
|
|
@@ -698,11 +716,18 @@ class LinkArtifact(Artifact):
|
|
|
698
716
|
link_iteration=None,
|
|
699
717
|
link_key=None,
|
|
700
718
|
link_tree=None,
|
|
701
|
-
# All params up until here are legacy params for compatibility with legacy artifacts.
|
|
702
719
|
project=None,
|
|
720
|
+
# All params up until here are legacy params for compatibility with legacy artifacts.
|
|
721
|
+
# TODO: remove them in 1.9.0.
|
|
703
722
|
metadata: ArtifactMetadata = None,
|
|
704
723
|
spec: LinkArtifactSpec = None,
|
|
705
724
|
):
|
|
725
|
+
if key or target_path or link_iteration or link_key or link_tree or project:
|
|
726
|
+
warnings.warn(
|
|
727
|
+
"Artifact constructor parameters are deprecated and will be removed in 1.9.0. "
|
|
728
|
+
"Use the metadata and spec parameters instead.",
|
|
729
|
+
DeprecationWarning,
|
|
730
|
+
)
|
|
706
731
|
super().__init__(
|
|
707
732
|
key, target_path=target_path, project=project, metadata=metadata, spec=spec
|
|
708
733
|
)
|
mlrun/artifacts/dataset.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import os
|
|
15
15
|
import pathlib
|
|
16
|
+
import warnings
|
|
16
17
|
from io import StringIO
|
|
17
18
|
from typing import Optional
|
|
18
19
|
|
|
@@ -160,6 +161,13 @@ class DatasetArtifact(Artifact):
|
|
|
160
161
|
label_column: str = None,
|
|
161
162
|
**kwargs,
|
|
162
163
|
):
|
|
164
|
+
if key or format or target_path:
|
|
165
|
+
warnings.warn(
|
|
166
|
+
"Artifact constructor parameters are deprecated and will be removed in 1.9.0. "
|
|
167
|
+
"Use the metadata and spec parameters instead.",
|
|
168
|
+
DeprecationWarning,
|
|
169
|
+
)
|
|
170
|
+
|
|
163
171
|
format = (format or "").lower()
|
|
164
172
|
super().__init__(key, None, format=format, target_path=target_path)
|
|
165
173
|
if format and format not in self.SUPPORTED_FORMATS:
|
mlrun/artifacts/manager.py
CHANGED
|
@@ -16,6 +16,7 @@ import typing
|
|
|
16
16
|
from os.path import exists, isdir
|
|
17
17
|
from urllib.parse import urlparse
|
|
18
18
|
|
|
19
|
+
import mlrun.common.schemas.artifact
|
|
19
20
|
import mlrun.config
|
|
20
21
|
from mlrun.utils.helpers import (
|
|
21
22
|
get_local_file_schema,
|
|
@@ -343,6 +344,23 @@ class ArtifactManager:
|
|
|
343
344
|
project=project,
|
|
344
345
|
)
|
|
345
346
|
|
|
347
|
+
def delete_artifact(
|
|
348
|
+
self,
|
|
349
|
+
item: Artifact,
|
|
350
|
+
deletion_strategy: mlrun.common.schemas.artifact.ArtifactsDeletionStrategies = (
|
|
351
|
+
mlrun.common.schemas.artifact.ArtifactsDeletionStrategies.metadata_only
|
|
352
|
+
),
|
|
353
|
+
secrets: dict = None,
|
|
354
|
+
):
|
|
355
|
+
self.artifact_db.del_artifact(
|
|
356
|
+
key=item.db_key,
|
|
357
|
+
project=item.project,
|
|
358
|
+
tag=item.tag,
|
|
359
|
+
tree=item.tree,
|
|
360
|
+
deletion_strategy=deletion_strategy,
|
|
361
|
+
secrets=secrets,
|
|
362
|
+
)
|
|
363
|
+
|
|
346
364
|
|
|
347
365
|
def extend_artifact_path(artifact_path: str, default_artifact_path: str):
|
|
348
366
|
artifact_path = str(artifact_path or "")
|
mlrun/artifacts/model.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import tempfile
|
|
16
|
+
import warnings
|
|
16
17
|
from os import path
|
|
17
18
|
from typing import Any, Optional
|
|
18
19
|
|
|
@@ -148,6 +149,12 @@ class ModelArtifact(Artifact):
|
|
|
148
149
|
model_dir=None,
|
|
149
150
|
**kwargs,
|
|
150
151
|
):
|
|
152
|
+
if key or body or format or target_path:
|
|
153
|
+
warnings.warn(
|
|
154
|
+
"Artifact constructor parameters are deprecated and will be removed in 1.9.0. "
|
|
155
|
+
"Use the metadata and spec parameters instead.",
|
|
156
|
+
DeprecationWarning,
|
|
157
|
+
)
|
|
151
158
|
super().__init__(key, body, format=format, target_path=target_path, **kwargs)
|
|
152
159
|
model_file = str(model_file or "")
|
|
153
160
|
if model_file and "/" in model_file:
|
|
@@ -502,7 +509,7 @@ def _get_extra(target, extra_data, is_dir=False):
|
|
|
502
509
|
def _remove_tag_from_spec_yaml(model_spec):
|
|
503
510
|
spec_dict = model_spec.to_dict()
|
|
504
511
|
spec_dict["metadata"].pop("tag", None)
|
|
505
|
-
return yaml.
|
|
512
|
+
return yaml.safe_dump(spec_dict)
|
|
506
513
|
|
|
507
514
|
|
|
508
515
|
def update_model(
|
mlrun/artifacts/plots.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import base64
|
|
15
15
|
import typing
|
|
16
|
+
import warnings
|
|
16
17
|
from io import BytesIO
|
|
17
18
|
|
|
18
19
|
import mlrun
|
|
@@ -34,6 +35,12 @@ class PlotArtifact(Artifact):
|
|
|
34
35
|
def __init__(
|
|
35
36
|
self, key=None, body=None, is_inline=False, target_path=None, title=None
|
|
36
37
|
):
|
|
38
|
+
if key or body or is_inline or target_path:
|
|
39
|
+
warnings.warn(
|
|
40
|
+
"Artifact constructor parameters are deprecated and will be removed in 1.9.0. "
|
|
41
|
+
"Use the metadata and spec parameters instead.",
|
|
42
|
+
DeprecationWarning,
|
|
43
|
+
)
|
|
37
44
|
super().__init__(key, body, format="html", target_path=target_path)
|
|
38
45
|
self.metadata.description = title
|
|
39
46
|
|
|
@@ -87,6 +94,12 @@ class PlotlyArtifact(Artifact):
|
|
|
87
94
|
:param key: Key for the artifact to be stored in the database.
|
|
88
95
|
:param target_path: Path to save the artifact.
|
|
89
96
|
"""
|
|
97
|
+
if key or target_path:
|
|
98
|
+
warnings.warn(
|
|
99
|
+
"Artifact constructor parameters are deprecated and will be removed in 1.9.0. "
|
|
100
|
+
"Use the metadata and spec parameters instead.",
|
|
101
|
+
DeprecationWarning,
|
|
102
|
+
)
|
|
90
103
|
# Validate the plotly package:
|
|
91
104
|
try:
|
|
92
105
|
from plotly.graph_objs import Figure
|
mlrun/common/schemas/__init__.py
CHANGED
|
@@ -14,7 +14,13 @@
|
|
|
14
14
|
#
|
|
15
15
|
# flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
|
|
16
16
|
|
|
17
|
-
from .alert import
|
|
17
|
+
from .alert import (
|
|
18
|
+
AlertActiveState,
|
|
19
|
+
AlertConfig,
|
|
20
|
+
AlertNotification,
|
|
21
|
+
AlertTemplate,
|
|
22
|
+
Event,
|
|
23
|
+
)
|
|
18
24
|
from .api_gateway import (
|
|
19
25
|
APIGateway,
|
|
20
26
|
APIGatewayAuthenticationMode,
|
|
@@ -142,8 +148,10 @@ from .model_monitoring import (
|
|
|
142
148
|
ModelMonitoringMode,
|
|
143
149
|
ModelMonitoringStoreKinds,
|
|
144
150
|
MonitoringFunctionNames,
|
|
151
|
+
MonitoringTSDBTables,
|
|
145
152
|
PrometheusEndpoints,
|
|
146
|
-
|
|
153
|
+
TimeSeriesConnector,
|
|
154
|
+
TSDBTarget,
|
|
147
155
|
)
|
|
148
156
|
from .notification import (
|
|
149
157
|
Notification,
|
mlrun/common/schemas/alert.py
CHANGED
|
@@ -26,10 +26,10 @@ class EventEntityKind(StrEnum):
|
|
|
26
26
|
JOB = "job"
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class
|
|
29
|
+
class EventEntities(pydantic.BaseModel):
|
|
30
30
|
kind: EventEntityKind
|
|
31
31
|
project: str
|
|
32
|
-
|
|
32
|
+
ids: pydantic.conlist(str, min_items=1, max_items=1)
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class EventKind(StrEnum):
|
|
@@ -48,7 +48,7 @@ _event_kind_entity_map = {
|
|
|
48
48
|
class Event(pydantic.BaseModel):
|
|
49
49
|
kind: EventKind
|
|
50
50
|
timestamp: Union[str, datetime] = None # occurrence time
|
|
51
|
-
entity:
|
|
51
|
+
entity: EventEntities
|
|
52
52
|
value_dict: Optional[dict] = pydantic.Field(default_factory=dict)
|
|
53
53
|
|
|
54
54
|
def is_valid(self):
|
|
@@ -71,6 +71,12 @@ class AlertTrigger(pydantic.BaseModel):
|
|
|
71
71
|
events: list[EventKind] = []
|
|
72
72
|
prometheus_alert: str = None
|
|
73
73
|
|
|
74
|
+
def __eq__(self, other):
|
|
75
|
+
return (
|
|
76
|
+
self.prometheus_alert == other.prometheus_alert
|
|
77
|
+
and self.events == other.events
|
|
78
|
+
)
|
|
79
|
+
|
|
74
80
|
|
|
75
81
|
class AlertCriteria(pydantic.BaseModel):
|
|
76
82
|
count: Annotated[
|
|
@@ -86,12 +92,27 @@ class AlertCriteria(pydantic.BaseModel):
|
|
|
86
92
|
),
|
|
87
93
|
] = None
|
|
88
94
|
|
|
95
|
+
def __eq__(self, other):
|
|
96
|
+
return self.count == other.count and self.period == other.period
|
|
97
|
+
|
|
89
98
|
|
|
90
99
|
class ResetPolicy(StrEnum):
|
|
91
100
|
MANUAL = "manual"
|
|
92
101
|
AUTO = "auto"
|
|
93
102
|
|
|
94
103
|
|
|
104
|
+
class AlertNotification(pydantic.BaseModel):
|
|
105
|
+
notification: Notification
|
|
106
|
+
cooldown_period: Annotated[
|
|
107
|
+
str,
|
|
108
|
+
pydantic.Field(
|
|
109
|
+
description="Period during which notifications "
|
|
110
|
+
"will not be sent after initial send. The format of this would be in time."
|
|
111
|
+
" e.g. 1d, 3h, 5m, 15s"
|
|
112
|
+
),
|
|
113
|
+
] = None
|
|
114
|
+
|
|
115
|
+
|
|
95
116
|
class AlertConfig(pydantic.BaseModel):
|
|
96
117
|
project: str
|
|
97
118
|
id: int = None
|
|
@@ -108,15 +129,53 @@ class AlertConfig(pydantic.BaseModel):
|
|
|
108
129
|
]
|
|
109
130
|
created: Union[str, datetime] = None
|
|
110
131
|
severity: AlertSeverity
|
|
111
|
-
|
|
132
|
+
entities: EventEntities
|
|
112
133
|
trigger: AlertTrigger
|
|
113
134
|
criteria: Optional[AlertCriteria]
|
|
114
135
|
reset_policy: ResetPolicy = ResetPolicy.MANUAL
|
|
115
|
-
notifications: pydantic.conlist(
|
|
136
|
+
notifications: pydantic.conlist(AlertNotification, min_items=1)
|
|
116
137
|
state: AlertActiveState = AlertActiveState.INACTIVE
|
|
117
138
|
count: Optional[int] = 0
|
|
118
139
|
|
|
140
|
+
def get_raw_notifications(self) -> list[Notification]:
|
|
141
|
+
return [
|
|
142
|
+
alert_notification.notification for alert_notification in self.notifications
|
|
143
|
+
]
|
|
144
|
+
|
|
119
145
|
|
|
120
146
|
class AlertsModes(StrEnum):
|
|
121
147
|
enabled = "enabled"
|
|
122
148
|
disabled = "disabled"
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class AlertTemplate(
|
|
152
|
+
pydantic.BaseModel
|
|
153
|
+
): # Template fields that are not shared with created configs
|
|
154
|
+
template_id: int = None
|
|
155
|
+
template_name: str
|
|
156
|
+
template_description: Optional[str] = (
|
|
157
|
+
"String explaining the purpose of this template"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# A property that identifies templates that were created by the system and cannot be modified/deleted by the user
|
|
161
|
+
system_generated: bool = False
|
|
162
|
+
|
|
163
|
+
# AlertConfig fields that are pre-defined
|
|
164
|
+
description: Optional[str] = (
|
|
165
|
+
"String to be sent in the generated notifications e.g. 'Model {{ $project }}/{{ $entity }} is drifting.'"
|
|
166
|
+
)
|
|
167
|
+
severity: AlertSeverity
|
|
168
|
+
trigger: AlertTrigger
|
|
169
|
+
criteria: Optional[AlertCriteria]
|
|
170
|
+
reset_policy: ResetPolicy = ResetPolicy.MANUAL
|
|
171
|
+
|
|
172
|
+
# This is slightly different than __eq__ as it doesn't compare everything
|
|
173
|
+
def templates_differ(self, other):
|
|
174
|
+
return (
|
|
175
|
+
self.template_description != other.template_description
|
|
176
|
+
or self.description != other.description
|
|
177
|
+
or self.severity != other.severity
|
|
178
|
+
or self.trigger != other.trigger
|
|
179
|
+
or self.reset_policy != other.reset_policy
|
|
180
|
+
or self.criteria != other.criteria
|
|
181
|
+
)
|
|
@@ -23,6 +23,7 @@ import mlrun.common.types
|
|
|
23
23
|
class APIGatewayAuthenticationMode(mlrun.common.types.StrEnum):
|
|
24
24
|
basic = "basicAuth"
|
|
25
25
|
none = "none"
|
|
26
|
+
access_key = "accessKey"
|
|
26
27
|
|
|
27
28
|
@classmethod
|
|
28
29
|
def from_str(cls, authentication_mode: str):
|
|
@@ -30,6 +31,8 @@ class APIGatewayAuthenticationMode(mlrun.common.types.StrEnum):
|
|
|
30
31
|
return cls.none
|
|
31
32
|
elif authentication_mode == "basicAuth":
|
|
32
33
|
return cls.basic
|
|
34
|
+
elif authentication_mode == "accessKey":
|
|
35
|
+
return cls.access_key
|
|
33
36
|
else:
|
|
34
37
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
35
38
|
f"Authentication mode `{authentication_mode}` is not supported",
|
|
@@ -63,6 +66,7 @@ class APIGatewayUpstream(_APIGatewayBaseModel):
|
|
|
63
66
|
kind: Optional[str] = "nucliofunction"
|
|
64
67
|
nucliofunction: dict[str, str]
|
|
65
68
|
percentage: Optional[int] = 0
|
|
69
|
+
port: Optional[int] = 0
|
|
66
70
|
|
|
67
71
|
|
|
68
72
|
class APIGatewaySpec(_APIGatewayBaseModel):
|
mlrun/common/schemas/artifact.py
CHANGED
|
@@ -93,3 +93,18 @@ class Artifact(pydantic.BaseModel):
|
|
|
93
93
|
metadata: ArtifactMetadata
|
|
94
94
|
spec: ArtifactSpec
|
|
95
95
|
status: ObjectStatus
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class ArtifactsDeletionStrategies(mlrun.common.types.StrEnum):
|
|
99
|
+
"""Artifacts deletion strategies types."""
|
|
100
|
+
|
|
101
|
+
metadata_only = "metadata-only"
|
|
102
|
+
"""Only removes the artifact db record, leaving all related artifact data in-place"""
|
|
103
|
+
|
|
104
|
+
data_optional = "data-optional"
|
|
105
|
+
"""Delete the artifact data of the artifact as a best-effort.
|
|
106
|
+
If artifact data deletion fails still try to delete the artifact db record"""
|
|
107
|
+
|
|
108
|
+
data_force = "data-force"
|
|
109
|
+
"""Delete the artifact data, and if cannot delete it fail the deletion
|
|
110
|
+
and don’t delete the artifact db record"""
|
mlrun/common/schemas/auth.py
CHANGED
|
@@ -59,6 +59,7 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
|
|
|
59
59
|
hub_source = "hub-source"
|
|
60
60
|
workflow = "workflow"
|
|
61
61
|
alert = "alert"
|
|
62
|
+
alert_templates = "alert-templates"
|
|
62
63
|
event = "event"
|
|
63
64
|
datastore_profile = "datastore-profile"
|
|
64
65
|
api_gateway = "api-gateway"
|
|
@@ -87,6 +88,7 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
|
|
|
87
88
|
AuthorizationResourceTypes.run: "/projects/{project_name}/runs/{resource_name}",
|
|
88
89
|
AuthorizationResourceTypes.event: "/projects/{project_name}/events/{resource_name}",
|
|
89
90
|
AuthorizationResourceTypes.alert: "/projects/{project_name}/alerts/{resource_name}",
|
|
91
|
+
AuthorizationResourceTypes.alert_templates: "/alert-templates/{resource_name}",
|
|
90
92
|
# runtime resource doesn't have an identifier, we don't need any auth granularity behind project level
|
|
91
93
|
AuthorizationResourceTypes.runtime_resource: "/projects/{project_name}/runtime-resources",
|
|
92
94
|
AuthorizationResourceTypes.model_endpoint: "/projects/{project_name}/model-endpoints/{resource_name}",
|
|
@@ -30,14 +30,17 @@ from .constants import (
|
|
|
30
30
|
ModelMonitoringMode,
|
|
31
31
|
ModelMonitoringStoreKinds,
|
|
32
32
|
MonitoringFunctionNames,
|
|
33
|
+
MonitoringTSDBTables,
|
|
33
34
|
ProjectSecretKeys,
|
|
34
35
|
PrometheusEndpoints,
|
|
35
36
|
PrometheusMetric,
|
|
36
37
|
ResultData,
|
|
37
38
|
SchedulingKeys,
|
|
38
|
-
|
|
39
|
+
TimeSeriesConnector,
|
|
40
|
+
TSDBTarget,
|
|
39
41
|
VersionedModel,
|
|
40
42
|
WriterEvent,
|
|
43
|
+
WriterEventKind,
|
|
41
44
|
)
|
|
42
45
|
from .grafana import (
|
|
43
46
|
GrafanaColumn,
|