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.

Files changed (77) hide show
  1. mlrun/__init__.py +10 -1
  2. mlrun/__main__.py +18 -4
  3. mlrun/alerts/__init__.py +15 -0
  4. mlrun/alerts/alert.py +144 -0
  5. mlrun/artifacts/__init__.py +7 -1
  6. mlrun/artifacts/base.py +28 -3
  7. mlrun/artifacts/dataset.py +8 -0
  8. mlrun/artifacts/manager.py +18 -0
  9. mlrun/artifacts/model.py +8 -1
  10. mlrun/artifacts/plots.py +13 -0
  11. mlrun/common/schemas/__init__.py +10 -2
  12. mlrun/common/schemas/alert.py +64 -5
  13. mlrun/common/schemas/api_gateway.py +4 -0
  14. mlrun/common/schemas/artifact.py +15 -0
  15. mlrun/common/schemas/auth.py +2 -0
  16. mlrun/common/schemas/model_monitoring/__init__.py +4 -1
  17. mlrun/common/schemas/model_monitoring/constants.py +17 -1
  18. mlrun/common/schemas/model_monitoring/model_endpoints.py +60 -1
  19. mlrun/common/schemas/project.py +5 -1
  20. mlrun/config.py +11 -4
  21. mlrun/datastore/datastore_profile.py +10 -7
  22. mlrun/db/base.py +24 -4
  23. mlrun/db/httpdb.py +97 -43
  24. mlrun/db/nopdb.py +25 -4
  25. mlrun/errors.py +5 -0
  26. mlrun/launcher/base.py +3 -2
  27. mlrun/lists.py +4 -0
  28. mlrun/model.py +15 -8
  29. mlrun/model_monitoring/__init__.py +1 -1
  30. mlrun/model_monitoring/applications/_application_steps.py +1 -2
  31. mlrun/model_monitoring/applications/context.py +1 -1
  32. mlrun/model_monitoring/applications/histogram_data_drift.py +64 -38
  33. mlrun/model_monitoring/db/__init__.py +2 -0
  34. mlrun/model_monitoring/db/stores/base/store.py +9 -36
  35. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +63 -110
  36. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +56 -202
  37. mlrun/model_monitoring/db/tsdb/__init__.py +71 -0
  38. mlrun/model_monitoring/db/tsdb/base.py +135 -0
  39. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  40. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
  41. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +442 -0
  42. mlrun/model_monitoring/db/v3io_tsdb_reader.py +134 -0
  43. mlrun/model_monitoring/stream_processing.py +46 -210
  44. mlrun/model_monitoring/writer.py +50 -100
  45. mlrun/platforms/__init__.py +10 -9
  46. mlrun/platforms/iguazio.py +19 -200
  47. mlrun/projects/operations.py +11 -7
  48. mlrun/projects/pipelines.py +13 -76
  49. mlrun/projects/project.py +62 -17
  50. mlrun/render.py +9 -3
  51. mlrun/run.py +5 -38
  52. mlrun/runtimes/__init__.py +1 -0
  53. mlrun/runtimes/base.py +3 -3
  54. mlrun/runtimes/kubejob.py +2 -1
  55. mlrun/runtimes/nuclio/api_gateway.py +163 -77
  56. mlrun/runtimes/nuclio/application/application.py +160 -7
  57. mlrun/runtimes/nuclio/function.py +25 -45
  58. mlrun/runtimes/pod.py +16 -36
  59. mlrun/runtimes/remotesparkjob.py +1 -1
  60. mlrun/runtimes/sparkjob/spark3job.py +1 -1
  61. mlrun/runtimes/utils.py +0 -38
  62. mlrun/track/tracker.py +2 -1
  63. mlrun/utils/helpers.py +51 -31
  64. mlrun/utils/logger.py +11 -6
  65. mlrun/utils/notifications/notification/base.py +1 -1
  66. mlrun/utils/notifications/notification/slack.py +9 -4
  67. mlrun/utils/notifications/notification/webhook.py +1 -1
  68. mlrun/utils/notifications/notification_pusher.py +21 -14
  69. mlrun/utils/version/version.json +2 -2
  70. {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/METADATA +4 -3
  71. {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/RECORD +75 -69
  72. mlrun/kfpops.py +0 -860
  73. mlrun/platforms/other.py +0 -305
  74. {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/LICENSE +0 -0
  75. {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/WHEEL +0 -0
  76. {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/entry_points.txt +0 -0
  77. {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("/tmp/state", "w") as fp:
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("/tmp/image", "w") as fp:
594
+ with open(image_file_path, "w") as fp:
581
595
  fp.write(image)
582
- with open("/tmp/fullimage", "w") as fp:
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
 
@@ -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
@@ -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 Artifact, ArtifactMetadata, ArtifactSpec, get_artifact_meta
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
  )
@@ -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:
@@ -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.dump(spec_dict)
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
@@ -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 AlertActiveState, AlertConfig, Event
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
- TimeSeriesTarget,
153
+ TimeSeriesConnector,
154
+ TSDBTarget,
147
155
  )
148
156
  from .notification import (
149
157
  Notification,
@@ -26,10 +26,10 @@ class EventEntityKind(StrEnum):
26
26
  JOB = "job"
27
27
 
28
28
 
29
- class EventEntity(pydantic.BaseModel):
29
+ class EventEntities(pydantic.BaseModel):
30
30
  kind: EventEntityKind
31
31
  project: str
32
- id: str
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: EventEntity
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
- entity: EventEntity
132
+ entities: EventEntities
112
133
  trigger: AlertTrigger
113
134
  criteria: Optional[AlertCriteria]
114
135
  reset_policy: ResetPolicy = ResetPolicy.MANUAL
115
- notifications: pydantic.conlist(Notification, min_items=1)
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):
@@ -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"""
@@ -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
- TimeSeriesTarget,
39
+ TimeSeriesConnector,
40
+ TSDBTarget,
39
41
  VersionedModel,
40
42
  WriterEvent,
43
+ WriterEventKind,
41
44
  )
42
45
  from .grafana import (
43
46
  GrafanaColumn,