mlrun 1.10.0rc25__py3-none-any.whl → 1.10.0rc27__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/artifacts/llm_prompt.py +8 -1
- mlrun/common/model_monitoring/helpers.py +86 -0
- mlrun/common/schemas/hub.py +11 -18
- mlrun/config.py +2 -3
- mlrun/datastore/__init__.py +2 -2
- mlrun/datastore/datastore_profile.py +27 -3
- mlrun/datastore/model_provider/huggingface_provider.py +5 -1
- mlrun/datastore/model_provider/model_provider.py +1 -1
- mlrun/datastore/s3.py +24 -2
- mlrun/datastore/storeytargets.py +2 -3
- mlrun/db/base.py +14 -0
- mlrun/db/httpdb.py +11 -2
- mlrun/db/nopdb.py +13 -0
- mlrun/k8s_utils.py +0 -14
- mlrun/model_monitoring/applications/base.py +20 -3
- mlrun/model_monitoring/controller.py +5 -3
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +3 -1
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +17 -4
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +3 -0
- mlrun/model_monitoring/helpers.py +5 -5
- mlrun/projects/pipelines.py +2 -2
- mlrun/projects/project.py +5 -5
- mlrun/run.py +12 -1
- mlrun/runtimes/base.py +0 -3
- mlrun/runtimes/mounts.py +15 -2
- mlrun/runtimes/nuclio/function.py +35 -26
- mlrun/runtimes/pod.py +153 -11
- mlrun/serving/routers.py +23 -41
- mlrun/serving/server.py +1 -0
- mlrun/serving/states.py +3 -3
- mlrun/serving/system_steps.py +52 -29
- mlrun/serving/v2_serving.py +9 -10
- mlrun/utils/helpers.py +10 -13
- mlrun/utils/notifications/notification/base.py +18 -0
- mlrun/utils/notifications/notification/git.py +2 -4
- mlrun/utils/notifications/notification/slack.py +2 -4
- mlrun/utils/notifications/notification/webhook.py +2 -5
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.10.0rc25.dist-info → mlrun-1.10.0rc27.dist-info}/METADATA +22 -26
- {mlrun-1.10.0rc25.dist-info → mlrun-1.10.0rc27.dist-info}/RECORD +44 -44
- {mlrun-1.10.0rc25.dist-info → mlrun-1.10.0rc27.dist-info}/WHEEL +0 -0
- {mlrun-1.10.0rc25.dist-info → mlrun-1.10.0rc27.dist-info}/entry_points.txt +0 -0
- {mlrun-1.10.0rc25.dist-info → mlrun-1.10.0rc27.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.10.0rc25.dist-info → mlrun-1.10.0rc27.dist-info}/top_level.txt +0 -0
mlrun/artifacts/llm_prompt.py
CHANGED
|
@@ -62,12 +62,19 @@ class LLMPromptArtifactSpec(ArtifactSpec):
|
|
|
62
62
|
parent_uri=model_artifact.uri
|
|
63
63
|
if isinstance(model_artifact, model_art.ModelArtifact)
|
|
64
64
|
else model_artifact,
|
|
65
|
+
format=kwargs.pop("format", "") or "json",
|
|
65
66
|
**kwargs,
|
|
66
67
|
)
|
|
67
68
|
|
|
68
69
|
self.prompt_template = prompt_template
|
|
69
70
|
self.prompt_legend = prompt_legend
|
|
70
|
-
|
|
71
|
+
if model_configuration is not None and not isinstance(
|
|
72
|
+
model_configuration, dict
|
|
73
|
+
):
|
|
74
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
75
|
+
"LLMPromptArtifact model_configuration must be a dictionary or None"
|
|
76
|
+
)
|
|
77
|
+
self.model_configuration = model_configuration or {}
|
|
71
78
|
self.description = description
|
|
72
79
|
self._model_artifact = (
|
|
73
80
|
model_artifact
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import sys
|
|
16
16
|
import typing
|
|
17
|
+
from datetime import datetime
|
|
17
18
|
|
|
18
19
|
import mlrun.common
|
|
19
20
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
@@ -24,6 +25,7 @@ BinCounts = typing.NewType("BinCounts", list[int])
|
|
|
24
25
|
BinEdges = typing.NewType("BinEdges", list[float])
|
|
25
26
|
|
|
26
27
|
_MAX_FLOAT = sys.float_info.max
|
|
28
|
+
logger = mlrun.utils.create_logger(level="info", name="mm_helpers")
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
def parse_model_endpoint_project_prefix(path: str, project_name: str):
|
|
@@ -87,3 +89,87 @@ def pad_features_hist(feature_stats: FeatureStats) -> None:
|
|
|
87
89
|
for feature in feature_stats.values():
|
|
88
90
|
if hist_key in feature:
|
|
89
91
|
pad_hist(Histogram(feature[hist_key]))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_model_endpoints_creation_task_status(
|
|
95
|
+
server,
|
|
96
|
+
) -> tuple[
|
|
97
|
+
mlrun.common.schemas.BackgroundTaskState,
|
|
98
|
+
typing.Optional[datetime],
|
|
99
|
+
typing.Optional[set[str]],
|
|
100
|
+
]:
|
|
101
|
+
background_task = None
|
|
102
|
+
background_task_state = mlrun.common.schemas.BackgroundTaskState.running
|
|
103
|
+
background_task_check_timestamp = None
|
|
104
|
+
model_endpoint_uids = None
|
|
105
|
+
try:
|
|
106
|
+
background_task = mlrun.get_run_db().get_project_background_task(
|
|
107
|
+
server.project, server.model_endpoint_creation_task_name
|
|
108
|
+
)
|
|
109
|
+
background_task_check_timestamp = mlrun.utils.now_date()
|
|
110
|
+
log_background_task_state(
|
|
111
|
+
server, background_task.status.state, background_task_check_timestamp
|
|
112
|
+
)
|
|
113
|
+
background_task_state = background_task.status.state
|
|
114
|
+
except mlrun.errors.MLRunNotFoundError:
|
|
115
|
+
logger.warning(
|
|
116
|
+
"Model endpoint creation task not found listing model endpoints",
|
|
117
|
+
project=server.project,
|
|
118
|
+
task_name=server.model_endpoint_creation_task_name,
|
|
119
|
+
)
|
|
120
|
+
if background_task is None:
|
|
121
|
+
model_endpoints = mlrun.get_run_db().list_model_endpoints(
|
|
122
|
+
project=server.project,
|
|
123
|
+
function_name=server.function_name,
|
|
124
|
+
function_tag=server.function_tag,
|
|
125
|
+
tsdb_metrics=False,
|
|
126
|
+
)
|
|
127
|
+
if model_endpoints:
|
|
128
|
+
model_endpoint_uids = {
|
|
129
|
+
endpoint.metadata.uid for endpoint in model_endpoints.endpoints
|
|
130
|
+
}
|
|
131
|
+
logger.info(
|
|
132
|
+
"Model endpoints found after background task not found, model monitoring will monitor "
|
|
133
|
+
"events",
|
|
134
|
+
project=server.project,
|
|
135
|
+
function_name=server.function_name,
|
|
136
|
+
function_tag=server.function_tag,
|
|
137
|
+
uids=model_endpoint_uids,
|
|
138
|
+
)
|
|
139
|
+
background_task_state = mlrun.common.schemas.BackgroundTaskState.succeeded
|
|
140
|
+
else:
|
|
141
|
+
logger.warning(
|
|
142
|
+
"Model endpoints not found after background task not found, model monitoring will not "
|
|
143
|
+
"monitor events",
|
|
144
|
+
project=server.project,
|
|
145
|
+
function_name=server.function_name,
|
|
146
|
+
function_tag=server.function_tag,
|
|
147
|
+
)
|
|
148
|
+
background_task_state = mlrun.common.schemas.BackgroundTaskState.failed
|
|
149
|
+
return background_task_state, background_task_check_timestamp, model_endpoint_uids
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def log_background_task_state(
|
|
153
|
+
server,
|
|
154
|
+
background_task_state: mlrun.common.schemas.BackgroundTaskState,
|
|
155
|
+
background_task_check_timestamp: typing.Optional[datetime],
|
|
156
|
+
):
|
|
157
|
+
logger.info(
|
|
158
|
+
"Checking model endpoint creation task status",
|
|
159
|
+
task_name=server.model_endpoint_creation_task_name,
|
|
160
|
+
)
|
|
161
|
+
if (
|
|
162
|
+
background_task_state
|
|
163
|
+
in mlrun.common.schemas.BackgroundTaskState.terminal_states()
|
|
164
|
+
):
|
|
165
|
+
logger.info(
|
|
166
|
+
f"Model endpoint creation task completed with state {background_task_state}"
|
|
167
|
+
)
|
|
168
|
+
else: # in progress
|
|
169
|
+
logger.info(
|
|
170
|
+
f"Model endpoint creation task is still in progress with the current state: "
|
|
171
|
+
f"{background_task_state}. Events will not be monitored for the next "
|
|
172
|
+
f"{mlrun.mlconf.model_endpoint_monitoring.model_endpoint_creation_check_period} seconds",
|
|
173
|
+
function_name=server.function.name,
|
|
174
|
+
background_task_check_timestamp=background_task_check_timestamp.isoformat(),
|
|
175
|
+
)
|
mlrun/common/schemas/hub.py
CHANGED
|
@@ -37,9 +37,9 @@ class HubObjectMetadata(BaseModel):
|
|
|
37
37
|
extra = Extra.allow
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
# Currently only functions are supported. Will add more in the future.
|
|
41
40
|
class HubSourceType(mlrun.common.types.StrEnum):
|
|
42
41
|
functions = "functions"
|
|
42
|
+
modules = "modules"
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
# Sources-related objects
|
|
@@ -47,7 +47,6 @@ class HubSourceSpec(ObjectSpec):
|
|
|
47
47
|
path: str # URL to base directory, should include schema (s3://, etc...)
|
|
48
48
|
channel: str
|
|
49
49
|
credentials: Optional[dict] = {}
|
|
50
|
-
object_type: HubSourceType = Field(HubSourceType.functions, const=True)
|
|
51
50
|
|
|
52
51
|
|
|
53
52
|
class HubSource(BaseModel):
|
|
@@ -56,11 +55,11 @@ class HubSource(BaseModel):
|
|
|
56
55
|
spec: HubSourceSpec
|
|
57
56
|
status: Optional[ObjectStatus] = ObjectStatus(state="created")
|
|
58
57
|
|
|
59
|
-
def get_full_uri(self, relative_path):
|
|
60
|
-
return f"{self.spec.path}/{
|
|
58
|
+
def get_full_uri(self, relative_path, object_type):
|
|
59
|
+
return f"{self.spec.path}/{object_type}/{self.spec.channel}/{relative_path}"
|
|
61
60
|
|
|
62
|
-
def get_catalog_uri(self):
|
|
63
|
-
return self.get_full_uri(mlrun.mlconf.hub.catalog_filename)
|
|
61
|
+
def get_catalog_uri(self, object_type):
|
|
62
|
+
return self.get_full_uri(mlrun.mlconf.hub.catalog_filename, object_type)
|
|
64
63
|
|
|
65
64
|
@classmethod
|
|
66
65
|
def generate_default_source(cls):
|
|
@@ -79,7 +78,6 @@ class HubSource(BaseModel):
|
|
|
79
78
|
spec=HubSourceSpec(
|
|
80
79
|
path=mlrun.mlconf.hub.default_source.url,
|
|
81
80
|
channel=mlrun.mlconf.hub.default_source.channel,
|
|
82
|
-
object_type=HubSourceType(mlrun.mlconf.hub.default_source.object_type),
|
|
83
81
|
),
|
|
84
82
|
status=ObjectStatus(state="created"),
|
|
85
83
|
)
|
|
@@ -108,21 +106,16 @@ class IndexedHubSource(BaseModel):
|
|
|
108
106
|
|
|
109
107
|
# Item-related objects
|
|
110
108
|
class HubItemMetadata(HubObjectMetadata):
|
|
111
|
-
source: HubSourceType =
|
|
109
|
+
source: HubSourceType = HubSourceType.functions
|
|
112
110
|
version: str
|
|
113
111
|
tag: Optional[str]
|
|
114
112
|
|
|
115
113
|
def get_relative_path(self) -> str:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return f"{modified_name}/{version}/"
|
|
122
|
-
else:
|
|
123
|
-
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
124
|
-
f"Bad source for hub item - {self.source}"
|
|
125
|
-
)
|
|
114
|
+
# This is needed since the hub deployment script modifies the paths to use _ instead of -.
|
|
115
|
+
modified_name = self.name.replace("-", "_")
|
|
116
|
+
# Prefer using the tag if exists. Otherwise, use version.
|
|
117
|
+
version = self.tag or self.version
|
|
118
|
+
return f"{modified_name}/{version}/"
|
|
126
119
|
|
|
127
120
|
|
|
128
121
|
class HubItemSpec(ObjectSpec):
|
mlrun/config.py
CHANGED
|
@@ -718,7 +718,6 @@ default_config = {
|
|
|
718
718
|
"name": "default",
|
|
719
719
|
"description": "MLRun global function hub",
|
|
720
720
|
"url": "https://mlrun.github.io/marketplace",
|
|
721
|
-
"object_type": "functions",
|
|
722
721
|
"channel": "master",
|
|
723
722
|
},
|
|
724
723
|
},
|
|
@@ -1000,9 +999,9 @@ class Config:
|
|
|
1000
999
|
)
|
|
1001
1000
|
|
|
1002
1001
|
@staticmethod
|
|
1003
|
-
def
|
|
1002
|
+
def get_default_hub_source_url_prefix(object_type) -> str:
|
|
1004
1003
|
default_source = config.hub.default_source
|
|
1005
|
-
return f"{default_source.url}/{
|
|
1004
|
+
return f"{default_source.url}/{object_type}/{default_source.channel}/"
|
|
1006
1005
|
|
|
1007
1006
|
@staticmethod
|
|
1008
1007
|
def decode_base64_config_and_load_to_object(
|
mlrun/datastore/__init__.py
CHANGED
|
@@ -43,7 +43,7 @@ import storey
|
|
|
43
43
|
|
|
44
44
|
import mlrun.datastore.wasbfs
|
|
45
45
|
from mlrun.datastore.datastore_profile import (
|
|
46
|
-
|
|
46
|
+
DatastoreProfileKafkaStream,
|
|
47
47
|
DatastoreProfileKafkaTarget,
|
|
48
48
|
DatastoreProfileV3io,
|
|
49
49
|
)
|
|
@@ -123,7 +123,7 @@ def get_stream_pusher(stream_path: str, **kwargs):
|
|
|
123
123
|
)
|
|
124
124
|
if isinstance(
|
|
125
125
|
datastore_profile,
|
|
126
|
-
(
|
|
126
|
+
(DatastoreProfileKafkaStream, DatastoreProfileKafkaTarget),
|
|
127
127
|
):
|
|
128
128
|
attributes = datastore_profile.attributes()
|
|
129
129
|
brokers = attributes.pop("brokers", None)
|
|
@@ -19,6 +19,7 @@ import typing
|
|
|
19
19
|
from urllib.parse import ParseResult, urlparse
|
|
20
20
|
|
|
21
21
|
import pydantic.v1
|
|
22
|
+
from deprecated import deprecated
|
|
22
23
|
from mergedeep import merge
|
|
23
24
|
|
|
24
25
|
import mlrun
|
|
@@ -138,6 +139,15 @@ class ConfigProfile(DatastoreProfile):
|
|
|
138
139
|
return res
|
|
139
140
|
|
|
140
141
|
|
|
142
|
+
# TODO: Remove in 1.12.0
|
|
143
|
+
@deprecated(
|
|
144
|
+
version="1.10.0",
|
|
145
|
+
reason=(
|
|
146
|
+
"This class is deprecated from mlrun 1.10.0, and will be removed in 1.12.0. "
|
|
147
|
+
"Use `DatastoreProfileKafkaStream` instead."
|
|
148
|
+
),
|
|
149
|
+
category=FutureWarning,
|
|
150
|
+
)
|
|
141
151
|
class DatastoreProfileKafkaTarget(DatastoreProfile):
|
|
142
152
|
type: str = pydantic.v1.Field("kafka_target")
|
|
143
153
|
_private_attributes = "kwargs_private"
|
|
@@ -158,8 +168,8 @@ class DatastoreProfileKafkaTarget(DatastoreProfile):
|
|
|
158
168
|
return attributes
|
|
159
169
|
|
|
160
170
|
|
|
161
|
-
class
|
|
162
|
-
type: str = pydantic.v1.Field("
|
|
171
|
+
class DatastoreProfileKafkaStream(DatastoreProfile):
|
|
172
|
+
type: str = pydantic.v1.Field("kafka_stream")
|
|
163
173
|
_private_attributes = ("kwargs_private", "sasl_user", "sasl_pass")
|
|
164
174
|
brokers: typing.Union[str, list[str]]
|
|
165
175
|
topics: typing.Union[str, list[str]]
|
|
@@ -198,6 +208,19 @@ class DatastoreProfileKafkaSource(DatastoreProfile):
|
|
|
198
208
|
return attributes
|
|
199
209
|
|
|
200
210
|
|
|
211
|
+
# TODO: Remove in 1.12.0
|
|
212
|
+
@deprecated(
|
|
213
|
+
version="1.10.0",
|
|
214
|
+
reason=(
|
|
215
|
+
"This class is deprecated from mlrun 1.10.0, and will be removed in 1.12.0. "
|
|
216
|
+
"Use `DatastoreProfileKafkaStream` instead."
|
|
217
|
+
),
|
|
218
|
+
category=FutureWarning,
|
|
219
|
+
)
|
|
220
|
+
class DatastoreProfileKafkaSource(DatastoreProfileKafkaStream):
|
|
221
|
+
type: str = pydantic.v1.Field("kafka_source")
|
|
222
|
+
|
|
223
|
+
|
|
201
224
|
class DatastoreProfileV3io(DatastoreProfile):
|
|
202
225
|
type: str = pydantic.v1.Field("v3io")
|
|
203
226
|
v3io_access_key: typing.Optional[str] = None
|
|
@@ -232,7 +255,7 @@ class DatastoreProfileS3(DatastoreProfile):
|
|
|
232
255
|
if self.secret_key:
|
|
233
256
|
res["AWS_SECRET_ACCESS_KEY"] = self.secret_key
|
|
234
257
|
if self.endpoint_url:
|
|
235
|
-
res["
|
|
258
|
+
res["AWS_ENDPOINT_URL_S3"] = self.endpoint_url
|
|
236
259
|
if self.force_non_anonymous:
|
|
237
260
|
res["S3_NON_ANONYMOUS"] = self.force_non_anonymous
|
|
238
261
|
if self.profile_name:
|
|
@@ -524,6 +547,7 @@ _DATASTORE_TYPE_TO_PROFILE_CLASS: dict[str, type[DatastoreProfile]] = {
|
|
|
524
547
|
"basic": DatastoreProfileBasic,
|
|
525
548
|
"kafka_target": DatastoreProfileKafkaTarget,
|
|
526
549
|
"kafka_source": DatastoreProfileKafkaSource,
|
|
550
|
+
"kafka_stream": DatastoreProfileKafkaStream,
|
|
527
551
|
"dbfs": DatastoreProfileDBFS,
|
|
528
552
|
"gcs": DatastoreProfileGCS,
|
|
529
553
|
"az": DatastoreProfileAzureBlob,
|
|
@@ -113,7 +113,11 @@ class HuggingFaceProvider(ModelProvider):
|
|
|
113
113
|
from huggingface_hub import snapshot_download
|
|
114
114
|
|
|
115
115
|
# Download the model and tokenizer files directly to the cache.
|
|
116
|
-
snapshot_download(
|
|
116
|
+
snapshot_download(
|
|
117
|
+
repo_id=self.model,
|
|
118
|
+
local_dir_use_symlinks=False,
|
|
119
|
+
token=self._get_secret_or_env("HF_TOKEN") or None,
|
|
120
|
+
)
|
|
117
121
|
except ImportError as exc:
|
|
118
122
|
raise ImportError("huggingface_hub package is not installed") from exc
|
|
119
123
|
|
|
@@ -180,7 +180,7 @@ class ModelProvider(BaseRemoteClient):
|
|
|
180
180
|
raise NotImplementedError("custom_invoke method is not implemented")
|
|
181
181
|
|
|
182
182
|
async def async_custom_invoke(
|
|
183
|
-
self, operation: Optional[Callable[..., Awaitable[Any]]], **invoke_kwargs
|
|
183
|
+
self, operation: Optional[Callable[..., Awaitable[Any]]] = None, **invoke_kwargs
|
|
184
184
|
) -> Any:
|
|
185
185
|
"""
|
|
186
186
|
Asynchronously invokes a model operation from a provider (e.g., OpenAI, Hugging Face, etc.)
|
mlrun/datastore/s3.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import time
|
|
16
|
+
import warnings
|
|
16
17
|
from typing import Optional
|
|
17
18
|
from urllib.parse import urlparse
|
|
18
19
|
|
|
@@ -28,6 +29,27 @@ from .base import DataStore, FileStats, make_datastore_schema_sanitizer
|
|
|
28
29
|
class S3Store(DataStore):
|
|
29
30
|
using_bucket = True
|
|
30
31
|
|
|
32
|
+
# TODO: Remove this in 1.12.0
|
|
33
|
+
def _get_endpoint_url_with_deprecation_warning(self):
|
|
34
|
+
"""Get S3 endpoint URL with backward compatibility for deprecated S3_ENDPOINT_URL"""
|
|
35
|
+
# First try the new environment variable
|
|
36
|
+
endpoint_url = self._get_secret_or_env("AWS_ENDPOINT_URL_S3")
|
|
37
|
+
if endpoint_url:
|
|
38
|
+
return endpoint_url
|
|
39
|
+
|
|
40
|
+
# Check for deprecated environment variable
|
|
41
|
+
deprecated_endpoint_url = self._get_secret_or_env("S3_ENDPOINT_URL")
|
|
42
|
+
if deprecated_endpoint_url:
|
|
43
|
+
warnings.warn(
|
|
44
|
+
"S3_ENDPOINT_URL is deprecated in 1.10.0 and will be removed in 1.12.0, "
|
|
45
|
+
"use AWS_ENDPOINT_URL_S3 instead.",
|
|
46
|
+
# TODO: Remove this in 1.12.0
|
|
47
|
+
FutureWarning,
|
|
48
|
+
)
|
|
49
|
+
return deprecated_endpoint_url
|
|
50
|
+
|
|
51
|
+
return None
|
|
52
|
+
|
|
31
53
|
def __init__(
|
|
32
54
|
self, parent, schema, name, endpoint="", secrets: Optional[dict] = None
|
|
33
55
|
):
|
|
@@ -41,7 +63,7 @@ class S3Store(DataStore):
|
|
|
41
63
|
access_key_id = self._get_secret_or_env("AWS_ACCESS_KEY_ID")
|
|
42
64
|
secret_key = self._get_secret_or_env("AWS_SECRET_ACCESS_KEY")
|
|
43
65
|
token_file = self._get_secret_or_env("AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE")
|
|
44
|
-
endpoint_url = self.
|
|
66
|
+
endpoint_url = self._get_endpoint_url_with_deprecation_warning()
|
|
45
67
|
force_non_anonymous = self._get_secret_or_env("S3_NON_ANONYMOUS")
|
|
46
68
|
profile_name = self._get_secret_or_env("AWS_PROFILE")
|
|
47
69
|
assume_role_arn = self._get_secret_or_env("MLRUN_AWS_ROLE_ARN")
|
|
@@ -159,7 +181,7 @@ class S3Store(DataStore):
|
|
|
159
181
|
def get_storage_options(self):
|
|
160
182
|
force_non_anonymous = self._get_secret_or_env("S3_NON_ANONYMOUS")
|
|
161
183
|
profile = self._get_secret_or_env("AWS_PROFILE")
|
|
162
|
-
endpoint_url = self.
|
|
184
|
+
endpoint_url = self._get_endpoint_url_with_deprecation_warning()
|
|
163
185
|
access_key_id = self._get_secret_or_env("AWS_ACCESS_KEY_ID")
|
|
164
186
|
secret = self._get_secret_or_env("AWS_SECRET_ACCESS_KEY")
|
|
165
187
|
token_file = self._get_secret_or_env("AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE")
|
mlrun/datastore/storeytargets.py
CHANGED
|
@@ -18,10 +18,9 @@ from mergedeep import merge
|
|
|
18
18
|
from storey import V3ioDriver
|
|
19
19
|
|
|
20
20
|
import mlrun
|
|
21
|
-
import mlrun.model_monitoring.helpers
|
|
22
21
|
from mlrun.datastore.base import DataStore
|
|
23
22
|
from mlrun.datastore.datastore_profile import (
|
|
24
|
-
|
|
23
|
+
DatastoreProfileKafkaStream,
|
|
25
24
|
DatastoreProfileKafkaTarget,
|
|
26
25
|
DatastoreProfileTDEngine,
|
|
27
26
|
datastore_profile_read,
|
|
@@ -138,7 +137,7 @@ class KafkaStoreyTarget(storey.KafkaTarget):
|
|
|
138
137
|
datastore_profile = datastore_profile_read(path)
|
|
139
138
|
if not isinstance(
|
|
140
139
|
datastore_profile,
|
|
141
|
-
(
|
|
140
|
+
(DatastoreProfileKafkaStream, DatastoreProfileKafkaTarget),
|
|
142
141
|
):
|
|
143
142
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
144
143
|
f"Unsupported datastore profile type: {type(datastore_profile)}"
|
mlrun/db/base.py
CHANGED
|
@@ -792,6 +792,7 @@ class RunDBInterface(ABC):
|
|
|
792
792
|
version: Optional[str] = None,
|
|
793
793
|
tag: Optional[str] = None,
|
|
794
794
|
force_refresh: bool = False,
|
|
795
|
+
object_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
795
796
|
):
|
|
796
797
|
pass
|
|
797
798
|
|
|
@@ -803,6 +804,19 @@ class RunDBInterface(ABC):
|
|
|
803
804
|
version: Optional[str] = None,
|
|
804
805
|
tag: str = "latest",
|
|
805
806
|
force_refresh: bool = False,
|
|
807
|
+
item_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
808
|
+
):
|
|
809
|
+
pass
|
|
810
|
+
|
|
811
|
+
@abstractmethod
|
|
812
|
+
def get_hub_asset(
|
|
813
|
+
self,
|
|
814
|
+
source_name: str,
|
|
815
|
+
item_name: str,
|
|
816
|
+
asset_name: str,
|
|
817
|
+
version: Optional[str] = None,
|
|
818
|
+
tag: str = "latest",
|
|
819
|
+
item_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
806
820
|
):
|
|
807
821
|
pass
|
|
808
822
|
|
mlrun/db/httpdb.py
CHANGED
|
@@ -45,6 +45,7 @@ import mlrun.runtimes.nuclio.api_gateway
|
|
|
45
45
|
import mlrun.runtimes.nuclio.function
|
|
46
46
|
import mlrun.utils
|
|
47
47
|
from mlrun.alerts.alert import AlertConfig
|
|
48
|
+
from mlrun.common.schemas.hub import HubSourceType
|
|
48
49
|
from mlrun.db.auth_utils import OAuthClientIDTokenProvider, StaticTokenProvider
|
|
49
50
|
from mlrun.errors import MLRunInvalidArgumentError, err_to_str
|
|
50
51
|
from mlrun.secrets import get_secret_or_env
|
|
@@ -4081,7 +4082,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4081
4082
|
response = self.api_call(
|
|
4082
4083
|
method=mlrun.common.types.HTTPMethod.DELETE,
|
|
4083
4084
|
path=f"projects/{project}/model-monitoring/functions",
|
|
4084
|
-
params={"
|
|
4085
|
+
params={"function": functions},
|
|
4085
4086
|
)
|
|
4086
4087
|
deletion_failed = False
|
|
4087
4088
|
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
@@ -4361,6 +4362,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4361
4362
|
version: Optional[str] = None,
|
|
4362
4363
|
tag: Optional[str] = None,
|
|
4363
4364
|
force_refresh: bool = False,
|
|
4365
|
+
object_type: HubSourceType = HubSourceType.functions,
|
|
4364
4366
|
):
|
|
4365
4367
|
"""
|
|
4366
4368
|
Retrieve the item catalog for a specified hub source.
|
|
@@ -4373,6 +4375,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4373
4375
|
rather than rely on cached information which may exist from previous get requests. For example,
|
|
4374
4376
|
if the source was re-built,
|
|
4375
4377
|
this will make the server get the updated information. Default is ``False``.
|
|
4378
|
+
:param object_type: Type of object to retrieve from the hub source (e.g: functions, modules).
|
|
4376
4379
|
:returns: :py:class:`~mlrun.common.schemas.hub.HubCatalog` object, which is essentially a list
|
|
4377
4380
|
of :py:class:`~mlrun.common.schemas.hub.HubItem` entries.
|
|
4378
4381
|
"""
|
|
@@ -4381,6 +4384,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4381
4384
|
"version": version,
|
|
4382
4385
|
"tag": tag,
|
|
4383
4386
|
"force-refresh": force_refresh,
|
|
4387
|
+
"object_type": object_type,
|
|
4384
4388
|
}
|
|
4385
4389
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4386
4390
|
return mlrun.common.schemas.HubCatalog(**response.json())
|
|
@@ -4392,6 +4396,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4392
4396
|
version: Optional[str] = None,
|
|
4393
4397
|
tag: str = "latest",
|
|
4394
4398
|
force_refresh: bool = False,
|
|
4399
|
+
item_type: HubSourceType = HubSourceType.functions,
|
|
4395
4400
|
):
|
|
4396
4401
|
"""
|
|
4397
4402
|
Retrieve a specific hub item.
|
|
@@ -4403,6 +4408,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4403
4408
|
:param force_refresh: Make the server fetch the information from the actual hub
|
|
4404
4409
|
source, rather than
|
|
4405
4410
|
rely on cached information. Default is ``False``.
|
|
4411
|
+
:param item_type: The type of item to retrieve from the hub source (e.g: functions, modules).
|
|
4406
4412
|
:returns: :py:class:`~mlrun.common.schemas.hub.HubItem`.
|
|
4407
4413
|
"""
|
|
4408
4414
|
path = (f"hub/sources/{source_name}/items/{item_name}",)
|
|
@@ -4410,6 +4416,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4410
4416
|
"version": version,
|
|
4411
4417
|
"tag": tag,
|
|
4412
4418
|
"force-refresh": force_refresh,
|
|
4419
|
+
"item_type": item_type,
|
|
4413
4420
|
}
|
|
4414
4421
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4415
4422
|
return mlrun.common.schemas.HubItem(**response.json())
|
|
@@ -4421,6 +4428,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4421
4428
|
asset_name: str,
|
|
4422
4429
|
version: Optional[str] = None,
|
|
4423
4430
|
tag: str = "latest",
|
|
4431
|
+
item_type: HubSourceType = HubSourceType.functions,
|
|
4424
4432
|
):
|
|
4425
4433
|
"""
|
|
4426
4434
|
Get hub asset from item.
|
|
@@ -4430,13 +4438,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4430
4438
|
:param asset_name: Name of the asset to retrieve.
|
|
4431
4439
|
:param version: Get a specific version of the item. Default is ``None``.
|
|
4432
4440
|
:param tag: Get a specific version of the item identified by tag. Default is ``latest``.
|
|
4433
|
-
|
|
4441
|
+
:param item_type: The type of item to retrieve from the hub source (e.g: functions, modules).
|
|
4434
4442
|
:returns: http response with the asset in the content attribute
|
|
4435
4443
|
"""
|
|
4436
4444
|
path = f"hub/sources/{source_name}/items/{item_name}/assets/{asset_name}"
|
|
4437
4445
|
params = {
|
|
4438
4446
|
"version": version,
|
|
4439
4447
|
"tag": tag,
|
|
4448
|
+
"item_type": item_type,
|
|
4440
4449
|
}
|
|
4441
4450
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4442
4451
|
return response
|
mlrun/db/nopdb.py
CHANGED
|
@@ -689,6 +689,7 @@ class NopDB(RunDBInterface):
|
|
|
689
689
|
version: Optional[str] = None,
|
|
690
690
|
tag: Optional[str] = None,
|
|
691
691
|
force_refresh: bool = False,
|
|
692
|
+
object_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
692
693
|
):
|
|
693
694
|
pass
|
|
694
695
|
|
|
@@ -700,6 +701,18 @@ class NopDB(RunDBInterface):
|
|
|
700
701
|
version: Optional[str] = None,
|
|
701
702
|
tag: str = "latest",
|
|
702
703
|
force_refresh: bool = False,
|
|
704
|
+
item_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
705
|
+
):
|
|
706
|
+
pass
|
|
707
|
+
|
|
708
|
+
def get_hub_asset(
|
|
709
|
+
self,
|
|
710
|
+
source_name: str,
|
|
711
|
+
item_name: str,
|
|
712
|
+
asset_name: str,
|
|
713
|
+
version: Optional[str] = None,
|
|
714
|
+
tag: str = "latest",
|
|
715
|
+
item_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
703
716
|
):
|
|
704
717
|
pass
|
|
705
718
|
|
mlrun/k8s_utils.py
CHANGED
|
@@ -470,20 +470,6 @@ def _handle_allow_mode(
|
|
|
470
470
|
list[kubernetes.client.V1Toleration],
|
|
471
471
|
typing.Optional[kubernetes.client.V1Affinity],
|
|
472
472
|
]:
|
|
473
|
-
for op in [
|
|
474
|
-
mlrun.common.schemas.NodeSelectorOperator.node_selector_op_not_in.value,
|
|
475
|
-
mlrun.common.schemas.NodeSelectorOperator.node_selector_op_in.value,
|
|
476
|
-
]:
|
|
477
|
-
affinity = _prune_affinity_node_selector_requirement(
|
|
478
|
-
generate_preemptible_node_selector_requirements(op),
|
|
479
|
-
affinity=affinity,
|
|
480
|
-
)
|
|
481
|
-
|
|
482
|
-
node_selector = _prune_node_selector(
|
|
483
|
-
mlconfig.get_preemptible_node_selector(),
|
|
484
|
-
enriched_node_selector=node_selector,
|
|
485
|
-
)
|
|
486
|
-
|
|
487
473
|
tolerations = _merge_tolerations(tolerations, preemptible_tolerations)
|
|
488
474
|
return node_selector, tolerations, affinity
|
|
489
475
|
|
|
@@ -347,6 +347,21 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
|
347
347
|
feature_stats=feature_stats,
|
|
348
348
|
)
|
|
349
349
|
)
|
|
350
|
+
|
|
351
|
+
if (
|
|
352
|
+
monitoring_context.endpoint_id
|
|
353
|
+
and monitoring_context.sample_df.empty
|
|
354
|
+
):
|
|
355
|
+
# The current sample is empty
|
|
356
|
+
context.logger.warning(
|
|
357
|
+
"No sample data available for tracking",
|
|
358
|
+
application_name=application_name,
|
|
359
|
+
endpoint_id=monitoring_context.endpoint_id,
|
|
360
|
+
start_time=monitoring_context.start_infer_time,
|
|
361
|
+
end_time=monitoring_context.end_infer_time,
|
|
362
|
+
)
|
|
363
|
+
return
|
|
364
|
+
|
|
350
365
|
result = self.do_tracking(monitoring_context)
|
|
351
366
|
endpoints_output[monitoring_context.endpoint_id].append(
|
|
352
367
|
(monitoring_context, result)
|
|
@@ -529,15 +544,17 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
|
529
544
|
else:
|
|
530
545
|
raise mlrun.errors.MLRunValueError(
|
|
531
546
|
"The start time for the application and endpoint precedes the last analyzed time: "
|
|
532
|
-
f"{start_dt
|
|
547
|
+
f"start_dt='{start_dt}', last_analyzed='{last_analyzed}', {application_name=}, "
|
|
548
|
+
f"{endpoint_id=}. "
|
|
533
549
|
"Writing data out of order is not supported, and the start time could not be "
|
|
534
550
|
"dynamically reset, as last_analyzed is later than the given end time or that "
|
|
535
|
-
f"base_period was specified ({end_dt
|
|
551
|
+
f"base_period was specified (end_dt='{end_dt}', {base_period=})."
|
|
536
552
|
)
|
|
537
553
|
else:
|
|
538
554
|
raise mlrun.errors.MLRunValueError(
|
|
539
555
|
"The start time for the application and endpoint precedes the last analyzed time: "
|
|
540
|
-
f"{start_dt
|
|
556
|
+
f"start_dt='{start_dt}', last_analyzed='{last_analyzed}', {application_name=}, "
|
|
557
|
+
f"{endpoint_id=}. "
|
|
541
558
|
"Writing data out of order is not supported. You should change the start time to "
|
|
542
559
|
f"'{last_analyzed}' or later."
|
|
543
560
|
)
|
|
@@ -807,6 +807,11 @@ class MonitoringApplicationController:
|
|
|
807
807
|
mm_constants.EndpointMode.BATCH_LEGACY,
|
|
808
808
|
],
|
|
809
809
|
).endpoints
|
|
810
|
+
|
|
811
|
+
if not endpoints:
|
|
812
|
+
logger.info("No model endpoints found", project=self.project)
|
|
813
|
+
return
|
|
814
|
+
|
|
810
815
|
last_request_dict = self.tsdb_connector.get_last_request(
|
|
811
816
|
endpoint_ids=[mep.metadata.uid for mep in endpoints]
|
|
812
817
|
)
|
|
@@ -815,9 +820,6 @@ class MonitoringApplicationController:
|
|
|
815
820
|
mm_constants.EventFieldType.ENDPOINT_ID
|
|
816
821
|
)[mm_constants.ModelEndpointSchema.LAST_REQUEST].to_dict()
|
|
817
822
|
|
|
818
|
-
if not endpoints:
|
|
819
|
-
logger.info("No model endpoints found", project=self.project)
|
|
820
|
-
return
|
|
821
823
|
monitoring_functions = self.project_obj.list_model_monitoring_functions()
|
|
822
824
|
if monitoring_functions:
|
|
823
825
|
# if monitoring_functions: - TODO : ML-7700
|
|
@@ -721,7 +721,9 @@ class TDEngineConnector(TSDBConnector):
|
|
|
721
721
|
endpoint_ids: Union[str, list[str]],
|
|
722
722
|
start: Optional[datetime] = None,
|
|
723
723
|
end: Optional[datetime] = None,
|
|
724
|
-
) -> pd.DataFrame:
|
|
724
|
+
) -> Union[pd.DataFrame, dict[str, float]]:
|
|
725
|
+
if not endpoint_ids:
|
|
726
|
+
return {}
|
|
725
727
|
filter_query = self._generate_filter_query(
|
|
726
728
|
filter_column=mm_schemas.EventFieldType.ENDPOINT_ID,
|
|
727
729
|
filter_values=endpoint_ids,
|