mlrun 1.8.0rc29__py3-none-any.whl → 1.8.0rc31__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 -34
- mlrun/api/schemas/__init__.py +1 -6
- mlrun/artifacts/document.py +3 -3
- mlrun/artifacts/manager.py +1 -0
- mlrun/artifacts/model.py +3 -3
- mlrun/common/model_monitoring/helpers.py +16 -7
- mlrun/common/runtimes/constants.py +5 -0
- mlrun/common/schemas/__init__.py +0 -2
- mlrun/common/schemas/model_monitoring/__init__.py +0 -2
- mlrun/common/schemas/model_monitoring/constants.py +4 -7
- mlrun/common/schemas/model_monitoring/grafana.py +17 -11
- mlrun/config.py +9 -36
- mlrun/datastore/datastore_profile.py +1 -1
- mlrun/datastore/sources.py +14 -13
- mlrun/datastore/storeytargets.py +20 -3
- mlrun/db/httpdb.py +4 -30
- mlrun/k8s_utils.py +2 -5
- mlrun/launcher/base.py +16 -0
- mlrun/model_monitoring/api.py +1 -2
- mlrun/model_monitoring/applications/_application_steps.py +23 -37
- mlrun/model_monitoring/applications/base.py +55 -40
- mlrun/model_monitoring/applications/context.py +0 -3
- mlrun/model_monitoring/applications/results.py +16 -16
- mlrun/model_monitoring/controller.py +35 -31
- mlrun/model_monitoring/db/tsdb/__init__.py +9 -5
- mlrun/model_monitoring/db/tsdb/base.py +60 -39
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +122 -53
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +140 -14
- mlrun/model_monitoring/helpers.py +124 -16
- mlrun/model_monitoring/stream_processing.py +6 -21
- mlrun/projects/pipelines.py +11 -3
- mlrun/projects/project.py +104 -115
- mlrun/run.py +2 -2
- mlrun/runtimes/nuclio/function.py +4 -2
- mlrun/serving/routers.py +3 -4
- mlrun/serving/server.py +10 -8
- mlrun/serving/states.py +12 -2
- mlrun/serving/v2_serving.py +25 -20
- mlrun/utils/async_http.py +32 -19
- mlrun/utils/helpers.py +5 -2
- mlrun/utils/logger.py +14 -10
- mlrun/utils/notifications/notification_pusher.py +25 -0
- mlrun/utils/regex.py +1 -0
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/METADATA +4 -4
- {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/RECORD +50 -50
- {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/LICENSE +0 -0
- {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/WHEEL +0 -0
- {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/top_level.txt +0 -0
|
@@ -95,8 +95,8 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
|
95
95
|
sample_data: Optional[pd.DataFrame] = None,
|
|
96
96
|
reference_data: Optional[pd.DataFrame] = None,
|
|
97
97
|
endpoints: Optional[list[tuple[str, str]]] = None,
|
|
98
|
-
start: Optional[
|
|
99
|
-
end: Optional[
|
|
98
|
+
start: Optional[str] = None,
|
|
99
|
+
end: Optional[str] = None,
|
|
100
100
|
base_period: Optional[int] = None,
|
|
101
101
|
):
|
|
102
102
|
"""
|
|
@@ -124,7 +124,6 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
|
124
124
|
return self.do_tracking(monitoring_context)
|
|
125
125
|
|
|
126
126
|
if endpoints is not None:
|
|
127
|
-
start, end = self._validate_times(start, end, base_period)
|
|
128
127
|
for window_start, window_end in self._window_generator(
|
|
129
128
|
start, end, base_period
|
|
130
129
|
):
|
|
@@ -137,43 +136,40 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
|
137
136
|
mm_constants.ApplicationEvent.END_INFER_TIME: window_end,
|
|
138
137
|
}
|
|
139
138
|
)
|
|
140
|
-
|
|
141
|
-
f"{endpoint_name}_{window_start.isoformat()}_{window_end.isoformat()}"
|
|
142
|
-
|
|
139
|
+
result_key = (
|
|
140
|
+
f"{endpoint_name}_{window_start.isoformat()}_{window_end.isoformat()}"
|
|
141
|
+
if window_start and window_end
|
|
142
|
+
else endpoint_name
|
|
143
143
|
)
|
|
144
|
+
context.log_result(result_key, result)
|
|
144
145
|
else:
|
|
145
146
|
return call_do_tracking()
|
|
146
147
|
|
|
147
|
-
@staticmethod
|
|
148
|
-
def _validate_times(
|
|
149
|
-
start: Optional[datetime],
|
|
150
|
-
end: Optional[datetime],
|
|
151
|
-
base_period: Optional[int],
|
|
152
|
-
) -> tuple[datetime, datetime]:
|
|
153
|
-
if (start is None) or (end is None):
|
|
154
|
-
raise mlrun.errors.MLRunValueError(
|
|
155
|
-
"When `endpoint_names` is provided, you must also pass the start and end times"
|
|
156
|
-
)
|
|
157
|
-
if (base_period is not None) and not (
|
|
158
|
-
isinstance(base_period, int) and base_period > 0
|
|
159
|
-
):
|
|
160
|
-
raise mlrun.errors.MLRunValueError(
|
|
161
|
-
"`base_period` must be a nonnegative integer - the number of minutes in a monitoring window"
|
|
162
|
-
)
|
|
163
|
-
return start, end
|
|
164
|
-
|
|
165
148
|
@staticmethod
|
|
166
149
|
def _window_generator(
|
|
167
|
-
start:
|
|
168
|
-
) -> Iterator[tuple[datetime, datetime]]:
|
|
150
|
+
start: Optional[str], end: Optional[str], base_period: Optional[int]
|
|
151
|
+
) -> Iterator[tuple[Optional[datetime], Optional[datetime]]]:
|
|
152
|
+
if start is None or end is None:
|
|
153
|
+
# A single window based on the `sample_data` input - see `_handler`.
|
|
154
|
+
yield None, None
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
start_dt = datetime.fromisoformat(start)
|
|
158
|
+
end_dt = datetime.fromisoformat(end)
|
|
159
|
+
|
|
169
160
|
if base_period is None:
|
|
170
|
-
yield
|
|
161
|
+
yield start_dt, end_dt
|
|
171
162
|
return
|
|
172
163
|
|
|
164
|
+
if not isinstance(base_period, int) or base_period <= 0:
|
|
165
|
+
raise mlrun.errors.MLRunValueError(
|
|
166
|
+
"`base_period` must be a nonnegative integer - the number of minutes in a monitoring window"
|
|
167
|
+
)
|
|
168
|
+
|
|
173
169
|
window_length = timedelta(minutes=base_period)
|
|
174
|
-
current_start_time =
|
|
175
|
-
while current_start_time <
|
|
176
|
-
current_end_time = min(current_start_time + window_length,
|
|
170
|
+
current_start_time = start_dt
|
|
171
|
+
while current_start_time < end_dt:
|
|
172
|
+
current_end_time = min(current_start_time + window_length, end_dt)
|
|
177
173
|
yield current_start_time, current_end_time
|
|
178
174
|
current_start_time = current_end_time
|
|
179
175
|
|
|
@@ -369,13 +365,25 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
|
369
365
|
:param requirements: List of Python requirements to be installed in the image.
|
|
370
366
|
:param requirements_file: Path to a Python requirements file to be installed in the image.
|
|
371
367
|
:param endpoints: A list of tuples of the model endpoint (name, uid) to get the data from.
|
|
372
|
-
If provided, you have to provide also the start and
|
|
373
|
-
|
|
374
|
-
:param
|
|
368
|
+
If provided, and ``sample_data`` is not, you have to provide also the ``start`` and
|
|
369
|
+
``end`` times of the data to analyze from the model endpoints.
|
|
370
|
+
:param start: The start time of the endpoint's data, not included.
|
|
371
|
+
If you want the model endpoint's data at ``start`` included, you need to subtract a
|
|
372
|
+
small ``datetime.timedelta`` from it.
|
|
373
|
+
:param end: The end time of the endpoint's data, included.
|
|
374
|
+
Please note: when ``start`` and ``end`` are set, they create a left-open time interval
|
|
375
|
+
("window") :math:`(\\text{start}, \\text{end}]` that excludes the endpoint's data at
|
|
376
|
+
``start`` and includes the data at ``end``:
|
|
377
|
+
:math:`\\text{start} < t \\leq \\text{end}`, :math:`t` is the time taken in the
|
|
378
|
+
window's data.
|
|
375
379
|
:param base_period: The window length in minutes. If ``None``, the whole window from ``start`` to ``end``
|
|
376
380
|
is taken. If an integer is specified, the application is run from ``start`` to ``end``
|
|
377
381
|
in ``base_period`` length windows, except for the last window that ends at ``end`` and
|
|
378
|
-
therefore may be shorter
|
|
382
|
+
therefore may be shorter:
|
|
383
|
+
:math:`(\\text{start}, \\text{start} + \\text{base_period}],
|
|
384
|
+
(\\text{start} + \\text{base_period}, \\text{start} + 2\\cdot\\text{base_period}],
|
|
385
|
+
..., (\\text{start} + m\\cdot\\text{base_period}, \\text{end}]`,
|
|
386
|
+
where :math:`m` is some positive integer.
|
|
379
387
|
|
|
380
388
|
:returns: The output of the
|
|
381
389
|
:py:meth:`~mlrun.model_monitoring.applications.ModelMonitoringApplicationBase.do_tracking`
|
|
@@ -395,16 +403,23 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
|
395
403
|
project=project,
|
|
396
404
|
)
|
|
397
405
|
|
|
398
|
-
params: dict[str, Union[list[tuple[str, str]],
|
|
406
|
+
params: dict[str, Union[list[tuple[str, str]], str, int, None]] = {}
|
|
399
407
|
if endpoints:
|
|
400
|
-
start, end = cls._validate_times(start, end, base_period)
|
|
401
408
|
params["endpoints"] = endpoints
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
409
|
+
if sample_data is None:
|
|
410
|
+
if start is None or end is None:
|
|
411
|
+
raise mlrun.errors.MLRunValueError(
|
|
412
|
+
"`start` and `end` times must be provided when `endpoints` "
|
|
413
|
+
"is provided without `sample_data`"
|
|
414
|
+
)
|
|
415
|
+
params["start"] = (
|
|
416
|
+
start.isoformat() if isinstance(start, datetime) else start
|
|
417
|
+
)
|
|
418
|
+
params["end"] = end.isoformat() if isinstance(end, datetime) else end
|
|
419
|
+
params["base_period"] = base_period
|
|
405
420
|
elif start or end or base_period:
|
|
406
421
|
raise mlrun.errors.MLRunValueError(
|
|
407
|
-
"Custom start and end times or base_period are supported only with endpoints data"
|
|
422
|
+
"Custom `start` and `end` times or base_period are supported only with endpoints data"
|
|
408
423
|
)
|
|
409
424
|
|
|
410
425
|
inputs: dict[str, str] = {}
|
|
@@ -111,9 +111,6 @@ class MonitoringApplicationContext:
|
|
|
111
111
|
self.endpoint_name = cast(
|
|
112
112
|
str, event.get(mm_constants.ApplicationEvent.ENDPOINT_NAME)
|
|
113
113
|
)
|
|
114
|
-
self.output_stream_uri = cast(
|
|
115
|
-
str, event.get(mm_constants.ApplicationEvent.OUTPUT_STREAM_URI)
|
|
116
|
-
)
|
|
117
114
|
|
|
118
115
|
self._feature_stats: Optional[FeatureStats] = feature_stats
|
|
119
116
|
self._sample_df_stats: Optional[FeatureStats] = None
|
|
@@ -22,7 +22,7 @@ from pydantic.v1.dataclasses import dataclass
|
|
|
22
22
|
|
|
23
23
|
import mlrun.common.helpers
|
|
24
24
|
import mlrun.common.model_monitoring.helpers
|
|
25
|
-
import mlrun.common.schemas.model_monitoring.constants as
|
|
25
|
+
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
26
26
|
import mlrun.utils.v3io_clients
|
|
27
27
|
from mlrun.utils import logger
|
|
28
28
|
|
|
@@ -33,10 +33,10 @@ class _ModelMonitoringApplicationDataRes(ABC):
|
|
|
33
33
|
name: str
|
|
34
34
|
|
|
35
35
|
def __post_init__(self):
|
|
36
|
-
pat = re.compile(
|
|
36
|
+
pat = re.compile(mm_constants.RESULT_NAME_PATTERN)
|
|
37
37
|
if not re.fullmatch(pat, self.name):
|
|
38
38
|
raise mlrun.errors.MLRunValueError(
|
|
39
|
-
"Attribute name must comply with the regex `
|
|
39
|
+
f"Attribute name must comply with the regex `{mm_constants.RESULT_NAME_PATTERN}`"
|
|
40
40
|
)
|
|
41
41
|
|
|
42
42
|
@abstractmethod
|
|
@@ -63,8 +63,8 @@ class ModelMonitoringApplicationResult(_ModelMonitoringApplicationDataRes):
|
|
|
63
63
|
|
|
64
64
|
name: str
|
|
65
65
|
value: float
|
|
66
|
-
kind:
|
|
67
|
-
status:
|
|
66
|
+
kind: mm_constants.ResultKindApp
|
|
67
|
+
status: mm_constants.ResultStatusApp
|
|
68
68
|
extra_data: dict = dataclasses.field(default_factory=dict)
|
|
69
69
|
|
|
70
70
|
def to_dict(self):
|
|
@@ -74,11 +74,11 @@ class ModelMonitoringApplicationResult(_ModelMonitoringApplicationDataRes):
|
|
|
74
74
|
:returns: (dict) Dictionary representation of the result.
|
|
75
75
|
"""
|
|
76
76
|
return {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
mm_constants.ResultData.RESULT_NAME: self.name,
|
|
78
|
+
mm_constants.ResultData.RESULT_VALUE: self.value,
|
|
79
|
+
mm_constants.ResultData.RESULT_KIND: self.kind.value,
|
|
80
|
+
mm_constants.ResultData.RESULT_STATUS: self.status.value,
|
|
81
|
+
mm_constants.ResultData.RESULT_EXTRA_DATA: json.dumps(self.extra_data),
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
@validator("extra_data")
|
|
@@ -118,8 +118,8 @@ class ModelMonitoringApplicationMetric(_ModelMonitoringApplicationDataRes):
|
|
|
118
118
|
:returns: (dict) Dictionary representation of the result.
|
|
119
119
|
"""
|
|
120
120
|
return {
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
mm_constants.MetricData.METRIC_NAME: self.name,
|
|
122
|
+
mm_constants.MetricData.METRIC_VALUE: self.value,
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
|
|
@@ -134,7 +134,7 @@ class _ModelMonitoringApplicationStats(_ModelMonitoringApplicationDataRes):
|
|
|
134
134
|
|
|
135
135
|
"""
|
|
136
136
|
|
|
137
|
-
name:
|
|
137
|
+
name: mm_constants.StatsKind
|
|
138
138
|
timestamp: str
|
|
139
139
|
stats: dict = dataclasses.field(default_factory=dict)
|
|
140
140
|
|
|
@@ -145,7 +145,7 @@ class _ModelMonitoringApplicationStats(_ModelMonitoringApplicationDataRes):
|
|
|
145
145
|
:returns: (dict) Dictionary representation of the result.
|
|
146
146
|
"""
|
|
147
147
|
return {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
mm_constants.StatsData.STATS_NAME: self.name,
|
|
149
|
+
mm_constants.StatsData.STATS: self.stats,
|
|
150
|
+
mm_constants.StatsData.TIMESTAMP: self.timestamp,
|
|
151
151
|
}
|
|
@@ -27,15 +27,15 @@ import mlrun
|
|
|
27
27
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
28
28
|
import mlrun.feature_store as fstore
|
|
29
29
|
import mlrun.model_monitoring
|
|
30
|
+
import mlrun.model_monitoring.helpers
|
|
30
31
|
from mlrun.common.schemas import EndpointType
|
|
31
32
|
from mlrun.common.schemas.model_monitoring.constants import (
|
|
32
33
|
ControllerEvent,
|
|
33
34
|
ControllerEventKind,
|
|
34
35
|
)
|
|
35
|
-
from mlrun.datastore import get_stream_pusher
|
|
36
36
|
from mlrun.errors import err_to_str
|
|
37
37
|
from mlrun.model_monitoring.db._schedules import ModelMonitoringSchedulesFile
|
|
38
|
-
from mlrun.model_monitoring.helpers import batch_dict2timedelta
|
|
38
|
+
from mlrun.model_monitoring.helpers import batch_dict2timedelta
|
|
39
39
|
from mlrun.utils import datetime_now, logger
|
|
40
40
|
|
|
41
41
|
_SECONDS_IN_DAY = int(datetime.timedelta(days=1).total_seconds())
|
|
@@ -249,10 +249,11 @@ class MonitoringApplicationController:
|
|
|
249
249
|
self._window_length = _get_window_length()
|
|
250
250
|
|
|
251
251
|
self.model_monitoring_access_key = self._get_model_monitoring_access_key()
|
|
252
|
-
self.v3io_access_key = mlrun.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
252
|
+
self.v3io_access_key = mlrun.mlconf.get_v3io_access_key()
|
|
253
|
+
store, _, _ = mlrun.store_manager.get_or_create_store(
|
|
254
|
+
mlrun.mlconf.artifact_path
|
|
255
|
+
)
|
|
256
|
+
self.storage_options = store.get_storage_options()
|
|
256
257
|
|
|
257
258
|
@staticmethod
|
|
258
259
|
def _get_model_monitoring_access_key() -> Optional[str]:
|
|
@@ -482,24 +483,23 @@ class MonitoringApplicationController:
|
|
|
482
483
|
),
|
|
483
484
|
mm_constants.ApplicationEvent.ENDPOINT_ID: endpoint_id,
|
|
484
485
|
mm_constants.ApplicationEvent.ENDPOINT_NAME: endpoint_name,
|
|
485
|
-
mm_constants.ApplicationEvent.OUTPUT_STREAM_URI: get_stream_path(
|
|
486
|
-
project=project,
|
|
487
|
-
function_name=mm_constants.MonitoringFunctionNames.WRITER,
|
|
488
|
-
),
|
|
489
486
|
}
|
|
490
487
|
for app_name in applications_names:
|
|
491
488
|
data.update({mm_constants.ApplicationEvent.APPLICATION_NAME: app_name})
|
|
492
|
-
|
|
489
|
+
|
|
490
|
+
app_stream = mlrun.model_monitoring.helpers.get_output_stream(
|
|
491
|
+
project=project,
|
|
492
|
+
function_name=app_name,
|
|
493
|
+
v3io_access_key=model_monitoring_access_key,
|
|
494
|
+
)
|
|
493
495
|
|
|
494
496
|
logger.info(
|
|
495
497
|
"Pushing data to application stream",
|
|
496
498
|
endpoint_id=endpoint_id,
|
|
497
499
|
app_name=app_name,
|
|
498
|
-
|
|
499
|
-
)
|
|
500
|
-
get_stream_pusher(stream_uri, access_key=model_monitoring_access_key).push(
|
|
501
|
-
[data]
|
|
500
|
+
app_stream_type=str(type(app_stream)),
|
|
502
501
|
)
|
|
502
|
+
app_stream.push([data])
|
|
503
503
|
|
|
504
504
|
def push_regular_event_to_controller_stream(self) -> None:
|
|
505
505
|
"""
|
|
@@ -628,10 +628,6 @@ class MonitoringApplicationController:
|
|
|
628
628
|
:param feature_set_uri: the feature set uri string
|
|
629
629
|
:param stream_access_key: access key to apply the model monitoring process.
|
|
630
630
|
"""
|
|
631
|
-
stream_uri = get_stream_path(
|
|
632
|
-
project=project,
|
|
633
|
-
function_name=mm_constants.MonitoringFunctionNames.APPLICATION_CONTROLLER,
|
|
634
|
-
)
|
|
635
631
|
event = {
|
|
636
632
|
ControllerEvent.KIND.value: kind,
|
|
637
633
|
ControllerEvent.PROJECT.value: project,
|
|
@@ -643,15 +639,18 @@ class MonitoringApplicationController:
|
|
|
643
639
|
ControllerEvent.FEATURE_SET_URI.value: feature_set_uri,
|
|
644
640
|
ControllerEvent.ENDPOINT_POLICY.value: endpoint_policy,
|
|
645
641
|
}
|
|
642
|
+
controller_stream = mlrun.model_monitoring.helpers.get_output_stream(
|
|
643
|
+
project=project,
|
|
644
|
+
function_name=mm_constants.MonitoringFunctionNames.APPLICATION_CONTROLLER,
|
|
645
|
+
v3io_access_key=stream_access_key,
|
|
646
|
+
)
|
|
646
647
|
logger.info(
|
|
647
648
|
"Pushing data to controller stream",
|
|
648
649
|
event=event,
|
|
649
650
|
endpoint_id=endpoint_id,
|
|
650
|
-
|
|
651
|
-
)
|
|
652
|
-
get_stream_pusher(stream_uri, access_key=stream_access_key).push(
|
|
653
|
-
[event], partition_key=endpoint_id
|
|
651
|
+
controller_stream_type=str(type(controller_stream)),
|
|
654
652
|
)
|
|
653
|
+
controller_stream.push([event], partition_key=endpoint_id)
|
|
655
654
|
|
|
656
655
|
def _push_to_main_stream(self, event: dict, endpoint_id: str) -> None:
|
|
657
656
|
"""
|
|
@@ -659,17 +658,18 @@ class MonitoringApplicationController:
|
|
|
659
658
|
:param event: event dictionary to push to stream
|
|
660
659
|
:param endpoint_id: endpoint id string
|
|
661
660
|
"""
|
|
662
|
-
|
|
663
|
-
|
|
661
|
+
mm_stream = mlrun.model_monitoring.helpers.get_output_stream(
|
|
662
|
+
project=event.get(ControllerEvent.PROJECT),
|
|
663
|
+
function_name=mm_constants.MonitoringFunctionNames.APPLICATION_CONTROLLER,
|
|
664
|
+
v3io_access_key=self.v3io_access_key,
|
|
665
|
+
)
|
|
664
666
|
logger.info(
|
|
665
667
|
"Pushing data to main stream, NOP event is been generated",
|
|
666
668
|
event=json.dumps(event),
|
|
667
669
|
endpoint_id=endpoint_id,
|
|
668
|
-
|
|
669
|
-
)
|
|
670
|
-
get_stream_pusher(stream_uri, access_key=self.model_monitoring_access_key).push(
|
|
671
|
-
[event], partition_key=endpoint_id
|
|
670
|
+
mm_stream_type=str(type(mm_stream)),
|
|
672
671
|
)
|
|
672
|
+
mm_stream.push([event], partition_key=endpoint_id)
|
|
673
673
|
|
|
674
674
|
|
|
675
675
|
def handler(context: nuclio_sdk.Context, event: nuclio_sdk.Event) -> None:
|
|
@@ -685,12 +685,16 @@ def handler(context: nuclio_sdk.Context, event: nuclio_sdk.Event) -> None:
|
|
|
685
685
|
trigger_kind=event.trigger.kind,
|
|
686
686
|
)
|
|
687
687
|
|
|
688
|
-
if event.trigger.kind
|
|
688
|
+
if event.trigger.kind in mm_constants.CRON_TRIGGER_KINDS:
|
|
689
689
|
# Runs controller chief:
|
|
690
690
|
context.user_data.monitor_app_controller.push_regular_event_to_controller_stream()
|
|
691
|
-
|
|
691
|
+
elif event.trigger.kind in mm_constants.STREAM_TRIGGER_KINDS:
|
|
692
692
|
# Runs controller worker:
|
|
693
693
|
context.user_data.monitor_app_controller.run(event)
|
|
694
|
+
else:
|
|
695
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
696
|
+
"Wrong trigger kind for model monitoring controller"
|
|
697
|
+
)
|
|
694
698
|
|
|
695
699
|
|
|
696
700
|
def init_context(context):
|
|
@@ -19,6 +19,7 @@ import mlrun.common.schemas.secret
|
|
|
19
19
|
import mlrun.datastore.datastore_profile
|
|
20
20
|
import mlrun.errors
|
|
21
21
|
import mlrun.model_monitoring.helpers
|
|
22
|
+
from mlrun.datastore.datastore_profile import DatastoreProfile
|
|
22
23
|
|
|
23
24
|
from .base import TSDBConnector
|
|
24
25
|
|
|
@@ -29,10 +30,13 @@ class ObjectTSDBFactory(enum.Enum):
|
|
|
29
30
|
v3io_tsdb = "v3io-tsdb"
|
|
30
31
|
tdengine = "tdengine"
|
|
31
32
|
|
|
32
|
-
def to_tsdb_connector(
|
|
33
|
+
def to_tsdb_connector(
|
|
34
|
+
self, project: str, profile: DatastoreProfile, **kwargs
|
|
35
|
+
) -> TSDBConnector:
|
|
33
36
|
"""
|
|
34
37
|
Return a TSDBConnector object based on the provided enum value.
|
|
35
38
|
:param project: The name of the project.
|
|
39
|
+
:param profile: Datastore profile containing DSN and credentials for TSDB connection
|
|
36
40
|
:return: `TSDBConnector` object.
|
|
37
41
|
"""
|
|
38
42
|
|
|
@@ -51,7 +55,7 @@ class ObjectTSDBFactory(enum.Enum):
|
|
|
51
55
|
|
|
52
56
|
from .tdengine.tdengine_connector import TDEngineConnector
|
|
53
57
|
|
|
54
|
-
return TDEngineConnector(project=project, **kwargs)
|
|
58
|
+
return TDEngineConnector(project=project, profile=profile, **kwargs)
|
|
55
59
|
|
|
56
60
|
@classmethod
|
|
57
61
|
def _missing_(cls, value: typing.Any):
|
|
@@ -87,12 +91,10 @@ def get_tsdb_connector(
|
|
|
87
91
|
kwargs = {}
|
|
88
92
|
if isinstance(profile, mlrun.datastore.datastore_profile.DatastoreProfileV3io):
|
|
89
93
|
tsdb_connector_type = mlrun.common.schemas.model_monitoring.TSDBTarget.V3IO_TSDB
|
|
90
|
-
kwargs["v3io_access_key"] = profile.v3io_access_key
|
|
91
94
|
elif isinstance(
|
|
92
95
|
profile, mlrun.datastore.datastore_profile.TDEngineDatastoreProfile
|
|
93
96
|
):
|
|
94
97
|
tsdb_connector_type = mlrun.common.schemas.model_monitoring.TSDBTarget.TDEngine
|
|
95
|
-
kwargs["connection_string"] = profile.dsn()
|
|
96
98
|
else:
|
|
97
99
|
extra_message = (
|
|
98
100
|
""
|
|
@@ -109,4 +111,6 @@ def get_tsdb_connector(
|
|
|
109
111
|
tsdb_connector_factory = ObjectTSDBFactory(tsdb_connector_type)
|
|
110
112
|
|
|
111
113
|
# Convert into TSDB connector object
|
|
112
|
-
return tsdb_connector_factory.to_tsdb_connector(
|
|
114
|
+
return tsdb_connector_factory.to_tsdb_connector(
|
|
115
|
+
project=project, profile=profile, **kwargs
|
|
116
|
+
)
|