mlrun 1.8.0rc44__py3-none-any.whl → 1.8.0rc45__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/config.py +6 -0
- mlrun/db/base.py +3 -7
- mlrun/db/httpdb.py +16 -18
- mlrun/db/nopdb.py +0 -5
- mlrun/model_monitoring/applications/histogram_data_drift.py +10 -18
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +46 -20
- mlrun/model_monitoring/writer.py +1 -1
- mlrun/projects/project.py +24 -27
- mlrun/runtimes/nuclio/application/reverse_proxy.go +66 -64
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc44.dist-info → mlrun-1.8.0rc45.dist-info}/METADATA +3 -2
- {mlrun-1.8.0rc44.dist-info → mlrun-1.8.0rc45.dist-info}/RECORD +16 -16
- {mlrun-1.8.0rc44.dist-info → mlrun-1.8.0rc45.dist-info}/WHEEL +1 -1
- {mlrun-1.8.0rc44.dist-info → mlrun-1.8.0rc45.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc44.dist-info → mlrun-1.8.0rc45.dist-info/licenses}/LICENSE +0 -0
- {mlrun-1.8.0rc44.dist-info → mlrun-1.8.0rc45.dist-info}/top_level.txt +0 -0
mlrun/config.py
CHANGED
|
@@ -549,6 +549,10 @@ default_config = {
|
|
|
549
549
|
},
|
|
550
550
|
},
|
|
551
551
|
"model_endpoint_monitoring": {
|
|
552
|
+
# Scaling Rule
|
|
553
|
+
# The fundamental scaling rule to maintain is: Shards/Partitions = Replicas * Workers
|
|
554
|
+
# In other words, the number of shards (V3IO) or partitions (Kafka) must be equal to the
|
|
555
|
+
# total number of worker processes across all pods.
|
|
552
556
|
"serving_stream": {
|
|
553
557
|
"v3io": {
|
|
554
558
|
"shard_count": 2,
|
|
@@ -822,6 +826,8 @@ default_config = {
|
|
|
822
826
|
# maximum allowed alert config cache size in alert's CRUD
|
|
823
827
|
# for the best performance, it is recommended to set this value to the maximum number of alerts
|
|
824
828
|
"max_allowed_cache_size": 20000,
|
|
829
|
+
# default limit for listing alert configs
|
|
830
|
+
"default_list_alert_configs_limit": 2000,
|
|
825
831
|
},
|
|
826
832
|
"auth_with_client_id": {
|
|
827
833
|
"enabled": False,
|
mlrun/db/base.py
CHANGED
|
@@ -889,7 +889,9 @@ class RunDBInterface(ABC):
|
|
|
889
889
|
pass
|
|
890
890
|
|
|
891
891
|
@abstractmethod
|
|
892
|
-
def list_alerts_configs(
|
|
892
|
+
def list_alerts_configs(
|
|
893
|
+
self, project="", limit: Optional[int] = None, offset: Optional[int] = None
|
|
894
|
+
):
|
|
893
895
|
pass
|
|
894
896
|
|
|
895
897
|
@abstractmethod
|
|
@@ -1105,12 +1107,6 @@ class RunDBInterface(ABC):
|
|
|
1105
1107
|
) -> bool:
|
|
1106
1108
|
pass
|
|
1107
1109
|
|
|
1108
|
-
@abstractmethod
|
|
1109
|
-
def deploy_histogram_data_drift_app(
|
|
1110
|
-
self, project: str, image: str = "mlrun/mlrun"
|
|
1111
|
-
) -> None:
|
|
1112
|
-
pass
|
|
1113
|
-
|
|
1114
1110
|
@abstractmethod
|
|
1115
1111
|
def set_model_monitoring_credentials(
|
|
1116
1112
|
self,
|
mlrun/db/httpdb.py
CHANGED
|
@@ -4080,21 +4080,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4080
4080
|
deletion_failed = True
|
|
4081
4081
|
return not deletion_failed
|
|
4082
4082
|
|
|
4083
|
-
def deploy_histogram_data_drift_app(
|
|
4084
|
-
self, project: str, image: str = "mlrun/mlrun"
|
|
4085
|
-
) -> None:
|
|
4086
|
-
"""
|
|
4087
|
-
Deploy the histogram data drift application.
|
|
4088
|
-
|
|
4089
|
-
:param project: Project name.
|
|
4090
|
-
:param image: The image on which the application will run.
|
|
4091
|
-
"""
|
|
4092
|
-
self.api_call(
|
|
4093
|
-
method=mlrun.common.types.HTTPMethod.PUT,
|
|
4094
|
-
path=f"projects/{project}/model-monitoring/histogram-data-drift-app",
|
|
4095
|
-
params={"image": image},
|
|
4096
|
-
)
|
|
4097
|
-
|
|
4098
4083
|
def set_model_monitoring_credentials(
|
|
4099
4084
|
self,
|
|
4100
4085
|
project: str,
|
|
@@ -4818,20 +4803,33 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4818
4803
|
response = self.api_call("GET", endpoint_path, error_message)
|
|
4819
4804
|
return AlertConfig.from_dict(response.json())
|
|
4820
4805
|
|
|
4821
|
-
def list_alerts_configs(
|
|
4806
|
+
def list_alerts_configs(
|
|
4807
|
+
self, project="", limit: Optional[int] = None, offset: Optional[int] = None
|
|
4808
|
+
) -> list[AlertConfig]:
|
|
4822
4809
|
"""
|
|
4823
4810
|
Retrieve list of alerts of a project.
|
|
4824
4811
|
|
|
4825
4812
|
:param project: The project name.
|
|
4813
|
+
:param limit: The maximum number of alerts to return.
|
|
4814
|
+
Defaults to `mlconf.alerts.default_list_alert_configs_limit` if not provided.
|
|
4815
|
+
:param offset: The number of alerts to skip.
|
|
4826
4816
|
|
|
4827
4817
|
:returns: All the alerts objects of the project.
|
|
4828
4818
|
"""
|
|
4829
4819
|
project = project or config.default_project
|
|
4830
4820
|
endpoint_path = f"projects/{project}/alerts"
|
|
4831
4821
|
error_message = f"get alerts {project}/alerts"
|
|
4832
|
-
|
|
4822
|
+
params = {}
|
|
4823
|
+
# TODO: Deprecate limit and offset when pagination is implemented
|
|
4824
|
+
if limit:
|
|
4825
|
+
params["page-size"] = limit
|
|
4826
|
+
if offset:
|
|
4827
|
+
params["offset"] = offset
|
|
4828
|
+
response = self.api_call(
|
|
4829
|
+
"GET", endpoint_path, error_message, params=params
|
|
4830
|
+
).json()
|
|
4833
4831
|
results = []
|
|
4834
|
-
for item in response:
|
|
4832
|
+
for item in response.get("alerts", []):
|
|
4835
4833
|
results.append(AlertConfig(**item))
|
|
4836
4834
|
return results
|
|
4837
4835
|
|
mlrun/db/nopdb.py
CHANGED
|
@@ -883,11 +883,6 @@ class NopDB(RunDBInterface):
|
|
|
883
883
|
) -> bool:
|
|
884
884
|
pass
|
|
885
885
|
|
|
886
|
-
def deploy_histogram_data_drift_app(
|
|
887
|
-
self, project: str, image: str = "mlrun/mlrun"
|
|
888
|
-
) -> None:
|
|
889
|
-
pass
|
|
890
|
-
|
|
891
886
|
def set_model_monitoring_credentials(
|
|
892
887
|
self,
|
|
893
888
|
project: str,
|
|
@@ -107,16 +107,14 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
|
|
|
107
107
|
* JSON with the general drift value per feature, produced by default.
|
|
108
108
|
* Plotly table with the various metrics and histograms per feature (disabled by default due to performance issues).
|
|
109
109
|
|
|
110
|
-
This application is deployed by default when calling
|
|
111
|
-
|
|
112
|
-
.. code-block:: python
|
|
113
|
-
|
|
114
|
-
project.enable_model_monitoring()
|
|
115
|
-
|
|
110
|
+
This application is deployed by default when calling
|
|
111
|
+
:py:func:`~mlrun.projects.MlrunProject.enable_model_monitoring`.
|
|
116
112
|
To avoid it, pass :code:`deploy_histogram_data_drift_app=False`.
|
|
117
113
|
|
|
118
114
|
If you want to change the application defaults, such as the classifier or which artifacts to produce, you
|
|
119
115
|
need to inherit from this class and deploy it as any other model monitoring application.
|
|
116
|
+
Please make sure to keep the default application name. This ensures that the full functionality of the application,
|
|
117
|
+
including the statistics view in the UI, is available.
|
|
120
118
|
"""
|
|
121
119
|
|
|
122
120
|
NAME: Final[str] = HistogramDataDriftApplicationConstants.NAME
|
|
@@ -140,8 +138,8 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
|
|
|
140
138
|
produce_plotly_artifact: bool = False,
|
|
141
139
|
) -> None:
|
|
142
140
|
"""
|
|
143
|
-
:param value_classifier: Classifier object that adheres to the
|
|
144
|
-
If not provided, the default
|
|
141
|
+
:param value_classifier: Classifier object that adheres to the :py:class:`~ValueClassifier` protocol.
|
|
142
|
+
If not provided, the default :py:class:`~DataDriftClassifier` is used.
|
|
145
143
|
"""
|
|
146
144
|
self._value_classifier = value_classifier or DataDriftClassifier()
|
|
147
145
|
assert self._REQUIRED_METRICS <= set(
|
|
@@ -181,10 +179,7 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
|
|
|
181
179
|
return metrics_per_feature
|
|
182
180
|
|
|
183
181
|
def _get_general_drift_result(
|
|
184
|
-
self,
|
|
185
|
-
metrics: list[mm_results.ModelMonitoringApplicationMetric],
|
|
186
|
-
monitoring_context: mm_context.MonitoringApplicationContext,
|
|
187
|
-
metrics_per_feature: DataFrame,
|
|
182
|
+
self, metrics: list[mm_results.ModelMonitoringApplicationMetric]
|
|
188
183
|
) -> mm_results.ModelMonitoringApplicationResult:
|
|
189
184
|
"""Get the general drift result from the metrics list"""
|
|
190
185
|
value = cast(
|
|
@@ -237,7 +232,8 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
|
|
|
237
232
|
monitoring_context: mm_context.MonitoringApplicationContext,
|
|
238
233
|
) -> list[mm_results._ModelMonitoringApplicationStats]:
|
|
239
234
|
"""
|
|
240
|
-
list the
|
|
235
|
+
Return a list of the statistics.
|
|
236
|
+
|
|
241
237
|
:param metrics: the calculated metrics
|
|
242
238
|
:param metrics_per_feature: metric calculated per feature
|
|
243
239
|
:param monitoring_context: context object for current monitoring application
|
|
@@ -376,11 +372,7 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
|
|
|
376
372
|
)
|
|
377
373
|
monitoring_context.logger.debug("Computing average per metric")
|
|
378
374
|
metrics = self._get_metrics(metrics_per_feature)
|
|
379
|
-
result = self._get_general_drift_result(
|
|
380
|
-
metrics=metrics,
|
|
381
|
-
monitoring_context=monitoring_context,
|
|
382
|
-
metrics_per_feature=metrics_per_feature,
|
|
383
|
-
)
|
|
375
|
+
result = self._get_general_drift_result(metrics=metrics)
|
|
384
376
|
stats = self._get_stats(
|
|
385
377
|
metrics=metrics,
|
|
386
378
|
monitoring_context=monitoring_context,
|
|
@@ -33,7 +33,12 @@ _TSDB_BE = "tsdb"
|
|
|
33
33
|
_TSDB_RATE = "1/s"
|
|
34
34
|
_CONTAINER = "users"
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
V3IO_FRAMESD_MEPS_LIMIT = (
|
|
37
|
+
200 # Maximum number of model endpoints per single request when using V3IO Frames
|
|
38
|
+
)
|
|
39
|
+
V3IO_CLIENT_MEPS_LIMIT = (
|
|
40
|
+
150 # Maximum number of model endpoints per single request when using V3IO Client
|
|
41
|
+
)
|
|
37
42
|
|
|
38
43
|
|
|
39
44
|
def _is_no_schema_error(exc: v3io_frames.Error) -> bool:
|
|
@@ -475,8 +480,8 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
475
480
|
tables = mm_schemas.V3IOTSDBTables.list()
|
|
476
481
|
|
|
477
482
|
# Split the endpoint ids into chunks to avoid exceeding the v3io-engine filter-expression limit
|
|
478
|
-
for i in range(0, len(endpoint_ids),
|
|
479
|
-
endpoint_id_chunk = endpoint_ids[i : i +
|
|
483
|
+
for i in range(0, len(endpoint_ids), V3IO_FRAMESD_MEPS_LIMIT):
|
|
484
|
+
endpoint_id_chunk = endpoint_ids[i : i + V3IO_FRAMESD_MEPS_LIMIT]
|
|
480
485
|
filter_query = f"endpoint_id IN({str(endpoint_id_chunk)[1:-1]}) "
|
|
481
486
|
for table in tables:
|
|
482
487
|
try:
|
|
@@ -684,11 +689,11 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
684
689
|
if isinstance(endpoint_id, str):
|
|
685
690
|
return f"endpoint_id=='{endpoint_id}'"
|
|
686
691
|
elif isinstance(endpoint_id, list):
|
|
687
|
-
if len(endpoint_id) >
|
|
692
|
+
if len(endpoint_id) > V3IO_FRAMESD_MEPS_LIMIT:
|
|
688
693
|
logger.info(
|
|
689
694
|
"The number of endpoint ids exceeds the v3io-engine filter-expression limit, "
|
|
690
695
|
"retrieving all the model endpoints from the db.",
|
|
691
|
-
limit=
|
|
696
|
+
limit=V3IO_FRAMESD_MEPS_LIMIT,
|
|
692
697
|
amount=len(endpoint_id),
|
|
693
698
|
)
|
|
694
699
|
return None
|
|
@@ -880,23 +885,41 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
880
885
|
start: Optional[datetime] = None,
|
|
881
886
|
end: Optional[datetime] = None,
|
|
882
887
|
) -> dict[str, float]:
|
|
883
|
-
if isinstance(endpoint_ids, str):
|
|
884
|
-
filter_expression = f"__name=='{endpoint_ids}'"
|
|
885
|
-
else:
|
|
886
|
-
filter_expression = " OR ".join(
|
|
887
|
-
[f"__name=='{endpoint_id}'" for endpoint_id in endpoint_ids]
|
|
888
|
-
)
|
|
889
|
-
|
|
890
888
|
# Get the last request timestamp for each endpoint from the KV table.
|
|
891
889
|
# The result of the query is a list of dictionaries,
|
|
892
890
|
# each dictionary contains the endpoint id and the last request timestamp.
|
|
891
|
+
last_request_timestamps = {}
|
|
892
|
+
if isinstance(endpoint_ids, str):
|
|
893
|
+
endpoint_ids = [endpoint_ids]
|
|
893
894
|
|
|
894
895
|
try:
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
896
|
+
if len(endpoint_ids) > V3IO_CLIENT_MEPS_LIMIT:
|
|
897
|
+
logger.warning(
|
|
898
|
+
"The number of endpoint ids exceeds the v3io-engine filter-expression limit, "
|
|
899
|
+
"retrieving last request for all the model endpoints from the KV table.",
|
|
900
|
+
limit=V3IO_CLIENT_MEPS_LIMIT,
|
|
901
|
+
amount=len(endpoint_ids),
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
res = self.v3io_client.kv.new_cursor(
|
|
905
|
+
container=self.container,
|
|
906
|
+
table_path=self.last_request_table,
|
|
907
|
+
).all()
|
|
908
|
+
last_request_timestamps.update(
|
|
909
|
+
{d["__name"]: d["last_request_timestamp"] for d in res}
|
|
910
|
+
)
|
|
911
|
+
else:
|
|
912
|
+
filter_expression = " OR ".join(
|
|
913
|
+
[f"__name=='{endpoint_id}'" for endpoint_id in endpoint_ids]
|
|
914
|
+
)
|
|
915
|
+
res = self.v3io_client.kv.new_cursor(
|
|
916
|
+
container=self.container,
|
|
917
|
+
table_path=self.last_request_table,
|
|
918
|
+
filter_expression=filter_expression,
|
|
919
|
+
).all()
|
|
920
|
+
last_request_timestamps.update(
|
|
921
|
+
{d["__name"]: d["last_request_timestamp"] for d in res}
|
|
922
|
+
)
|
|
900
923
|
except Exception as e:
|
|
901
924
|
logger.warning(
|
|
902
925
|
"Failed to get last request timestamp from V3IO KV table.",
|
|
@@ -904,9 +927,8 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
904
927
|
project=self.project,
|
|
905
928
|
table=self.last_request_table,
|
|
906
929
|
)
|
|
907
|
-
return {}
|
|
908
930
|
|
|
909
|
-
return
|
|
931
|
+
return last_request_timestamps
|
|
910
932
|
|
|
911
933
|
def get_drift_status(
|
|
912
934
|
self,
|
|
@@ -1131,4 +1153,8 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
1131
1153
|
endpoint_ids=list(model_endpoint_objects_by_uid.keys())
|
|
1132
1154
|
)
|
|
1133
1155
|
for uid, mep in model_endpoint_objects_by_uid.items():
|
|
1134
|
-
|
|
1156
|
+
# Set the last request timestamp to the MEP object. If not found, keep the existing value from the
|
|
1157
|
+
# DB (relevant for batch EP).
|
|
1158
|
+
mep.status.last_request = last_request_dictionary.get(
|
|
1159
|
+
uid, mep.status.last_request
|
|
1160
|
+
)
|
mlrun/model_monitoring/writer.py
CHANGED
mlrun/projects/project.py
CHANGED
|
@@ -2451,7 +2451,22 @@ class MlrunProject(ModelObj):
|
|
|
2451
2451
|
:param image: The image of the model monitoring controller, writer, monitoring
|
|
2452
2452
|
stream & histogram data drift functions, which are real time nuclio
|
|
2453
2453
|
functions. By default, the image is mlrun/mlrun.
|
|
2454
|
-
:param deploy_histogram_data_drift_app: If true, deploy the default histogram-based data drift application
|
|
2454
|
+
:param deploy_histogram_data_drift_app: If true, deploy the default histogram-based data drift application:
|
|
2455
|
+
:py:class:`~mlrun.model_monitoring.applications.histogram_data_drift.HistogramDataDriftApplication`.
|
|
2456
|
+
If false, and you want to deploy the histogram data drift application
|
|
2457
|
+
afterwards, you may use the
|
|
2458
|
+
:py:func:`~set_model_monitoring_function` method::
|
|
2459
|
+
|
|
2460
|
+
import mlrun.model_monitoring.applications.histogram_data_drift as histogram_data_drift
|
|
2461
|
+
|
|
2462
|
+
hist_app = project.set_model_monitoring_function(
|
|
2463
|
+
name=histogram_data_drift.HistogramDataDriftApplicationConstants.NAME, # keep the default name
|
|
2464
|
+
func=histogram_data_drift.__file__,
|
|
2465
|
+
application_class=histogram_data_drift.HistogramDataDriftApplication.__name__,
|
|
2466
|
+
)
|
|
2467
|
+
|
|
2468
|
+
project.deploy_function(hist_app)
|
|
2469
|
+
|
|
2455
2470
|
:param wait_for_deployment: If true, return only after the deployment is done on the backend.
|
|
2456
2471
|
Otherwise, deploy the model monitoring infrastructure on the
|
|
2457
2472
|
background, including the histogram data drift app if selected.
|
|
@@ -2488,30 +2503,6 @@ class MlrunProject(ModelObj):
|
|
|
2488
2503
|
)
|
|
2489
2504
|
self._wait_for_functions_deployment(deployment_functions)
|
|
2490
2505
|
|
|
2491
|
-
def deploy_histogram_data_drift_app(
|
|
2492
|
-
self,
|
|
2493
|
-
*,
|
|
2494
|
-
image: str = "mlrun/mlrun",
|
|
2495
|
-
db: Optional[mlrun.db.RunDBInterface] = None,
|
|
2496
|
-
wait_for_deployment: bool = False,
|
|
2497
|
-
) -> None:
|
|
2498
|
-
"""
|
|
2499
|
-
Deploy the histogram data drift application.
|
|
2500
|
-
|
|
2501
|
-
:param image: The image on which the application will run.
|
|
2502
|
-
:param db: An optional DB object.
|
|
2503
|
-
:param wait_for_deployment: If true, return only after the deployment is done on the backend.
|
|
2504
|
-
Otherwise, deploy the application on the background.
|
|
2505
|
-
"""
|
|
2506
|
-
if db is None:
|
|
2507
|
-
db = mlrun.db.get_run_db(secrets=self._secrets)
|
|
2508
|
-
db.deploy_histogram_data_drift_app(project=self.name, image=image)
|
|
2509
|
-
|
|
2510
|
-
if wait_for_deployment:
|
|
2511
|
-
self._wait_for_functions_deployment(
|
|
2512
|
-
[mm_constants.HistogramDataDriftApplicationConstants.NAME]
|
|
2513
|
-
)
|
|
2514
|
-
|
|
2515
2506
|
def update_model_monitoring_controller(
|
|
2516
2507
|
self,
|
|
2517
2508
|
base_period: int = 10,
|
|
@@ -5034,14 +5025,20 @@ class MlrunProject(ModelObj):
|
|
|
5034
5025
|
db = mlrun.db.get_run_db(secrets=self._secrets)
|
|
5035
5026
|
return db.get_alert_config(alert_name, self.metadata.name)
|
|
5036
5027
|
|
|
5037
|
-
def list_alerts_configs(
|
|
5028
|
+
def list_alerts_configs(
|
|
5029
|
+
self, limit: Optional[int] = None, offset: Optional[int] = None
|
|
5030
|
+
) -> list[AlertConfig]:
|
|
5038
5031
|
"""
|
|
5039
5032
|
Retrieve list of alerts of a project.
|
|
5040
5033
|
|
|
5034
|
+
:param limit: The maximum number of alerts to return.
|
|
5035
|
+
Defaults to `mlconf.alerts.default_list_alert_configs_limit` if not provided.
|
|
5036
|
+
:param offset: The number of alerts to skip before starting to collect alerts.
|
|
5037
|
+
|
|
5041
5038
|
:return: All the alerts objects of the project.
|
|
5042
5039
|
"""
|
|
5043
5040
|
db = mlrun.db.get_run_db(secrets=self._secrets)
|
|
5044
|
-
return db.list_alerts_configs(self.metadata.name)
|
|
5041
|
+
return db.list_alerts_configs(self.metadata.name, limit=limit, offset=offset)
|
|
5045
5042
|
|
|
5046
5043
|
def delete_alert_config(
|
|
5047
5044
|
self, alert_data: AlertConfig = None, alert_name: Optional[str] = None
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// you may not use this file except in compliance with the License.
|
|
5
5
|
// You may obtain a copy of the License at
|
|
6
6
|
//
|
|
7
|
-
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
8
|
//
|
|
9
9
|
// Unless required by applicable law or agreed to in writing, software
|
|
10
10
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
@@ -14,82 +14,84 @@
|
|
|
14
14
|
package main
|
|
15
15
|
|
|
16
16
|
import (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
"bytes"
|
|
18
|
+
"fmt"
|
|
19
|
+
"net/http"
|
|
20
|
+
"net/http/httptest"
|
|
21
|
+
"net/http/httputil"
|
|
22
|
+
"net/url"
|
|
23
|
+
"os"
|
|
24
|
+
"strings"
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
nuclio "github.com/nuclio/nuclio-sdk-go"
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
func Handler(context *nuclio.Context, event nuclio.Event) (interface{}, error) {
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
reverseProxy := context.UserData.(map[string]interface{})["reverseProxy"].(*httputil.ReverseProxy)
|
|
31
|
+
sidecarUrl := context.UserData.(map[string]interface{})["server"].(string)
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
// populate reverse proxy http request
|
|
34
|
+
httpRequest, err := http.NewRequest(event.GetMethod(), event.GetPath(), bytes.NewReader(event.GetBody()))
|
|
35
|
+
if err != nil {
|
|
36
|
+
context.Logger.ErrorWith("Failed to create a reverse proxy request")
|
|
37
|
+
return nil, err
|
|
38
|
+
}
|
|
39
|
+
for k, v := range event.GetHeaders() {
|
|
40
|
+
httpRequest.Header[k] = []string{v.(string)}
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
// populate query params
|
|
44
|
+
query := httpRequest.URL.Query()
|
|
45
|
+
for k, v := range event.GetFields() {
|
|
46
|
+
query.Set(k, v.(string))
|
|
47
|
+
}
|
|
48
|
+
httpRequest.URL.RawQuery = query.Encode()
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
recorder := httptest.NewRecorder()
|
|
51
|
+
reverseProxy.ServeHTTP(recorder, httpRequest)
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
// send request to sidecar
|
|
54
|
+
context.Logger.DebugWith("Forwarding request to sidecar",
|
|
55
|
+
"sidecarUrl", sidecarUrl,
|
|
56
|
+
"method", event.GetMethod())
|
|
57
|
+
response := recorder.Result()
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
headers := make(map[string]interface{})
|
|
60
|
+
for key, value := range response.Header {
|
|
61
|
+
headers[key] = value[0]
|
|
62
|
+
}
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
// let the processor calculate the content length
|
|
65
|
+
delete(headers, "Content-Length")
|
|
66
|
+
return nuclio.Response{
|
|
67
|
+
StatusCode: response.StatusCode,
|
|
68
|
+
Body: recorder.Body.Bytes(),
|
|
69
|
+
ContentType: response.Header.Get("Content-Type"),
|
|
70
|
+
Headers: headers,
|
|
71
|
+
}, nil
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
func InitContext(context *nuclio.Context) error {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
sidecarHost := os.Getenv("SIDECAR_HOST")
|
|
76
|
+
sidecarPort := os.Getenv("SIDECAR_PORT")
|
|
77
|
+
if sidecarHost == "" {
|
|
78
|
+
sidecarHost = "http://localhost"
|
|
79
|
+
} else if !strings.Contains(sidecarHost, "://") {
|
|
80
|
+
sidecarHost = fmt.Sprintf("http://%s", sidecarHost)
|
|
81
|
+
}
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
// url for request forwarding
|
|
84
|
+
sidecarUrl := fmt.Sprintf("%s:%s", sidecarHost, sidecarPort)
|
|
85
|
+
parsedURL, err := url.Parse(sidecarUrl)
|
|
86
|
+
if err != nil {
|
|
87
|
+
context.Logger.ErrorWith("Failed to parse sidecar url", "sidecarUrl", sidecarUrl)
|
|
88
|
+
return err
|
|
89
|
+
}
|
|
90
|
+
reverseProxy := httputil.NewSingleHostReverseProxy(parsedURL)
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
context.UserData = map[string]interface{}{
|
|
93
|
+
"server": sidecarUrl,
|
|
94
|
+
"reverseProxy": reverseProxy,
|
|
95
|
+
}
|
|
96
|
+
return nil
|
|
95
97
|
}
|
mlrun/utils/version/version.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mlrun
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.0rc45
|
|
4
4
|
Summary: Tracking and config of machine learning runs
|
|
5
5
|
Home-page: https://github.com/mlrun/mlrun
|
|
6
6
|
Author: Yaron Haviv
|
|
@@ -240,6 +240,7 @@ Dynamic: description-content-type
|
|
|
240
240
|
Dynamic: home-page
|
|
241
241
|
Dynamic: keywords
|
|
242
242
|
Dynamic: license
|
|
243
|
+
Dynamic: license-file
|
|
243
244
|
Dynamic: provides-extra
|
|
244
245
|
Dynamic: requires-dist
|
|
245
246
|
Dynamic: requires-python
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
mlrun/__init__.py,sha256=Cqm9U9eCEdLpMejhU2BEhubu0mHL71igJJIwYa738EA,7450
|
|
2
2
|
mlrun/__main__.py,sha256=0NDzPf9VFRO8KFfGgb8mkGUPIDS285aASV8Hbxs-ND0,45920
|
|
3
|
-
mlrun/config.py,sha256=
|
|
3
|
+
mlrun/config.py,sha256=JEE29XflgA8NsdAOeSmIFBKhS_r-FKHUFwMjcSOYq30,71820
|
|
4
4
|
mlrun/errors.py,sha256=LkcbXTLANGdsgo2CRX2pdbyNmt--lMsjGv0XZMgP-Nc,8222
|
|
5
5
|
mlrun/execution.py,sha256=FUktsD3puSFjc3LZJU35b-OmFBrBPBNntViCLQVuwnk,50008
|
|
6
6
|
mlrun/features.py,sha256=ReBaNGsBYXqcbgI012n-SO_j6oHIbk_Vpv0CGPXbUmo,15842
|
|
@@ -108,10 +108,10 @@ mlrun/datastore/wasbfs/__init__.py,sha256=s5Ul-0kAhYqFjKDR2X0O2vDGDbLQQduElb32Ev
|
|
|
108
108
|
mlrun/datastore/wasbfs/fs.py,sha256=ge8NK__5vTcFT-krI155_8RDUywQw4SIRX6BWATXy9Q,6299
|
|
109
109
|
mlrun/db/__init__.py,sha256=WqJ4x8lqJ7ZoKbhEyFqkYADd9P6E3citckx9e9ZLcIU,1163
|
|
110
110
|
mlrun/db/auth_utils.py,sha256=hpg8D2r82oN0BWabuWN04BTNZ7jYMAF242YSUpK7LFM,5211
|
|
111
|
-
mlrun/db/base.py,sha256=
|
|
111
|
+
mlrun/db/base.py,sha256=Uo28PyTRkauFLGHZPF6IkDbF-WyEA03GObC3su87Pr8,30716
|
|
112
112
|
mlrun/db/factory.py,sha256=yP2vVmveUE7LYTCHbS6lQIxP9rW--zdISWuPd_I3d_4,2111
|
|
113
|
-
mlrun/db/httpdb.py,sha256=
|
|
114
|
-
mlrun/db/nopdb.py,sha256=
|
|
113
|
+
mlrun/db/httpdb.py,sha256=l4qdr7MWfLHuq3gV5fHQspLbAxXbJinGlN0kO-sqftA,231598
|
|
114
|
+
mlrun/db/nopdb.py,sha256=TwyU1B6Z4S6n5iu6pftxRqimhvroz1PnPwFhAoXxr4c,27098
|
|
115
115
|
mlrun/feature_store/__init__.py,sha256=SlI845bWt6xX34SXunHHqhmFAR9-5v2ak8N-qpcAPGo,1328
|
|
116
116
|
mlrun/feature_store/api.py,sha256=qKj5Tk6prTab6XWatWhBuPRVp0eJEctoxRMN2wz48vA,32168
|
|
117
117
|
mlrun/feature_store/common.py,sha256=Z7USI-d1fo0iwBMsqMBtJflJfyuiV3BLoDXQPSAoBAs,12826
|
|
@@ -224,12 +224,12 @@ mlrun/model_monitoring/features_drift_table.py,sha256=c6GpKtpOJbuT1u5uMWDL_S-6N4
|
|
|
224
224
|
mlrun/model_monitoring/helpers.py,sha256=Q4vcc7x41lCJdFQIE8UFPY0WIQ8a-4tSGhziMA4ib4w,22003
|
|
225
225
|
mlrun/model_monitoring/stream_processing.py,sha256=4M0H4txMlsC2Q5iKTPp992KWoNPAJjPHj9rqWhXbl8w,33321
|
|
226
226
|
mlrun/model_monitoring/tracking_policy.py,sha256=PBIGrUYWrwcE5gwXupBIVzOb0QRRwPJsgQm_yLGQxB4,5595
|
|
227
|
-
mlrun/model_monitoring/writer.py,sha256=
|
|
227
|
+
mlrun/model_monitoring/writer.py,sha256=ibbhvfSHb8Reqlb7RGFEAUNM4iTyK1gk8-2m46mP6VM,8428
|
|
228
228
|
mlrun/model_monitoring/applications/__init__.py,sha256=xDBxkBjl-whHSG_4t1mLkxiypLH-fzn8TmAW9Mjo2uI,759
|
|
229
229
|
mlrun/model_monitoring/applications/_application_steps.py,sha256=PxULZznKW66Oq-fKaraOAbsTuGnV0zgXh6_91wX3KUo,8367
|
|
230
230
|
mlrun/model_monitoring/applications/base.py,sha256=7XL12idItWkoE3CJ_48F6cwVx5pJH3bgfG92hb8LcN8,24872
|
|
231
231
|
mlrun/model_monitoring/applications/context.py,sha256=Wou9lviSETjEqyMoIAi0Ko58luRkx0uy3ZDUVyRheNA,16144
|
|
232
|
-
mlrun/model_monitoring/applications/histogram_data_drift.py,sha256=
|
|
232
|
+
mlrun/model_monitoring/applications/histogram_data_drift.py,sha256=09t0tfC35W0SeJA3fzN29pJiB6G-V_8GlcvULVq6H9Q,15179
|
|
233
233
|
mlrun/model_monitoring/applications/results.py,sha256=_qmj6TWT0SR2bi7gUyRKBU418eGgGoLW2_hTJ7S-ock,5782
|
|
234
234
|
mlrun/model_monitoring/applications/evidently/__init__.py,sha256=-DqdPnBSrjZhFvKOu_Ie3MiFvlur9sPTZpZ1u0_1AE8,690
|
|
235
235
|
mlrun/model_monitoring/applications/evidently/base.py,sha256=C8402vQJH7jmY-i49DnYjy6p6dETWex4Tdi8ylFLecA,5097
|
|
@@ -245,7 +245,7 @@ mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py,sha256=Uadj0UvAmln
|
|
|
245
245
|
mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py,sha256=gDK6nNbAwTprs2UAI1r7r6loZB40I_8iQ2JvedvAs78,37765
|
|
246
246
|
mlrun/model_monitoring/db/tsdb/v3io/__init__.py,sha256=aL3bfmQsUQ-sbvKGdNihFj8gLCK3mSys0qDcXtYOwgc,616
|
|
247
247
|
mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py,sha256=_-zo9relCDtjGgievxAcAP9gVN9nDWs8BzGtFwTjb9M,6284
|
|
248
|
-
mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py,sha256=
|
|
248
|
+
mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py,sha256=GLxg8N1eK7agKgPanOoA1JNbXEH9_kesNRzAPYOgtAQ,46033
|
|
249
249
|
mlrun/model_monitoring/metrics/__init__.py,sha256=6CsTXAxeLbbf8yfCADTaxmiavqwrLEdYFJ-qc5kgDAY,569
|
|
250
250
|
mlrun/model_monitoring/metrics/histogram_distance.py,sha256=E9_WIl2vd6qNvoHVHoFcnuQk3ekbFWOdi8aU7sHrfk4,4724
|
|
251
251
|
mlrun/package/__init__.py,sha256=v7VDyK9kDOOuDvFo4oiGV2fx-vM1KL7fdN9pGLakhUQ,7008
|
|
@@ -270,7 +270,7 @@ mlrun/platforms/iguazio.py,sha256=6VBTq8eQ3mzT96tzjYhAtcMQ2VjF4x8LpIPW5DAcX2Q,13
|
|
|
270
270
|
mlrun/projects/__init__.py,sha256=0Krf0WIKfnZa71WthYOg0SoaTodGg3sV_hK3f_OlTPI,1220
|
|
271
271
|
mlrun/projects/operations.py,sha256=TzPbTYBgmYrjxTKP_wOtBJYFFFwDCQtaVvF1Snr0TfM,20029
|
|
272
272
|
mlrun/projects/pipelines.py,sha256=wud7ezeEmhIJvfYE_wzQbA4ygEfGXHtbOtoOpan6poY,48556
|
|
273
|
-
mlrun/projects/project.py,sha256=
|
|
273
|
+
mlrun/projects/project.py,sha256=H-mjTHqV_T9PhfCfGQRNm1R-7cM-7boS1Jd1TN9SyYo,235337
|
|
274
274
|
mlrun/runtimes/__init__.py,sha256=J9Sy2HiyMlztNv6VUurMzF5H2XzttNil8nRsWDsqLyg,8923
|
|
275
275
|
mlrun/runtimes/base.py,sha256=EL14Kmc1vWEjnBPJwLj5hHC6CtRAQHJLmohCD3sFEHo,37855
|
|
276
276
|
mlrun/runtimes/daskjob.py,sha256=JwuGvOiPsxEDHHMMUS4Oie4hLlYYIZwihAl6DjroTY0,19521
|
|
@@ -297,7 +297,7 @@ mlrun/runtimes/nuclio/nuclio.py,sha256=sLK8KdGO1LbftlL3HqPZlFOFTAAuxJACZCVl1c0Ha
|
|
|
297
297
|
mlrun/runtimes/nuclio/serving.py,sha256=1QPza0oG63bt3Bpib2VGhDcW3PNEjjsBUzIYBhiYR0s,32666
|
|
298
298
|
mlrun/runtimes/nuclio/application/__init__.py,sha256=rRs5vasy_G9IyoTpYIjYDafGoL6ifFBKgBtsXn31Atw,614
|
|
299
299
|
mlrun/runtimes/nuclio/application/application.py,sha256=VPX-ruYQJ7-7yd5c2sWdF4U5JCGSS3kYjUfOgev6l_Y,29186
|
|
300
|
-
mlrun/runtimes/nuclio/application/reverse_proxy.go,sha256=
|
|
300
|
+
mlrun/runtimes/nuclio/application/reverse_proxy.go,sha256=lEHH74vr2PridIHp1Jkc_NjkrWb5b6zawRrNxHQhwGU,2913
|
|
301
301
|
mlrun/runtimes/sparkjob/__init__.py,sha256=GPP_ekItxiU9Ydn3mJa4Obph02Bg6DO-JYs791_MV58,607
|
|
302
302
|
mlrun/runtimes/sparkjob/spark3job.py,sha256=E777WdlSe7Yx2kpg1bK0zZokn93bOQiUbtvtbcHV7ig,41610
|
|
303
303
|
mlrun/serving/__init__.py,sha256=FhOlOCnBC5HFXOHzSDe4NHBs6mNUDP_Qqy6WMNsCwws,1307
|
|
@@ -340,11 +340,11 @@ mlrun/utils/notifications/notification/mail.py,sha256=ZyJ3eqd8simxffQmXzqd3bgbAq
|
|
|
340
340
|
mlrun/utils/notifications/notification/slack.py,sha256=eQvmctTh6wIG5xVOesLLV9S1-UUCu5UEQ9JIJOor3ts,7183
|
|
341
341
|
mlrun/utils/notifications/notification/webhook.py,sha256=NeyIMSBojjjTJaUHmPbxMByp34GxYkl1-16NqzU27fU,4943
|
|
342
342
|
mlrun/utils/version/__init__.py,sha256=7kkrB7hEZ3cLXoWj1kPoDwo4MaswsI2JVOBpbKgPAgc,614
|
|
343
|
-
mlrun/utils/version/version.json,sha256=
|
|
343
|
+
mlrun/utils/version/version.json,sha256=M386FKHwnC4eHpp3xG7fFtQEQllorzsiu9pDs5U8888,89
|
|
344
344
|
mlrun/utils/version/version.py,sha256=eEW0tqIAkU9Xifxv8Z9_qsYnNhn3YH7NRAfM-pPLt1g,1878
|
|
345
|
-
mlrun-1.8.
|
|
346
|
-
mlrun-1.8.
|
|
347
|
-
mlrun-1.8.
|
|
348
|
-
mlrun-1.8.
|
|
349
|
-
mlrun-1.8.
|
|
350
|
-
mlrun-1.8.
|
|
345
|
+
mlrun-1.8.0rc45.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
346
|
+
mlrun-1.8.0rc45.dist-info/METADATA,sha256=Hrx8b3n6ywe0Ttl7L2PHZSvuIXzm9ELWceKlutJ-7jk,26008
|
|
347
|
+
mlrun-1.8.0rc45.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
|
348
|
+
mlrun-1.8.0rc45.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
|
|
349
|
+
mlrun-1.8.0rc45.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
|
|
350
|
+
mlrun-1.8.0rc45.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|