mlrun 1.7.0rc42__py3-none-any.whl → 1.7.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/__main__.py +4 -2
- mlrun/artifacts/manager.py +9 -2
- mlrun/common/schemas/__init__.py +1 -0
- mlrun/common/schemas/alert.py +11 -11
- mlrun/common/schemas/auth.py +2 -0
- mlrun/common/schemas/client_spec.py +0 -1
- mlrun/common/schemas/frontend_spec.py +7 -0
- mlrun/common/schemas/notification.py +32 -5
- mlrun/common/schemas/workflow.py +1 -0
- mlrun/config.py +47 -22
- mlrun/data_types/data_types.py +5 -0
- mlrun/datastore/base.py +4 -7
- mlrun/datastore/storeytargets.py +4 -3
- mlrun/datastore/targets.py +17 -4
- mlrun/db/httpdb.py +10 -12
- mlrun/db/nopdb.py +21 -4
- mlrun/execution.py +7 -2
- mlrun/feature_store/api.py +1 -0
- mlrun/feature_store/retrieval/spark_merger.py +7 -3
- mlrun/frameworks/_common/plan.py +3 -3
- mlrun/frameworks/_ml_common/plan.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +2 -3
- mlrun/k8s_utils.py +48 -2
- mlrun/launcher/client.py +6 -6
- mlrun/model.py +2 -1
- mlrun/model_monitoring/applications/results.py +2 -2
- mlrun/model_monitoring/controller.py +1 -1
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +15 -1
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +12 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +2 -2
- mlrun/model_monitoring/helpers.py +7 -15
- mlrun/model_monitoring/writer.py +8 -2
- mlrun/projects/pipelines.py +2 -0
- mlrun/projects/project.py +152 -60
- mlrun/render.py +3 -3
- mlrun/runtimes/daskjob.py +1 -1
- mlrun/runtimes/kubejob.py +6 -6
- mlrun/runtimes/local.py +4 -1
- mlrun/runtimes/nuclio/api_gateway.py +6 -0
- mlrun/runtimes/nuclio/application/application.py +5 -4
- mlrun/runtimes/nuclio/function.py +45 -0
- mlrun/runtimes/pod.py +21 -13
- mlrun/runtimes/sparkjob/spark3job.py +4 -0
- mlrun/serving/server.py +2 -0
- mlrun/utils/async_http.py +1 -1
- mlrun/utils/helpers.py +39 -16
- mlrun/utils/notifications/notification/__init__.py +0 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc45.dist-info}/METADATA +27 -27
- {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc45.dist-info}/RECORD +54 -54
- {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc45.dist-info}/WHEEL +1 -1
- {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc45.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc45.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc45.dist-info}/top_level.txt +0 -0
mlrun/__main__.py
CHANGED
|
@@ -734,9 +734,11 @@ def get(kind, name, selector, namespace, uid, project, tag, db, extra_args):
|
|
|
734
734
|
if db:
|
|
735
735
|
mlconf.dbpath = db
|
|
736
736
|
if not project:
|
|
737
|
-
|
|
737
|
+
logger.warning(
|
|
738
|
+
"Project parameter was not specified. Defaulting to 'default' project"
|
|
739
|
+
)
|
|
738
740
|
if kind.startswith("po"):
|
|
739
|
-
|
|
741
|
+
logger.warning("Unsupported, use 'get runtimes' instead")
|
|
740
742
|
return
|
|
741
743
|
|
|
742
744
|
elif kind.startswith("runtime"):
|
mlrun/artifacts/manager.py
CHANGED
|
@@ -72,7 +72,12 @@ class ArtifactProducer:
|
|
|
72
72
|
self.inputs = {}
|
|
73
73
|
|
|
74
74
|
def get_meta(self) -> dict:
|
|
75
|
-
return {
|
|
75
|
+
return {
|
|
76
|
+
"kind": self.kind,
|
|
77
|
+
"name": self.name,
|
|
78
|
+
"tag": self.tag,
|
|
79
|
+
"owner": self.owner,
|
|
80
|
+
}
|
|
76
81
|
|
|
77
82
|
@property
|
|
78
83
|
def uid(self):
|
|
@@ -195,7 +200,9 @@ class ArtifactManager:
|
|
|
195
200
|
:param artifact_path: The path to store the artifact.
|
|
196
201
|
If not provided, the artifact will be stored in the default artifact path.
|
|
197
202
|
:param format: The format of the artifact. (e.g. csv, json, html, etc.)
|
|
198
|
-
:param upload: Whether to upload the artifact
|
|
203
|
+
:param upload: Whether to upload the artifact to the datastore. If not provided, and the
|
|
204
|
+
`local_path` is not a directory, upload occurs by default. Directories are uploaded only when this
|
|
205
|
+
flag is explicitly set to `True`.
|
|
199
206
|
:param labels: Labels to add to the artifact.
|
|
200
207
|
:param db_key: The key to use when logging the artifact to the DB.
|
|
201
208
|
If not provided, will generate a key based on the producer name and the artifact key.
|
mlrun/common/schemas/__init__.py
CHANGED
mlrun/common/schemas/alert.py
CHANGED
|
@@ -34,17 +34,17 @@ class EventEntities(pydantic.BaseModel):
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
class EventKind(StrEnum):
|
|
37
|
-
DATA_DRIFT_DETECTED = "
|
|
38
|
-
DATA_DRIFT_SUSPECTED = "
|
|
39
|
-
CONCEPT_DRIFT_DETECTED = "
|
|
40
|
-
CONCEPT_DRIFT_SUSPECTED = "
|
|
41
|
-
MODEL_PERFORMANCE_DETECTED = "
|
|
42
|
-
MODEL_PERFORMANCE_SUSPECTED = "
|
|
43
|
-
SYSTEM_PERFORMANCE_DETECTED = "
|
|
44
|
-
SYSTEM_PERFORMANCE_SUSPECTED = "
|
|
45
|
-
MM_APP_ANOMALY_DETECTED = "
|
|
46
|
-
MM_APP_ANOMALY_SUSPECTED = "
|
|
47
|
-
MM_APP_FAILED = "
|
|
37
|
+
DATA_DRIFT_DETECTED = "data-drift-detected"
|
|
38
|
+
DATA_DRIFT_SUSPECTED = "data-drift-suspected"
|
|
39
|
+
CONCEPT_DRIFT_DETECTED = "concept-drift-detected"
|
|
40
|
+
CONCEPT_DRIFT_SUSPECTED = "concept-drift-suspected"
|
|
41
|
+
MODEL_PERFORMANCE_DETECTED = "model-performance-detected"
|
|
42
|
+
MODEL_PERFORMANCE_SUSPECTED = "model-performance-suspected"
|
|
43
|
+
SYSTEM_PERFORMANCE_DETECTED = "system-performance-detected"
|
|
44
|
+
SYSTEM_PERFORMANCE_SUSPECTED = "system-performance-suspected"
|
|
45
|
+
MM_APP_ANOMALY_DETECTED = "mm-app-anomaly-detected"
|
|
46
|
+
MM_APP_ANOMALY_SUSPECTED = "mm-app-anomaly-suspected"
|
|
47
|
+
MM_APP_FAILED = "mm-app-failed"
|
|
48
48
|
FAILED = "failed"
|
|
49
49
|
|
|
50
50
|
|
mlrun/common/schemas/auth.py
CHANGED
|
@@ -63,6 +63,7 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
|
|
|
63
63
|
event = "event"
|
|
64
64
|
datastore_profile = "datastore-profile"
|
|
65
65
|
api_gateway = "api-gateway"
|
|
66
|
+
project_summaries = "project-summaries"
|
|
66
67
|
|
|
67
68
|
def to_resource_string(
|
|
68
69
|
self,
|
|
@@ -72,6 +73,7 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
|
|
|
72
73
|
return {
|
|
73
74
|
# project is the resource itself, so no need for both resource_name and project_name
|
|
74
75
|
AuthorizationResourceTypes.project: "/projects/{project_name}",
|
|
76
|
+
AuthorizationResourceTypes.project_summaries: "/projects/{project_name}/project-summaries/{resource_name}",
|
|
75
77
|
AuthorizationResourceTypes.function: "/projects/{project_name}/functions/{resource_name}",
|
|
76
78
|
AuthorizationResourceTypes.artifact: "/projects/{project_name}/artifacts/{resource_name}",
|
|
77
79
|
AuthorizationResourceTypes.project_background_task: (
|
|
@@ -57,7 +57,6 @@ class ClientSpec(pydantic.BaseModel):
|
|
|
57
57
|
redis_url: typing.Optional[str]
|
|
58
58
|
redis_type: typing.Optional[str]
|
|
59
59
|
sql_url: typing.Optional[str]
|
|
60
|
-
model_endpoint_monitoring_store_type: typing.Optional[str]
|
|
61
60
|
model_endpoint_monitoring_endpoint_store_connection: typing.Optional[str]
|
|
62
61
|
model_monitoring_tsdb_connection: typing.Optional[str]
|
|
63
62
|
ce: typing.Optional[dict]
|
|
@@ -50,6 +50,12 @@ class FeatureFlags(pydantic.BaseModel):
|
|
|
50
50
|
preemption_nodes: PreemptionNodesFeatureFlag
|
|
51
51
|
|
|
52
52
|
|
|
53
|
+
class ArtifactLimits(pydantic.BaseModel):
|
|
54
|
+
max_chunk_size: int
|
|
55
|
+
max_preview_size: int
|
|
56
|
+
max_download_size: int
|
|
57
|
+
|
|
58
|
+
|
|
53
59
|
class FrontendSpec(pydantic.BaseModel):
|
|
54
60
|
jobs_dashboard_url: typing.Optional[str]
|
|
55
61
|
model_monitoring_dashboard_url: typing.Optional[str]
|
|
@@ -71,3 +77,4 @@ class FrontendSpec(pydantic.BaseModel):
|
|
|
71
77
|
allowed_artifact_path_prefixes_list: list[str]
|
|
72
78
|
ce: typing.Optional[dict]
|
|
73
79
|
internal_labels: list[str] = []
|
|
80
|
+
artifact_limits: ArtifactLimits
|
|
@@ -22,11 +22,38 @@ import mlrun.common.types
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class NotificationKind(mlrun.common.types.StrEnum):
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
"""Currently, the supported notification kinds and their params are as follows:"""
|
|
26
|
+
|
|
27
|
+
console: str = "console"
|
|
28
|
+
"""no params, local only"""
|
|
29
|
+
|
|
30
|
+
git: str = "git"
|
|
31
|
+
"""
|
|
32
|
+
**token** - The git token to use for the git notification.\n
|
|
33
|
+
**repo** - The git repo to which to send the notification.\n
|
|
34
|
+
**issue** - The git issue to which to send the notification.\n
|
|
35
|
+
**merge_request** -
|
|
36
|
+
In GitLab (as opposed to GitHub), merge requests and issues are separate entities.
|
|
37
|
+
If using merge request, the issue will be ignored, and vice versa.\n
|
|
38
|
+
**server** - The git server to which to send the notification.\n
|
|
39
|
+
**gitlab** - (bool) Whether the git server is GitLab or not.\n
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
ipython: str = "ipython"
|
|
43
|
+
"""no params, local only"""
|
|
44
|
+
|
|
45
|
+
slack: str = "slack"
|
|
46
|
+
"""**webhook** - The slack webhook to which to send the notification."""
|
|
47
|
+
|
|
48
|
+
webhook: str = "webhook"
|
|
49
|
+
"""
|
|
50
|
+
**url** - The webhook url to which to send the notification.\n
|
|
51
|
+
**method** - The http method to use when sending the notification (GET, POST, PUT, etc…).\n
|
|
52
|
+
**headers** - (dict) The http headers to send with the notification.\n
|
|
53
|
+
**override_body** - (dict) The body to send with the notification.\n
|
|
54
|
+
**verify_ssl** -
|
|
55
|
+
(bool) Whether SSL certificates are validated during HTTP requests or not, The default is set to True.
|
|
56
|
+
"""
|
|
30
57
|
|
|
31
58
|
|
|
32
59
|
class NotificationSeverity(mlrun.common.types.StrEnum):
|
mlrun/common/schemas/workflow.py
CHANGED
|
@@ -32,6 +32,7 @@ class WorkflowSpec(pydantic.BaseModel):
|
|
|
32
32
|
schedule: typing.Union[str, ScheduleCronTrigger] = None
|
|
33
33
|
run_local: typing.Optional[bool] = None
|
|
34
34
|
image: typing.Optional[str] = None
|
|
35
|
+
workflow_runner_node_selector: typing.Optional[dict[str, str]] = None
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
class WorkflowRequest(pydantic.BaseModel):
|
mlrun/config.py
CHANGED
|
@@ -27,6 +27,7 @@ import copy
|
|
|
27
27
|
import json
|
|
28
28
|
import os
|
|
29
29
|
import typing
|
|
30
|
+
import warnings
|
|
30
31
|
from collections.abc import Mapping
|
|
31
32
|
from datetime import timedelta
|
|
32
33
|
from distutils.util import strtobool
|
|
@@ -35,6 +36,7 @@ from threading import Lock
|
|
|
35
36
|
|
|
36
37
|
import dotenv
|
|
37
38
|
import semver
|
|
39
|
+
import urllib3.exceptions
|
|
38
40
|
import yaml
|
|
39
41
|
|
|
40
42
|
import mlrun.common.constants
|
|
@@ -152,6 +154,11 @@ default_config = {
|
|
|
152
154
|
"datasets": {
|
|
153
155
|
"max_preview_columns": 100,
|
|
154
156
|
},
|
|
157
|
+
"limits": {
|
|
158
|
+
"max_chunk_size": 1024 * 1024 * 1, # 1MB
|
|
159
|
+
"max_preview_size": 1024 * 1024 * 10, # 10MB
|
|
160
|
+
"max_download_size": 1024 * 1024 * 100, # 100MB
|
|
161
|
+
},
|
|
155
162
|
},
|
|
156
163
|
# FIXME: Adding these defaults here so we won't need to patch the "installing component" (provazio-controller) to
|
|
157
164
|
# configure this values on field systems, for newer system this will be configured correctly
|
|
@@ -326,7 +333,7 @@ default_config = {
|
|
|
326
333
|
"http": {
|
|
327
334
|
# when True, the client will verify the server's TLS
|
|
328
335
|
# set to False for backwards compatibility.
|
|
329
|
-
"verify":
|
|
336
|
+
"verify": True,
|
|
330
337
|
},
|
|
331
338
|
"db": {
|
|
332
339
|
"commit_retry_timeout": 30,
|
|
@@ -532,7 +539,6 @@ default_config = {
|
|
|
532
539
|
"store_prefixes": {
|
|
533
540
|
"default": "v3io:///users/pipelines/{project}/model-endpoints/{kind}",
|
|
534
541
|
"user_space": "v3io:///projects/{project}/model-endpoints/{kind}",
|
|
535
|
-
"stream": "", # TODO: Delete in 1.9.0
|
|
536
542
|
"monitoring_application": "v3io:///users/pipelines/{project}/monitoring-apps/",
|
|
537
543
|
},
|
|
538
544
|
# Offline storage path can be either relative or a full path. This path is used for general offline data
|
|
@@ -545,7 +551,6 @@ default_config = {
|
|
|
545
551
|
"parquet_batching_max_events": 10_000,
|
|
546
552
|
"parquet_batching_timeout_secs": timedelta(minutes=1).total_seconds(),
|
|
547
553
|
# See mlrun.model_monitoring.db.stores.ObjectStoreFactory for available options
|
|
548
|
-
"store_type": "v3io-nosql", # TODO: Delete in 1.9.0
|
|
549
554
|
"endpoint_store_connection": "",
|
|
550
555
|
# See mlrun.model_monitoring.db.tsdb.ObjectTSDBFactory for available options
|
|
551
556
|
"tsdb_connection": "",
|
|
@@ -729,7 +734,7 @@ default_config = {
|
|
|
729
734
|
"grafana_url": "",
|
|
730
735
|
"alerts": {
|
|
731
736
|
# supported modes: "enabled", "disabled".
|
|
732
|
-
"mode": "
|
|
737
|
+
"mode": "disabled",
|
|
733
738
|
# maximum number of alerts we allow to be configured.
|
|
734
739
|
# user will get an error when exceeding this
|
|
735
740
|
"max_allowed": 10000,
|
|
@@ -791,7 +796,21 @@ class Config:
|
|
|
791
796
|
for key, value in cfg.items():
|
|
792
797
|
if hasattr(self, key):
|
|
793
798
|
if isinstance(value, dict):
|
|
794
|
-
|
|
799
|
+
# ignore the `skip_errors` flag here
|
|
800
|
+
# if the key does not align with what mlrun config expects it is a user
|
|
801
|
+
# input error that can lead to unexpected behavior.
|
|
802
|
+
# raise the exception to ensure configuration is loaded correctly and do not
|
|
803
|
+
# ignore any errors.
|
|
804
|
+
config_value = getattr(self, key)
|
|
805
|
+
try:
|
|
806
|
+
config_value.update(value)
|
|
807
|
+
except AttributeError as exc:
|
|
808
|
+
if not isinstance(config_value, (dict, Config)):
|
|
809
|
+
raise ValueError(
|
|
810
|
+
f"Can not update `{key}` config. "
|
|
811
|
+
f"Expected a configuration but received {type(value)}"
|
|
812
|
+
) from exc
|
|
813
|
+
raise exc
|
|
795
814
|
else:
|
|
796
815
|
try:
|
|
797
816
|
setattr(self, key, value)
|
|
@@ -1095,6 +1114,9 @@ class Config:
|
|
|
1095
1114
|
# importing here to avoid circular dependency
|
|
1096
1115
|
import mlrun.db
|
|
1097
1116
|
|
|
1117
|
+
# It ensures that SSL verification is set before establishing a connection
|
|
1118
|
+
_configure_ssl_verification(self.httpdb.http.verify)
|
|
1119
|
+
|
|
1098
1120
|
# when dbpath is set we want to connect to it which will sync configuration from it to the client
|
|
1099
1121
|
mlrun.db.get_run_db(value, force_reconnect=True)
|
|
1100
1122
|
|
|
@@ -1123,10 +1145,10 @@ class Config:
|
|
|
1123
1145
|
project: str = "",
|
|
1124
1146
|
kind: str = "",
|
|
1125
1147
|
target: str = "online",
|
|
1126
|
-
artifact_path: str = None,
|
|
1127
|
-
function_name: str = None,
|
|
1148
|
+
artifact_path: typing.Optional[str] = None,
|
|
1149
|
+
function_name: typing.Optional[str] = None,
|
|
1128
1150
|
**kwargs,
|
|
1129
|
-
) ->
|
|
1151
|
+
) -> str:
|
|
1130
1152
|
"""Get the full path from the configuration based on the provided project and kind.
|
|
1131
1153
|
|
|
1132
1154
|
:param project: Project name.
|
|
@@ -1142,8 +1164,7 @@ class Config:
|
|
|
1142
1164
|
relative artifact path will be taken from the global MLRun artifact path.
|
|
1143
1165
|
:param function_name: Application name, None for model_monitoring_stream.
|
|
1144
1166
|
|
|
1145
|
-
:return: Full configured path for the provided kind.
|
|
1146
|
-
or a list of paths in the case of the online model monitoring stream path.
|
|
1167
|
+
:return: Full configured path for the provided kind.
|
|
1147
1168
|
"""
|
|
1148
1169
|
|
|
1149
1170
|
if target != "offline":
|
|
@@ -1164,18 +1185,11 @@ class Config:
|
|
|
1164
1185
|
if function_name is None
|
|
1165
1186
|
else f"{kind}-{function_name.lower()}",
|
|
1166
1187
|
)
|
|
1167
|
-
elif kind == "stream":
|
|
1168
|
-
return
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
kind=kind,
|
|
1173
|
-
), # old stream uri (pipelines) for BC ML-6043
|
|
1174
|
-
mlrun.mlconf.model_endpoint_monitoring.store_prefixes.user_space.format(
|
|
1175
|
-
project=project,
|
|
1176
|
-
kind=kind,
|
|
1177
|
-
), # new stream uri (projects)
|
|
1178
|
-
]
|
|
1188
|
+
elif kind == "stream":
|
|
1189
|
+
return mlrun.mlconf.model_endpoint_monitoring.store_prefixes.user_space.format(
|
|
1190
|
+
project=project,
|
|
1191
|
+
kind=kind,
|
|
1192
|
+
)
|
|
1179
1193
|
else:
|
|
1180
1194
|
return mlrun.mlconf.model_endpoint_monitoring.store_prefixes.default.format(
|
|
1181
1195
|
project=project,
|
|
@@ -1292,6 +1306,7 @@ def _do_populate(env=None, skip_errors=False):
|
|
|
1292
1306
|
if data:
|
|
1293
1307
|
config.update(data, skip_errors=skip_errors)
|
|
1294
1308
|
|
|
1309
|
+
_configure_ssl_verification(config.httpdb.http.verify)
|
|
1295
1310
|
_validate_config(config)
|
|
1296
1311
|
|
|
1297
1312
|
|
|
@@ -1351,6 +1366,16 @@ def _convert_str(value, typ):
|
|
|
1351
1366
|
return typ(value)
|
|
1352
1367
|
|
|
1353
1368
|
|
|
1369
|
+
def _configure_ssl_verification(verify_ssl: bool) -> None:
|
|
1370
|
+
"""Configure SSL verification warnings based on the setting."""
|
|
1371
|
+
if not verify_ssl:
|
|
1372
|
+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
1373
|
+
else:
|
|
1374
|
+
# If the user changes the `verify` setting to `True` at runtime using `mlrun.set_env_from_file` after
|
|
1375
|
+
# importing `mlrun`, we need to reload the `mlrun` configuration and enable this warning.
|
|
1376
|
+
warnings.simplefilter("default", urllib3.exceptions.InsecureRequestWarning)
|
|
1377
|
+
|
|
1378
|
+
|
|
1354
1379
|
def read_env(env=None, prefix=env_prefix):
|
|
1355
1380
|
"""Read configuration from environment"""
|
|
1356
1381
|
env = os.environ if env is None else env
|
mlrun/data_types/data_types.py
CHANGED
|
@@ -70,6 +70,11 @@ def pa_type_to_value_type(type_):
|
|
|
70
70
|
if isinstance(type_, TimestampType):
|
|
71
71
|
return ValueType.DATETIME
|
|
72
72
|
|
|
73
|
+
# pandas category type translates to pyarrow DictionaryType
|
|
74
|
+
# we need to unpack the value type (ML-7868)
|
|
75
|
+
if isinstance(type_, pyarrow.DictionaryType):
|
|
76
|
+
type_ = type_.value_type
|
|
77
|
+
|
|
73
78
|
type_map = {
|
|
74
79
|
pyarrow.bool_(): ValueType.BOOL,
|
|
75
80
|
pyarrow.int64(): ValueType.INT64,
|
mlrun/datastore/base.py
CHANGED
|
@@ -24,13 +24,12 @@ import pandas as pd
|
|
|
24
24
|
import pyarrow
|
|
25
25
|
import pytz
|
|
26
26
|
import requests
|
|
27
|
-
import urllib3
|
|
28
27
|
from deprecated import deprecated
|
|
29
28
|
|
|
30
29
|
import mlrun.config
|
|
31
30
|
import mlrun.errors
|
|
32
31
|
from mlrun.errors import err_to_str
|
|
33
|
-
from mlrun.utils import StorePrefix,
|
|
32
|
+
from mlrun.utils import StorePrefix, is_jupyter, logger
|
|
34
33
|
|
|
35
34
|
from .store_resources import is_store_uri, parse_store_uri
|
|
36
35
|
from .utils import filter_df_start_end_time, select_columns_from_df
|
|
@@ -620,14 +619,14 @@ class DataItem:
|
|
|
620
619
|
)
|
|
621
620
|
return df
|
|
622
621
|
|
|
623
|
-
def show(self, format=None):
|
|
622
|
+
def show(self, format: Optional[str] = None) -> None:
|
|
624
623
|
"""show the data object content in Jupyter
|
|
625
624
|
|
|
626
625
|
:param format: format to use (when there is no/wrong suffix), e.g. 'png'
|
|
627
626
|
"""
|
|
628
|
-
if not
|
|
627
|
+
if not is_jupyter:
|
|
629
628
|
logger.warning(
|
|
630
|
-
"Jupyter
|
|
629
|
+
"Jupyter was not detected. `.show()` displays only inside Jupyter."
|
|
631
630
|
)
|
|
632
631
|
return
|
|
633
632
|
|
|
@@ -745,8 +744,6 @@ class HttpStore(DataStore):
|
|
|
745
744
|
|
|
746
745
|
verify_ssl = mlconf.httpdb.http.verify
|
|
747
746
|
try:
|
|
748
|
-
if not verify_ssl:
|
|
749
|
-
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
750
747
|
response = requests.get(url, headers=headers, auth=auth, verify=verify_ssl)
|
|
751
748
|
except OSError as exc:
|
|
752
749
|
raise OSError(f"error: cannot connect to {url}: {err_to_str(exc)}")
|
mlrun/datastore/storeytargets.py
CHANGED
|
@@ -89,8 +89,8 @@ class StreamStoreyTarget(storey.StreamTarget):
|
|
|
89
89
|
raise mlrun.errors.MLRunInvalidArgumentError("StreamTarget requires a path")
|
|
90
90
|
|
|
91
91
|
access_key = storage_options.get("v3io_access_key")
|
|
92
|
-
storage = (
|
|
93
|
-
|
|
92
|
+
storage = V3ioDriver(
|
|
93
|
+
webapi=endpoint or mlrun.mlconf.v3io_api, access_key=access_key
|
|
94
94
|
)
|
|
95
95
|
|
|
96
96
|
if storage_options:
|
|
@@ -137,7 +137,8 @@ class RedisNoSqlStoreyTarget(storey.NoSqlTarget):
|
|
|
137
137
|
def __init__(self, *args, **kwargs):
|
|
138
138
|
path = kwargs.pop("path")
|
|
139
139
|
endpoint, uri = mlrun.datastore.targets.RedisNoSqlTarget.get_server_endpoint(
|
|
140
|
-
path
|
|
140
|
+
path,
|
|
141
|
+
kwargs.pop("credentials_prefix", None),
|
|
141
142
|
)
|
|
142
143
|
kwargs["path"] = endpoint + "/" + uri
|
|
143
144
|
super().__init__(*args, **kwargs)
|
mlrun/datastore/targets.py
CHANGED
|
@@ -439,6 +439,12 @@ class BaseStoreTarget(DataTargetBase):
|
|
|
439
439
|
self.storage_options = storage_options
|
|
440
440
|
self.schema = schema or {}
|
|
441
441
|
self.credentials_prefix = credentials_prefix
|
|
442
|
+
if credentials_prefix:
|
|
443
|
+
warnings.warn(
|
|
444
|
+
"The 'credentials_prefix' parameter is deprecated and will be removed in "
|
|
445
|
+
"1.9.0. Please use datastore profiles instead.",
|
|
446
|
+
FutureWarning,
|
|
447
|
+
)
|
|
442
448
|
|
|
443
449
|
self._target = None
|
|
444
450
|
self._resource = None
|
|
@@ -1479,7 +1485,7 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
|
|
|
1479
1485
|
writer_step_name = "RedisNoSqlTarget"
|
|
1480
1486
|
|
|
1481
1487
|
@staticmethod
|
|
1482
|
-
def get_server_endpoint(path):
|
|
1488
|
+
def get_server_endpoint(path, credentials_prefix=None):
|
|
1483
1489
|
endpoint, uri = parse_path(path)
|
|
1484
1490
|
endpoint = endpoint or mlrun.mlconf.redis.url
|
|
1485
1491
|
if endpoint.startswith("ds://"):
|
|
@@ -1497,7 +1503,9 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
|
|
|
1497
1503
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
1498
1504
|
"Provide Redis username and password only via secrets"
|
|
1499
1505
|
)
|
|
1500
|
-
credentials_prefix = mlrun.get_secret_or_env(
|
|
1506
|
+
credentials_prefix = credentials_prefix or mlrun.get_secret_or_env(
|
|
1507
|
+
key="CREDENTIALS_PREFIX"
|
|
1508
|
+
)
|
|
1501
1509
|
user = mlrun.get_secret_or_env(
|
|
1502
1510
|
"REDIS_USER", default="", prefix=credentials_prefix
|
|
1503
1511
|
)
|
|
@@ -1517,7 +1525,9 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
|
|
|
1517
1525
|
from storey import Table
|
|
1518
1526
|
from storey.redis_driver import RedisDriver
|
|
1519
1527
|
|
|
1520
|
-
endpoint, uri = self.get_server_endpoint(
|
|
1528
|
+
endpoint, uri = self.get_server_endpoint(
|
|
1529
|
+
self.get_target_path(), self.credentials_prefix
|
|
1530
|
+
)
|
|
1521
1531
|
|
|
1522
1532
|
return Table(
|
|
1523
1533
|
uri,
|
|
@@ -1526,7 +1536,9 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
|
|
|
1526
1536
|
)
|
|
1527
1537
|
|
|
1528
1538
|
def get_spark_options(self, key_column=None, timestamp_key=None, overwrite=True):
|
|
1529
|
-
endpoint, uri = self.get_server_endpoint(
|
|
1539
|
+
endpoint, uri = self.get_server_endpoint(
|
|
1540
|
+
self.get_target_path(), self.credentials_prefix
|
|
1541
|
+
)
|
|
1530
1542
|
parsed_endpoint = urlparse(endpoint)
|
|
1531
1543
|
store, path_in_store, path = self._get_store_and_path()
|
|
1532
1544
|
return {
|
|
@@ -1577,6 +1589,7 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
|
|
|
1577
1589
|
class_name="mlrun.datastore.storeytargets.RedisNoSqlStoreyTarget",
|
|
1578
1590
|
columns=column_list,
|
|
1579
1591
|
table=table,
|
|
1592
|
+
credentials_prefix=self.credentials_prefix,
|
|
1580
1593
|
**self.attributes,
|
|
1581
1594
|
)
|
|
1582
1595
|
|
mlrun/db/httpdb.py
CHANGED
|
@@ -525,10 +525,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
525
525
|
server_cfg.get("external_platform_tracking")
|
|
526
526
|
or config.external_platform_tracking
|
|
527
527
|
)
|
|
528
|
-
config.model_endpoint_monitoring.store_type = (
|
|
529
|
-
server_cfg.get("model_endpoint_monitoring_store_type")
|
|
530
|
-
or config.model_endpoint_monitoring.store_type
|
|
531
|
-
)
|
|
532
528
|
config.model_endpoint_monitoring.endpoint_store_connection = (
|
|
533
529
|
server_cfg.get("model_endpoint_monitoring_endpoint_store_connection")
|
|
534
530
|
or config.model_endpoint_monitoring.endpoint_store_connection
|
|
@@ -1374,20 +1370,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1374
1370
|
:returns: :py:class:`~mlrun.common.schemas.GroupedByProjectRuntimeResourcesOutput` listing the runtime resources
|
|
1375
1371
|
that were removed.
|
|
1376
1372
|
"""
|
|
1377
|
-
if grace_period is None:
|
|
1378
|
-
grace_period = config.runtime_resources_deletion_grace_period
|
|
1379
|
-
logger.info(
|
|
1380
|
-
"Using default grace period for runtime resources deletion",
|
|
1381
|
-
grace_period=grace_period,
|
|
1382
|
-
)
|
|
1383
|
-
|
|
1384
1373
|
params = {
|
|
1385
1374
|
"label-selector": label_selector,
|
|
1386
1375
|
"kind": kind,
|
|
1387
1376
|
"object-id": object_id,
|
|
1388
1377
|
"force": force,
|
|
1389
|
-
"grace-period": grace_period,
|
|
1390
1378
|
}
|
|
1379
|
+
if grace_period is not None:
|
|
1380
|
+
params["grace-period"] = grace_period
|
|
1391
1381
|
error = "Failed deleting runtime resources"
|
|
1392
1382
|
project_path = project if project else "*"
|
|
1393
1383
|
response = self.api_call(
|
|
@@ -4193,6 +4183,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4193
4183
|
:param event_data: The data of the event.
|
|
4194
4184
|
:param project: The project that the event belongs to.
|
|
4195
4185
|
"""
|
|
4186
|
+
if mlrun.mlconf.alerts.mode == mlrun.common.schemas.alert.AlertsModes.disabled:
|
|
4187
|
+
logger.warning("Alerts are disabled, event will not be generated")
|
|
4188
|
+
|
|
4196
4189
|
project = project or config.default_project
|
|
4197
4190
|
endpoint_path = f"projects/{project}/events/{name}"
|
|
4198
4191
|
error_message = f"post event {project}/events/{name}"
|
|
@@ -4219,6 +4212,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4219
4212
|
if not alert_data:
|
|
4220
4213
|
raise mlrun.errors.MLRunInvalidArgumentError("Alert data must be provided")
|
|
4221
4214
|
|
|
4215
|
+
if mlrun.mlconf.alerts.mode == mlrun.common.schemas.alert.AlertsModes.disabled:
|
|
4216
|
+
logger.warning(
|
|
4217
|
+
"Alerts are disabled, alert will still be stored but will not be triggered"
|
|
4218
|
+
)
|
|
4219
|
+
|
|
4222
4220
|
project = project or config.default_project
|
|
4223
4221
|
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
4224
4222
|
error_message = f"put alert {project}/alerts/{alert_name}"
|
mlrun/db/nopdb.py
CHANGED
|
@@ -21,6 +21,7 @@ import mlrun.common.formatters
|
|
|
21
21
|
import mlrun.common.runtimes.constants
|
|
22
22
|
import mlrun.common.schemas
|
|
23
23
|
import mlrun.errors
|
|
24
|
+
import mlrun.lists
|
|
24
25
|
|
|
25
26
|
from ..config import config
|
|
26
27
|
from ..utils import logger
|
|
@@ -73,6 +74,22 @@ class NopDB(RunDBInterface):
|
|
|
73
74
|
def abort_run(self, uid, project="", iter=0, timeout=45, status_text=""):
|
|
74
75
|
pass
|
|
75
76
|
|
|
77
|
+
def list_runtime_resources(
|
|
78
|
+
self,
|
|
79
|
+
project: Optional[str] = None,
|
|
80
|
+
label_selector: Optional[str] = None,
|
|
81
|
+
kind: Optional[str] = None,
|
|
82
|
+
object_id: Optional[str] = None,
|
|
83
|
+
group_by: Optional[
|
|
84
|
+
mlrun.common.schemas.ListRuntimeResourcesGroupByField
|
|
85
|
+
] = None,
|
|
86
|
+
) -> Union[
|
|
87
|
+
mlrun.common.schemas.RuntimeResourcesOutput,
|
|
88
|
+
mlrun.common.schemas.GroupedByJobRuntimeResourcesOutput,
|
|
89
|
+
mlrun.common.schemas.GroupedByProjectRuntimeResourcesOutput,
|
|
90
|
+
]:
|
|
91
|
+
return []
|
|
92
|
+
|
|
76
93
|
def read_run(
|
|
77
94
|
self,
|
|
78
95
|
uid,
|
|
@@ -108,7 +125,7 @@ class NopDB(RunDBInterface):
|
|
|
108
125
|
max_partitions: int = 0,
|
|
109
126
|
with_notifications: bool = False,
|
|
110
127
|
):
|
|
111
|
-
|
|
128
|
+
return mlrun.lists.RunList()
|
|
112
129
|
|
|
113
130
|
def del_run(self, uid, project="", iter=0):
|
|
114
131
|
pass
|
|
@@ -149,7 +166,7 @@ class NopDB(RunDBInterface):
|
|
|
149
166
|
format_: mlrun.common.formatters.ArtifactFormat = mlrun.common.formatters.ArtifactFormat.full,
|
|
150
167
|
limit: int = None,
|
|
151
168
|
):
|
|
152
|
-
|
|
169
|
+
return mlrun.lists.ArtifactList()
|
|
153
170
|
|
|
154
171
|
def del_artifact(
|
|
155
172
|
self,
|
|
@@ -181,7 +198,7 @@ class NopDB(RunDBInterface):
|
|
|
181
198
|
def list_functions(
|
|
182
199
|
self, name=None, project="", tag="", labels=None, since=None, until=None
|
|
183
200
|
):
|
|
184
|
-
|
|
201
|
+
return []
|
|
185
202
|
|
|
186
203
|
def tag_objects(
|
|
187
204
|
self,
|
|
@@ -421,7 +438,7 @@ class NopDB(RunDBInterface):
|
|
|
421
438
|
] = mlrun.common.formatters.PipelineFormat.metadata_only,
|
|
422
439
|
page_size: int = None,
|
|
423
440
|
) -> mlrun.common.schemas.PipelinesOutput:
|
|
424
|
-
|
|
441
|
+
return mlrun.common.schemas.PipelinesOutput(runs=[], total_size=0)
|
|
425
442
|
|
|
426
443
|
def create_project_secrets(
|
|
427
444
|
self,
|
mlrun/execution.py
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import logging
|
|
15
16
|
import os
|
|
16
17
|
import uuid
|
|
17
18
|
from copy import deepcopy
|
|
@@ -168,6 +169,8 @@ class MLClientCtx:
|
|
|
168
169
|
@log_level.setter
|
|
169
170
|
def log_level(self, value: str):
|
|
170
171
|
"""Set the logging level, e.g. 'debug', 'info', 'error'"""
|
|
172
|
+
level = logging.getLevelName(value.upper())
|
|
173
|
+
self._logger.set_logger_level(level)
|
|
171
174
|
self._log_level = value
|
|
172
175
|
|
|
173
176
|
@property
|
|
@@ -335,7 +338,7 @@ class MLClientCtx:
|
|
|
335
338
|
"name": self.name,
|
|
336
339
|
"kind": "run",
|
|
337
340
|
"uri": uri,
|
|
338
|
-
"owner": get_in(self._labels,
|
|
341
|
+
"owner": get_in(self._labels, mlrun_constants.MLRunInternalLabels.owner),
|
|
339
342
|
}
|
|
340
343
|
if mlrun_constants.MLRunInternalLabels.workflow in self._labels:
|
|
341
344
|
resp[mlrun_constants.MLRunInternalLabels.workflow] = self._labels[
|
|
@@ -631,7 +634,9 @@ class MLClientCtx:
|
|
|
631
634
|
:param viewer: Kubeflow viewer type
|
|
632
635
|
:param target_path: Absolute target path (instead of using artifact_path + local_path)
|
|
633
636
|
:param src_path: Deprecated, use local_path
|
|
634
|
-
:param upload:
|
|
637
|
+
:param upload: Whether to upload the artifact to the datastore. If not provided, and the `local_path`
|
|
638
|
+
is not a directory, upload occurs by default. Directories are uploaded only when this
|
|
639
|
+
flag is explicitly set to `True`.
|
|
635
640
|
:param labels: A set of key/value labels to tag the artifact with
|
|
636
641
|
:param format: Optional, format to use (e.g. csv, parquet, ..)
|
|
637
642
|
:param db_key: The key to use in the artifact DB table, by default its run name + '_' + key
|
mlrun/feature_store/api.py
CHANGED
|
@@ -188,9 +188,13 @@ class SparkFeatureMerger(BaseMerger):
|
|
|
188
188
|
|
|
189
189
|
if self.spark is None:
|
|
190
190
|
# create spark context
|
|
191
|
-
self.spark =
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
self.spark = (
|
|
192
|
+
SparkSession.builder.appName(
|
|
193
|
+
f"vector-merger-{self.vector.metadata.name}"
|
|
194
|
+
)
|
|
195
|
+
.config("spark.driver.memory", "2g")
|
|
196
|
+
.getOrCreate()
|
|
197
|
+
)
|
|
194
198
|
|
|
195
199
|
def _get_engine_df(
|
|
196
200
|
self,
|