mlrun 1.10.0rc18__py3-none-any.whl → 1.11.0rc16__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 +24 -3
- mlrun/__main__.py +0 -4
- mlrun/artifacts/dataset.py +2 -2
- mlrun/artifacts/document.py +6 -1
- mlrun/artifacts/llm_prompt.py +21 -15
- mlrun/artifacts/model.py +3 -3
- mlrun/artifacts/plots.py +1 -1
- mlrun/{model_monitoring/db/tsdb/tdengine → auth}/__init__.py +2 -3
- mlrun/auth/nuclio.py +89 -0
- mlrun/auth/providers.py +429 -0
- mlrun/auth/utils.py +415 -0
- mlrun/common/constants.py +14 -0
- mlrun/common/model_monitoring/helpers.py +123 -0
- mlrun/common/runtimes/constants.py +28 -0
- mlrun/common/schemas/__init__.py +14 -3
- mlrun/common/schemas/alert.py +2 -2
- mlrun/common/schemas/api_gateway.py +3 -0
- mlrun/common/schemas/auth.py +12 -10
- mlrun/common/schemas/client_spec.py +4 -0
- mlrun/common/schemas/constants.py +25 -0
- mlrun/common/schemas/frontend_spec.py +1 -8
- mlrun/common/schemas/function.py +34 -0
- mlrun/common/schemas/hub.py +33 -20
- mlrun/common/schemas/model_monitoring/__init__.py +2 -1
- mlrun/common/schemas/model_monitoring/constants.py +12 -15
- mlrun/common/schemas/model_monitoring/functions.py +13 -4
- mlrun/common/schemas/model_monitoring/model_endpoints.py +11 -0
- mlrun/common/schemas/pipeline.py +1 -1
- mlrun/common/schemas/secret.py +17 -2
- mlrun/common/secrets.py +95 -1
- mlrun/common/types.py +10 -10
- mlrun/config.py +69 -19
- mlrun/data_types/infer.py +2 -2
- mlrun/datastore/__init__.py +12 -5
- mlrun/datastore/azure_blob.py +162 -47
- mlrun/datastore/base.py +274 -10
- mlrun/datastore/datastore.py +7 -2
- mlrun/datastore/datastore_profile.py +84 -22
- mlrun/datastore/model_provider/huggingface_provider.py +225 -41
- mlrun/datastore/model_provider/mock_model_provider.py +87 -0
- mlrun/datastore/model_provider/model_provider.py +206 -74
- mlrun/datastore/model_provider/openai_provider.py +226 -66
- mlrun/datastore/s3.py +39 -18
- mlrun/datastore/sources.py +1 -1
- mlrun/datastore/store_resources.py +4 -4
- mlrun/datastore/storeytargets.py +17 -12
- mlrun/datastore/targets.py +1 -1
- mlrun/datastore/utils.py +25 -6
- mlrun/datastore/v3io.py +1 -1
- mlrun/db/base.py +63 -32
- mlrun/db/httpdb.py +373 -153
- mlrun/db/nopdb.py +54 -21
- mlrun/errors.py +4 -2
- mlrun/execution.py +66 -25
- mlrun/feature_store/api.py +1 -1
- mlrun/feature_store/common.py +1 -1
- mlrun/feature_store/feature_vector_utils.py +1 -1
- mlrun/feature_store/steps.py +8 -6
- mlrun/frameworks/_common/utils.py +3 -3
- mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +2 -1
- mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
- mlrun/frameworks/_ml_common/utils.py +2 -1
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +4 -3
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +2 -1
- mlrun/frameworks/onnx/dataset.py +2 -1
- mlrun/frameworks/onnx/mlrun_interface.py +2 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +5 -4
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +2 -1
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +2 -1
- mlrun/frameworks/pytorch/utils.py +2 -1
- mlrun/frameworks/sklearn/metric.py +2 -1
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +5 -4
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +2 -1
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +2 -1
- mlrun/hub/__init__.py +52 -0
- mlrun/hub/base.py +142 -0
- mlrun/hub/module.py +172 -0
- mlrun/hub/step.py +113 -0
- mlrun/k8s_utils.py +105 -16
- mlrun/launcher/base.py +15 -7
- mlrun/launcher/local.py +4 -1
- mlrun/model.py +14 -4
- mlrun/model_monitoring/__init__.py +0 -1
- mlrun/model_monitoring/api.py +65 -28
- mlrun/model_monitoring/applications/__init__.py +1 -1
- mlrun/model_monitoring/applications/base.py +299 -128
- mlrun/model_monitoring/applications/context.py +2 -4
- mlrun/model_monitoring/controller.py +132 -58
- mlrun/model_monitoring/db/_schedules.py +38 -29
- mlrun/model_monitoring/db/_stats.py +6 -16
- mlrun/model_monitoring/db/tsdb/__init__.py +9 -7
- mlrun/model_monitoring/db/tsdb/base.py +29 -9
- mlrun/model_monitoring/db/tsdb/preaggregate.py +234 -0
- mlrun/model_monitoring/db/tsdb/stream_graph_steps.py +63 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_metrics_queries.py +414 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_predictions_queries.py +376 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_results_queries.py +590 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connection.py +434 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connector.py +541 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_operations.py +808 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_schema.py +502 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream.py +163 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream_graph_steps.py +60 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_dataframe_processor.py +141 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_query_builder.py +585 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/writer_graph_steps.py +73 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +20 -9
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +235 -51
- mlrun/model_monitoring/features_drift_table.py +2 -1
- mlrun/model_monitoring/helpers.py +30 -6
- mlrun/model_monitoring/stream_processing.py +34 -28
- mlrun/model_monitoring/writer.py +224 -4
- mlrun/package/__init__.py +2 -1
- mlrun/platforms/__init__.py +0 -43
- mlrun/platforms/iguazio.py +8 -4
- mlrun/projects/operations.py +17 -11
- mlrun/projects/pipelines.py +2 -2
- mlrun/projects/project.py +187 -123
- mlrun/run.py +95 -21
- mlrun/runtimes/__init__.py +2 -186
- mlrun/runtimes/base.py +103 -25
- mlrun/runtimes/constants.py +225 -0
- mlrun/runtimes/daskjob.py +5 -2
- mlrun/runtimes/databricks_job/databricks_runtime.py +2 -1
- mlrun/runtimes/local.py +5 -2
- mlrun/runtimes/mounts.py +20 -2
- mlrun/runtimes/nuclio/__init__.py +12 -7
- mlrun/runtimes/nuclio/api_gateway.py +36 -6
- mlrun/runtimes/nuclio/application/application.py +339 -40
- mlrun/runtimes/nuclio/function.py +222 -72
- mlrun/runtimes/nuclio/serving.py +132 -42
- mlrun/runtimes/pod.py +213 -21
- mlrun/runtimes/utils.py +49 -9
- mlrun/secrets.py +99 -14
- mlrun/serving/__init__.py +2 -0
- mlrun/serving/remote.py +84 -11
- mlrun/serving/routers.py +26 -44
- mlrun/serving/server.py +138 -51
- mlrun/serving/serving_wrapper.py +6 -2
- mlrun/serving/states.py +997 -283
- mlrun/serving/steps.py +62 -0
- mlrun/serving/system_steps.py +149 -95
- mlrun/serving/v2_serving.py +9 -10
- mlrun/track/trackers/mlflow_tracker.py +29 -31
- mlrun/utils/helpers.py +292 -94
- mlrun/utils/http.py +9 -2
- mlrun/utils/notifications/notification/base.py +18 -0
- mlrun/utils/notifications/notification/git.py +3 -5
- mlrun/utils/notifications/notification/mail.py +39 -16
- mlrun/utils/notifications/notification/slack.py +2 -4
- mlrun/utils/notifications/notification/webhook.py +2 -5
- mlrun/utils/notifications/notification_pusher.py +3 -3
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +3 -4
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/METADATA +63 -74
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/RECORD +161 -143
- mlrun/api/schemas/__init__.py +0 -259
- mlrun/db/auth_utils.py +0 -152
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +0 -344
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +0 -75
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +0 -281
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +0 -1266
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/WHEEL +0 -0
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/entry_points.txt +0 -0
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/top_level.txt +0 -0
mlrun/db/httpdb.py
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
|
|
15
14
|
import enum
|
|
16
15
|
import http
|
|
16
|
+
import os
|
|
17
17
|
import re
|
|
18
18
|
import time
|
|
19
19
|
import traceback
|
|
@@ -24,6 +24,7 @@ from datetime import datetime, timedelta
|
|
|
24
24
|
from os import environ, path, remove
|
|
25
25
|
from typing import Literal, Optional, Union
|
|
26
26
|
from urllib.parse import urlparse
|
|
27
|
+
from uuid import UUID
|
|
27
28
|
|
|
28
29
|
import pydantic.v1
|
|
29
30
|
import requests
|
|
@@ -31,6 +32,7 @@ import semver
|
|
|
31
32
|
from pydantic.v1 import parse_obj_as
|
|
32
33
|
|
|
33
34
|
import mlrun
|
|
35
|
+
import mlrun.auth
|
|
34
36
|
import mlrun.common.constants
|
|
35
37
|
import mlrun.common.formatters
|
|
36
38
|
import mlrun.common.runtimes
|
|
@@ -38,13 +40,14 @@ import mlrun.common.schemas
|
|
|
38
40
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
39
41
|
import mlrun.common.schemas.model_monitoring.model_endpoints as mm_endpoints
|
|
40
42
|
import mlrun.common.types
|
|
43
|
+
import mlrun.k8s_utils
|
|
41
44
|
import mlrun.platforms
|
|
42
45
|
import mlrun.projects
|
|
43
46
|
import mlrun.runtimes.nuclio.api_gateway
|
|
44
47
|
import mlrun.runtimes.nuclio.function
|
|
45
48
|
import mlrun.utils
|
|
46
49
|
from mlrun.alerts.alert import AlertConfig
|
|
47
|
-
from mlrun.
|
|
50
|
+
from mlrun.common.schemas.hub import HubSourceType
|
|
48
51
|
from mlrun.errors import MLRunInvalidArgumentError, err_to_str
|
|
49
52
|
from mlrun.secrets import get_secret_or_env
|
|
50
53
|
from mlrun_pipelines.utils import compile_pipeline
|
|
@@ -124,6 +127,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
124
127
|
r"\/?run\/.+\/.+",
|
|
125
128
|
]
|
|
126
129
|
|
|
130
|
+
NON_RETRIABLE_PATHS = [
|
|
131
|
+
# Storing user secret tokens is not idempotent — retrying the request may result inconsistent secret storage.
|
|
132
|
+
r"\/?user-secrets/tokens",
|
|
133
|
+
]
|
|
134
|
+
|
|
127
135
|
def __init__(self, url):
|
|
128
136
|
self.server_version = ""
|
|
129
137
|
self.session = None
|
|
@@ -135,43 +143,56 @@ class HTTPRunDB(RunDBInterface):
|
|
|
135
143
|
version.Version().get_python_version()
|
|
136
144
|
)
|
|
137
145
|
|
|
146
|
+
self.user = None
|
|
147
|
+
self.password = None
|
|
148
|
+
self.token_provider = None
|
|
149
|
+
self.base_url = None
|
|
150
|
+
self._parsed_url = None
|
|
151
|
+
|
|
138
152
|
self._enrich_and_validate(url)
|
|
139
153
|
|
|
140
154
|
def _enrich_and_validate(self, url):
|
|
141
|
-
parsed_url =
|
|
142
|
-
scheme = parsed_url.scheme.lower()
|
|
143
|
-
if scheme not in ("http", "https"):
|
|
144
|
-
raise ValueError(
|
|
145
|
-
f"Invalid URL scheme {scheme} for HTTPRunDB, only http(s) is supported"
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
endpoint = parsed_url.hostname
|
|
149
|
-
if parsed_url.port:
|
|
150
|
-
endpoint += f":{parsed_url.port}"
|
|
151
|
-
base_url = f"{parsed_url.scheme}://{endpoint}{parsed_url.path}"
|
|
155
|
+
base_url, parsed_url = self._resolve_api_urls(url)
|
|
152
156
|
|
|
153
157
|
self.base_url = base_url
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
self._parsed_url = parsed_url
|
|
159
|
+
self.user = parsed_url.username or config.httpdb.user
|
|
160
|
+
self.password = parsed_url.password or config.httpdb.password
|
|
161
|
+
self._init_token_provider()
|
|
162
|
+
|
|
163
|
+
def _init_token_provider(self):
|
|
164
|
+
"""
|
|
165
|
+
Initialize token provider according to current config.
|
|
166
|
+
|
|
167
|
+
Must be called after `connect()` synced config from server (client-spec), since
|
|
168
|
+
some auth flows (e.g. Iguazio V4 OAuth token) require values fetched from the API.
|
|
169
|
+
"""
|
|
156
170
|
self.token_provider = None
|
|
157
171
|
|
|
158
172
|
if config.auth_with_client_id.enabled:
|
|
159
|
-
self.token_provider = OAuthClientIDTokenProvider(
|
|
173
|
+
self.token_provider = mlrun.auth.OAuthClientIDTokenProvider(
|
|
160
174
|
token_endpoint=get_secret_or_env("MLRUN_AUTH_TOKEN_ENDPOINT"),
|
|
161
175
|
client_id=get_secret_or_env("MLRUN_AUTH_CLIENT_ID"),
|
|
162
176
|
client_secret=get_secret_or_env("MLRUN_AUTH_CLIENT_SECRET"),
|
|
163
177
|
timeout=config.auth_with_client_id.request_timeout,
|
|
164
178
|
)
|
|
179
|
+
elif config.auth_with_oauth_token.enabled:
|
|
180
|
+
self.token_provider = mlrun.auth.IGTokenProvider(
|
|
181
|
+
token_endpoint=config.auth_token_endpoint,
|
|
182
|
+
timeout=config.auth_with_oauth_token.request_timeout,
|
|
183
|
+
)
|
|
165
184
|
else:
|
|
166
185
|
username, password, token = mlrun.platforms.add_or_refresh_credentials(
|
|
167
|
-
|
|
186
|
+
self._parsed_url.hostname,
|
|
187
|
+
self.user,
|
|
188
|
+
self.password,
|
|
189
|
+
config.httpdb.token,
|
|
168
190
|
)
|
|
191
|
+
self.user = username
|
|
192
|
+
self.password = password
|
|
169
193
|
|
|
170
194
|
if token:
|
|
171
|
-
self.token_provider = StaticTokenProvider(token)
|
|
172
|
-
|
|
173
|
-
self.user = username
|
|
174
|
-
self.password = password
|
|
195
|
+
self.token_provider = mlrun.auth.StaticTokenProvider(token)
|
|
175
196
|
|
|
176
197
|
def __repr__(self):
|
|
177
198
|
cls = self.__class__.__name__
|
|
@@ -252,8 +273,18 @@ class HTTPRunDB(RunDBInterface):
|
|
|
252
273
|
}
|
|
253
274
|
kw["cookies"] = cookies
|
|
254
275
|
else:
|
|
255
|
-
if
|
|
256
|
-
|
|
276
|
+
if (
|
|
277
|
+
mlrun.common.schemas.HeaderNames.authorization
|
|
278
|
+
not in kw.setdefault("headers", {})
|
|
279
|
+
):
|
|
280
|
+
kw["headers"].update(
|
|
281
|
+
{
|
|
282
|
+
mlrun.common.schemas.HeaderNames.authorization: (
|
|
283
|
+
mlrun.common.schemas.AuthorizationHeaderPrefixes.bearer
|
|
284
|
+
+ token
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
)
|
|
257
288
|
|
|
258
289
|
if mlrun.common.schemas.HeaderNames.client_version not in kw.setdefault(
|
|
259
290
|
"headers", {}
|
|
@@ -273,10 +304,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
273
304
|
if isinstance(dict_[key], enum.Enum):
|
|
274
305
|
dict_[key] = dict_[key].value
|
|
275
306
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
307
|
+
retry_on_post = self._is_retry_on_post_allowed(method, path)
|
|
308
|
+
|
|
309
|
+
retry_on_put = self._is_retry_put_allowed(method, path)
|
|
310
|
+
|
|
311
|
+
# if the method is POST or PUT, we need to update the session with the appropriate retry policy
|
|
312
|
+
if not self.session or method in ("POST", "PUT"):
|
|
313
|
+
self.session = self._init_session(retry_on_post, retry_on_put)
|
|
280
314
|
|
|
281
315
|
try:
|
|
282
316
|
response = self.session.request(
|
|
@@ -392,11 +426,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
392
426
|
data.extend(response.json().get(key, []))
|
|
393
427
|
return data, page_token
|
|
394
428
|
|
|
395
|
-
def _init_session(self, retry_on_post: bool = False):
|
|
429
|
+
def _init_session(self, retry_on_post: bool = False, retry_on_put: bool = True):
|
|
396
430
|
return mlrun.utils.HTTPSessionWithRetry(
|
|
397
431
|
retry_on_exception=config.httpdb.retry_api_call_on_exception
|
|
398
432
|
== mlrun.common.schemas.HTTPSessionRetryMode.enabled.value,
|
|
399
433
|
retry_on_post=retry_on_post,
|
|
434
|
+
retry_on_put=retry_on_put,
|
|
400
435
|
)
|
|
401
436
|
|
|
402
437
|
def _path_of(self, resource, project, uid=None):
|
|
@@ -418,7 +453,28 @@ class HTTPRunDB(RunDBInterface):
|
|
|
418
453
|
re.match(regex, path) for regex in self.RETRIABLE_POST_PATHS
|
|
419
454
|
)
|
|
420
455
|
|
|
421
|
-
def
|
|
456
|
+
def _is_retry_put_allowed(self, method: str, path: str) -> bool:
|
|
457
|
+
"""
|
|
458
|
+
Determine if PUT request to the given path should be retried.
|
|
459
|
+
|
|
460
|
+
:param method: HTTP method
|
|
461
|
+
:param path: API path to check
|
|
462
|
+
:return: True if retry is allowed, False otherwise
|
|
463
|
+
"""
|
|
464
|
+
if method != "PUT":
|
|
465
|
+
return True
|
|
466
|
+
|
|
467
|
+
# Strip query parameters and fragment if present
|
|
468
|
+
parsed_path = urlparse(path).path.lstrip("/")
|
|
469
|
+
|
|
470
|
+
# If the path matches a non-retriable path, do not allow retry
|
|
471
|
+
for regex in self.NON_RETRIABLE_PATHS:
|
|
472
|
+
if re.fullmatch(regex, parsed_path):
|
|
473
|
+
return False
|
|
474
|
+
|
|
475
|
+
return True
|
|
476
|
+
|
|
477
|
+
def connect(self, secrets=None) -> typing.Self:
|
|
422
478
|
"""Connect to the MLRun API server. Must be called prior to executing any other method.
|
|
423
479
|
The code utilizes the URL for the API server from the configuration - ``config.dbpath``.
|
|
424
480
|
|
|
@@ -429,7 +485,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
429
485
|
"""
|
|
430
486
|
# hack to allow unit tests to instantiate HTTPRunDB without a real server behind
|
|
431
487
|
if "mock-server" in self.base_url:
|
|
432
|
-
return
|
|
488
|
+
return self
|
|
489
|
+
|
|
433
490
|
resp = self.api_call("GET", "client-spec", timeout=5)
|
|
434
491
|
try:
|
|
435
492
|
server_cfg = resp.json()
|
|
@@ -581,6 +638,44 @@ class HTTPRunDB(RunDBInterface):
|
|
|
581
638
|
prefix,
|
|
582
639
|
store_prefix_value,
|
|
583
640
|
)
|
|
641
|
+
config.httpdb.authentication.mode = (
|
|
642
|
+
server_cfg.get("authentication_mode")
|
|
643
|
+
or config.httpdb.authentication.mode
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
# Iguazio V4 OAuth token config auto-initialization
|
|
647
|
+
if (
|
|
648
|
+
config.httpdb.authentication.mode
|
|
649
|
+
== mlrun.common.types.AuthenticationMode.IGUAZIO_V4.value
|
|
650
|
+
):
|
|
651
|
+
if not config.auth_with_oauth_token.token_file:
|
|
652
|
+
user_token_file = os.path.expanduser("~/.igz.yml")
|
|
653
|
+
|
|
654
|
+
# runtimes
|
|
655
|
+
# TODO: change to os.getenv("MLRUN_RUNTIME_KIND")
|
|
656
|
+
# when https://github.com/mlrun/mlrun/pull/9121 is done.
|
|
657
|
+
if (
|
|
658
|
+
mlrun.k8s_utils.is_running_inside_kubernetes_cluster()
|
|
659
|
+
and not os.environ.get("JPY_SESSION_NAME")
|
|
660
|
+
):
|
|
661
|
+
user_token_file = os.path.join(
|
|
662
|
+
mlrun.common.constants.MLRUN_JOB_AUTH_SECRET_PATH,
|
|
663
|
+
mlrun.common.constants.MLRUN_JOB_AUTH_SECRET_FILE,
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
config.auth_with_oauth_token.token_file = user_token_file
|
|
667
|
+
|
|
668
|
+
# if running inside kubernetes, use the internal endpoint, otherwise use the external endpoint
|
|
669
|
+
if mlrun.k8s_utils.is_running_inside_kubernetes_cluster():
|
|
670
|
+
config.auth_token_endpoint = server_cfg.get(
|
|
671
|
+
"oauth_internal_token_endpoint"
|
|
672
|
+
)
|
|
673
|
+
else:
|
|
674
|
+
config.auth_token_endpoint = server_cfg.get(
|
|
675
|
+
"oauth_external_token_endpoint"
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
config.auth_with_oauth_token.enabled = True
|
|
584
679
|
|
|
585
680
|
except Exception as exc:
|
|
586
681
|
logger.warning(
|
|
@@ -588,6 +683,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
588
683
|
exc=err_to_str(exc),
|
|
589
684
|
traceback=traceback.format_exc(),
|
|
590
685
|
)
|
|
686
|
+
|
|
687
|
+
# Initialize token provider after syncing config from server
|
|
688
|
+
self._init_token_provider()
|
|
689
|
+
|
|
690
|
+
if config.is_iguazio_v4_mode() and config.auth_with_oauth_token.enabled:
|
|
691
|
+
mlrun.secrets.sync_secret_tokens()
|
|
591
692
|
return self
|
|
592
693
|
|
|
593
694
|
def store_log(self, uid, project="", body=None, append=False):
|
|
@@ -1231,7 +1332,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1231
1332
|
format_: Optional[
|
|
1232
1333
|
mlrun.common.formatters.ArtifactFormat
|
|
1233
1334
|
] = mlrun.common.formatters.ArtifactFormat.full,
|
|
1234
|
-
limit: Optional[int] = None,
|
|
1235
1335
|
partition_by: Optional[
|
|
1236
1336
|
Union[mlrun.common.schemas.ArtifactPartitionByField, str]
|
|
1237
1337
|
] = None,
|
|
@@ -1284,7 +1384,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1284
1384
|
points to a run and is used to filter artifacts by the run that produced them when the artifact producer id
|
|
1285
1385
|
is a workflow id (artifact was created as part of a workflow).
|
|
1286
1386
|
:param format_: The format in which to return the artifacts. Default is 'full'.
|
|
1287
|
-
:param limit: Deprecated - Maximum number of artifacts to return (will be removed in 1.11.0).
|
|
1288
1387
|
:param partition_by: Field to group results by. When `partition_by` is specified, the `partition_sort_by`
|
|
1289
1388
|
parameter must be provided as well.
|
|
1290
1389
|
:param rows_per_partition: How many top rows (per sorting defined by `partition_sort_by` and `partition_order`)
|
|
@@ -1308,12 +1407,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1308
1407
|
tree=tree,
|
|
1309
1408
|
producer_uri=producer_uri,
|
|
1310
1409
|
format_=format_,
|
|
1311
|
-
limit=limit,
|
|
1312
1410
|
partition_by=partition_by,
|
|
1313
1411
|
rows_per_partition=rows_per_partition,
|
|
1314
1412
|
partition_sort_by=partition_sort_by,
|
|
1315
1413
|
partition_order=partition_order,
|
|
1316
|
-
return_all=
|
|
1414
|
+
return_all=True,
|
|
1317
1415
|
parent=parent,
|
|
1318
1416
|
)
|
|
1319
1417
|
return artifacts
|
|
@@ -2204,7 +2302,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2204
2302
|
:param project: The project of the pipeline
|
|
2205
2303
|
:param pipeline: Pipeline function or path to .yaml/.zip pipeline file.
|
|
2206
2304
|
:param arguments: A dictionary of arguments to pass to the pipeline.
|
|
2207
|
-
:param experiment: A name to assign for the specific experiment.
|
|
2305
|
+
:param experiment: (deprecated) A name to assign for the specific experiment.
|
|
2208
2306
|
:param run: A name for this specific run.
|
|
2209
2307
|
:param namespace: Kubernetes namespace to execute the pipeline in.
|
|
2210
2308
|
:param artifact_path: A path to artifacts used by this pipeline.
|
|
@@ -2213,6 +2311,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2213
2311
|
workflow and all its resources are deleted)
|
|
2214
2312
|
:param timeout: Timeout for the API call.
|
|
2215
2313
|
"""
|
|
2314
|
+
if experiment is not None:
|
|
2315
|
+
warnings.warn(
|
|
2316
|
+
"The 'experiment' parameter is deprecated and will be removed in 1.13.0. "
|
|
2317
|
+
"Pipelines are automatically scoped by project.",
|
|
2318
|
+
# TODO: Remove this in 1.13.0
|
|
2319
|
+
FutureWarning,
|
|
2320
|
+
)
|
|
2216
2321
|
|
|
2217
2322
|
if isinstance(pipeline, str):
|
|
2218
2323
|
pipe_file = pipeline
|
|
@@ -2554,50 +2659,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2554
2659
|
resp = self.api_call("GET", path, error_message)
|
|
2555
2660
|
return FeatureSet.from_dict(resp.json())
|
|
2556
2661
|
|
|
2557
|
-
def list_features(
|
|
2558
|
-
self,
|
|
2559
|
-
project: Optional[str] = None,
|
|
2560
|
-
name: Optional[str] = None,
|
|
2561
|
-
tag: Optional[str] = None,
|
|
2562
|
-
entities: Optional[list[str]] = None,
|
|
2563
|
-
labels: Optional[Union[str, dict[str, Optional[str]], list[str]]] = None,
|
|
2564
|
-
) -> list[dict]:
|
|
2565
|
-
"""List feature-sets which contain specific features. This function may return multiple versions of the same
|
|
2566
|
-
feature-set if a specific tag is not requested. Note that the various filters of this function actually
|
|
2567
|
-
refer to the feature-set object containing the features, not to the features themselves.
|
|
2568
|
-
|
|
2569
|
-
:param project: Project which contains these features.
|
|
2570
|
-
:param name: Name of the feature to look for. The name is used in a like query, and is not case-sensitive. For
|
|
2571
|
-
example, looking for ``feat`` will return features which are named ``MyFeature`` as well as ``defeat``.
|
|
2572
|
-
:param tag: Return feature-sets which contain the features looked for, and are tagged with the specific tag.
|
|
2573
|
-
:param entities: Return only feature-sets which contain an entity whose name is contained in this list.
|
|
2574
|
-
:param labels: Filter feature-sets by label key-value pairs or key existence. This can be provided as:
|
|
2575
|
-
- A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
|
|
2576
|
-
or `{"label": None}` to check for key existence.
|
|
2577
|
-
- A list of strings formatted as `"label=value"` to match specific label key-value pairs,
|
|
2578
|
-
or just `"label"` for key existence.
|
|
2579
|
-
- A comma-separated string formatted as `"label1=value1,label2"` to match entities with
|
|
2580
|
-
the specified key-value pairs or key existence.
|
|
2581
|
-
:returns: A list of mapping from feature to a digest of the feature-set, which contains the feature-set
|
|
2582
|
-
meta-data. Multiple entries may be returned for any specific feature due to multiple tags or versions
|
|
2583
|
-
of the feature-set.
|
|
2584
|
-
"""
|
|
2585
|
-
|
|
2586
|
-
project = project or config.active_project
|
|
2587
|
-
labels = self._parse_labels(labels)
|
|
2588
|
-
params = {
|
|
2589
|
-
"name": name,
|
|
2590
|
-
"tag": tag,
|
|
2591
|
-
"entity": entities or [],
|
|
2592
|
-
"label": labels,
|
|
2593
|
-
}
|
|
2594
|
-
|
|
2595
|
-
path = f"projects/{project}/features"
|
|
2596
|
-
|
|
2597
|
-
error_message = f"Failed listing features, project: {project}, query: {params}"
|
|
2598
|
-
resp = self.api_call("GET", path, error_message, params=params)
|
|
2599
|
-
return resp.json()["features"]
|
|
2600
|
-
|
|
2601
2662
|
def list_features_v2(
|
|
2602
2663
|
self,
|
|
2603
2664
|
project: Optional[str] = None,
|
|
@@ -3623,7 +3684,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3623
3684
|
intersection {"intersect_metrics":[], "intersect_results":[]}
|
|
3624
3685
|
:return: A dictionary of application metrics and/or results for the model endpoints formatted by events_format.
|
|
3625
3686
|
"""
|
|
3626
|
-
path = f"projects/{project}/model-
|
|
3687
|
+
path = f"projects/{project}/model-monitoring/metrics"
|
|
3627
3688
|
params = {
|
|
3628
3689
|
"type": type,
|
|
3629
3690
|
"endpoint-id": endpoint_ids,
|
|
@@ -3647,40 +3708,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3647
3708
|
)
|
|
3648
3709
|
return parsed_metrics_by_endpoint
|
|
3649
3710
|
|
|
3650
|
-
def create_user_secrets(
|
|
3651
|
-
self,
|
|
3652
|
-
user: str,
|
|
3653
|
-
provider: Union[
|
|
3654
|
-
str, mlrun.common.schemas.SecretProviderName
|
|
3655
|
-
] = mlrun.common.schemas.SecretProviderName.vault,
|
|
3656
|
-
secrets: Optional[dict] = None,
|
|
3657
|
-
):
|
|
3658
|
-
"""Create user-context secret in Vault. Please refer to :py:func:`create_project_secrets` for more details
|
|
3659
|
-
and status of this functionality.
|
|
3660
|
-
|
|
3661
|
-
Note:
|
|
3662
|
-
This method is currently in technical preview, and requires a HashiCorp Vault infrastructure
|
|
3663
|
-
properly set up and connected to the MLRun API server.
|
|
3664
|
-
|
|
3665
|
-
:param user: The user context for which to generate the infra and store secrets.
|
|
3666
|
-
:param provider: The name of the secrets-provider to work with. Currently only ``vault`` is supported.
|
|
3667
|
-
:param secrets: A set of secret values to store within the Vault.
|
|
3668
|
-
"""
|
|
3669
|
-
path = "user-secrets"
|
|
3670
|
-
secrets_creation_request = mlrun.common.schemas.UserSecretCreationRequest(
|
|
3671
|
-
user=user,
|
|
3672
|
-
provider=provider,
|
|
3673
|
-
secrets=secrets,
|
|
3674
|
-
)
|
|
3675
|
-
body = secrets_creation_request.dict()
|
|
3676
|
-
error_message = f"Failed creating user secrets - {user}"
|
|
3677
|
-
self.api_call(
|
|
3678
|
-
"POST",
|
|
3679
|
-
path,
|
|
3680
|
-
error_message,
|
|
3681
|
-
body=dict_to_json(body),
|
|
3682
|
-
)
|
|
3683
|
-
|
|
3684
3711
|
@staticmethod
|
|
3685
3712
|
def _validate_version_compatibility(server_version, client_version) -> bool:
|
|
3686
3713
|
try:
|
|
@@ -3813,7 +3840,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3813
3840
|
tsdb_metrics: bool = False,
|
|
3814
3841
|
metric_list: Optional[list[str]] = None,
|
|
3815
3842
|
top_level: bool = False,
|
|
3816
|
-
|
|
3843
|
+
modes: Optional[
|
|
3844
|
+
Union[mm_constants.EndpointMode, list[mm_constants.EndpointMode]]
|
|
3845
|
+
] = None,
|
|
3817
3846
|
uids: Optional[list[str]] = None,
|
|
3818
3847
|
latest_only: bool = False,
|
|
3819
3848
|
) -> mlrun.common.schemas.ModelEndpointList:
|
|
@@ -3834,8 +3863,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3834
3863
|
If tsdb_metrics=False, this parameter will be ignored and no tsdb metrics
|
|
3835
3864
|
will be included.
|
|
3836
3865
|
:param top_level: Whether to return only top level model endpoints.
|
|
3837
|
-
:param
|
|
3838
|
-
to None.
|
|
3866
|
+
:param modes: Specifies the modes of the model endpoints. Can be "real-time" (0), "batch" (1),
|
|
3867
|
+
"batch_legacy" (2). If set to None, all are included.
|
|
3839
3868
|
:param uids: A list of unique ids to filter by.
|
|
3840
3869
|
:param latest_only: Whether to return only the latest model endpoint version.
|
|
3841
3870
|
:return: A list of model endpoints.
|
|
@@ -3844,6 +3873,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3844
3873
|
labels = self._parse_labels(labels)
|
|
3845
3874
|
if names and isinstance(names, str):
|
|
3846
3875
|
names = [names]
|
|
3876
|
+
if modes:
|
|
3877
|
+
# Ensure backward compatibility with Python 3.9 clients by converting IntEnum modes to integer values
|
|
3878
|
+
modes = (
|
|
3879
|
+
[modes.value]
|
|
3880
|
+
if isinstance(modes, mm_constants.EndpointMode)
|
|
3881
|
+
else [mode.value for mode in modes]
|
|
3882
|
+
)
|
|
3847
3883
|
response = self.api_call(
|
|
3848
3884
|
method=mlrun.common.types.HTTPMethod.GET,
|
|
3849
3885
|
path=path,
|
|
@@ -3859,7 +3895,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3859
3895
|
"tsdb-metrics": tsdb_metrics,
|
|
3860
3896
|
"metric": metric_list,
|
|
3861
3897
|
"top-level": top_level,
|
|
3862
|
-
"mode":
|
|
3898
|
+
"mode": modes,
|
|
3863
3899
|
"uid": uids,
|
|
3864
3900
|
"latest-only": latest_only,
|
|
3865
3901
|
},
|
|
@@ -3968,6 +4004,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3968
4004
|
raise MLRunInvalidArgumentError(
|
|
3969
4005
|
"Either endpoint_uid or function_name and function_tag must be provided"
|
|
3970
4006
|
)
|
|
4007
|
+
if uid:
|
|
4008
|
+
try:
|
|
4009
|
+
UUID(uid)
|
|
4010
|
+
except (ValueError, TypeError):
|
|
4011
|
+
raise MLRunInvalidArgumentError(
|
|
4012
|
+
"endpoint_id must be a valid UUID string"
|
|
4013
|
+
)
|
|
3971
4014
|
|
|
3972
4015
|
def update_model_monitoring_controller(
|
|
3973
4016
|
self,
|
|
@@ -4115,7 +4158,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4115
4158
|
response = self.api_call(
|
|
4116
4159
|
method=mlrun.common.types.HTTPMethod.DELETE,
|
|
4117
4160
|
path=f"projects/{project}/model-monitoring/functions",
|
|
4118
|
-
params={"
|
|
4161
|
+
params={"function": functions},
|
|
4119
4162
|
)
|
|
4120
4163
|
deletion_failed = False
|
|
4121
4164
|
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
@@ -4157,6 +4200,26 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4157
4200
|
params={**credentials, "replace_creds": replace_creds},
|
|
4158
4201
|
)
|
|
4159
4202
|
|
|
4203
|
+
def delete_model_monitoring_metrics(
|
|
4204
|
+
self,
|
|
4205
|
+
project: str,
|
|
4206
|
+
application_name: str,
|
|
4207
|
+
endpoint_ids: Optional[list[str]] = None,
|
|
4208
|
+
) -> None:
|
|
4209
|
+
"""
|
|
4210
|
+
Delete model endpoints metrics values.
|
|
4211
|
+
|
|
4212
|
+
:param project: The name of the project.
|
|
4213
|
+
:param application_name: The name of the application.
|
|
4214
|
+
:param endpoint_ids: The unique IDs of the model endpoints to delete metrics values from. If none is
|
|
4215
|
+
provided, the metrics values will be deleted from all project's model endpoints.
|
|
4216
|
+
"""
|
|
4217
|
+
self.api_call(
|
|
4218
|
+
method=mlrun.common.types.HTTPMethod.DELETE,
|
|
4219
|
+
path=f"projects/{project}/model-monitoring/metrics",
|
|
4220
|
+
params={"endpoint-id": endpoint_ids, "application-name": application_name},
|
|
4221
|
+
)
|
|
4222
|
+
|
|
4160
4223
|
def get_monitoring_function_summaries(
|
|
4161
4224
|
self,
|
|
4162
4225
|
project: str,
|
|
@@ -4171,8 +4234,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4171
4234
|
Get monitoring function summaries for the specified project.
|
|
4172
4235
|
|
|
4173
4236
|
:param project: The name of the project.
|
|
4174
|
-
:param start:
|
|
4175
|
-
|
|
4237
|
+
:param start: The start time of the monitoring applications’ statistics.
|
|
4238
|
+
If not defined, the default is 24 hours ago.
|
|
4239
|
+
Required timezone, applicable only when `include_stats` is set to True.
|
|
4240
|
+
:param end: The end time of the monitoring applications’ statistics.
|
|
4241
|
+
If not defined, the default is now.
|
|
4242
|
+
Required timezone, applicable only when `include_stats` is set to True.
|
|
4176
4243
|
:param names: List of function names to filter by (optional).
|
|
4177
4244
|
:param labels: Labels to filter by (optional).
|
|
4178
4245
|
:param include_stats: Whether to include statistics in the response (default is False).
|
|
@@ -4213,12 +4280,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4213
4280
|
) -> FunctionSummary:
|
|
4214
4281
|
"""
|
|
4215
4282
|
Get a monitoring function summary for the specified project and function.
|
|
4216
|
-
:param project: The name of the project.
|
|
4217
|
-
:param function_name: The name of the function.
|
|
4218
|
-
:param start: Start time for filtering the results (optional).
|
|
4219
|
-
:param end: End time for filtering the results (optional).
|
|
4220
|
-
:param include_latest_metrics: Whether to include the latest metrics in the response (default is False).
|
|
4221
4283
|
|
|
4284
|
+
:param project: The name of the project.
|
|
4285
|
+
:param function_name: The name of the function.
|
|
4286
|
+
:param start: The start time of the monitoring application's statistics.
|
|
4287
|
+
If not defined, the default is 24 hours ago. Required timezone.
|
|
4288
|
+
:param end: The end time of the monitoring application's statistics.
|
|
4289
|
+
If not defined, the default is now. Required timezone.
|
|
4290
|
+
:param include_latest_metrics: Whether to include the latest metrics in the response (default is False).
|
|
4222
4291
|
:return: A FunctionSummary object containing information about the monitoring function.
|
|
4223
4292
|
"""
|
|
4224
4293
|
|
|
@@ -4323,6 +4392,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4323
4392
|
item_name: Optional[str] = None,
|
|
4324
4393
|
tag: Optional[str] = None,
|
|
4325
4394
|
version: Optional[str] = None,
|
|
4395
|
+
item_type: HubSourceType = HubSourceType.functions,
|
|
4326
4396
|
) -> list[mlrun.common.schemas.hub.IndexedHubSource]:
|
|
4327
4397
|
"""
|
|
4328
4398
|
List hub sources in the MLRun DB.
|
|
@@ -4330,6 +4400,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4330
4400
|
:param item_name: Sources contain this item will be returned, If not provided all sources will be returned.
|
|
4331
4401
|
:param tag: Item tag to filter by, supported only if item name is provided.
|
|
4332
4402
|
:param version: Item version to filter by, supported only if item name is provided and tag is not.
|
|
4403
|
+
:param item_type: Item type to filter by, supported only if item name is provided.
|
|
4333
4404
|
|
|
4334
4405
|
:returns: List of indexed hub sources.
|
|
4335
4406
|
"""
|
|
@@ -4337,6 +4408,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4337
4408
|
params = {}
|
|
4338
4409
|
if item_name:
|
|
4339
4410
|
params["item-name"] = normalize_name(item_name)
|
|
4411
|
+
params["item-type"] = item_type
|
|
4340
4412
|
if tag:
|
|
4341
4413
|
params["tag"] = tag
|
|
4342
4414
|
if version:
|
|
@@ -4375,6 +4447,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4375
4447
|
version: Optional[str] = None,
|
|
4376
4448
|
tag: Optional[str] = None,
|
|
4377
4449
|
force_refresh: bool = False,
|
|
4450
|
+
object_type: HubSourceType = HubSourceType.functions,
|
|
4378
4451
|
):
|
|
4379
4452
|
"""
|
|
4380
4453
|
Retrieve the item catalog for a specified hub source.
|
|
@@ -4387,6 +4460,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4387
4460
|
rather than rely on cached information which may exist from previous get requests. For example,
|
|
4388
4461
|
if the source was re-built,
|
|
4389
4462
|
this will make the server get the updated information. Default is ``False``.
|
|
4463
|
+
:param object_type: Type of object to retrieve from the hub source (e.g: functions, modules).
|
|
4390
4464
|
:returns: :py:class:`~mlrun.common.schemas.hub.HubCatalog` object, which is essentially a list
|
|
4391
4465
|
of :py:class:`~mlrun.common.schemas.hub.HubItem` entries.
|
|
4392
4466
|
"""
|
|
@@ -4395,6 +4469,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4395
4469
|
"version": version,
|
|
4396
4470
|
"tag": tag,
|
|
4397
4471
|
"force-refresh": force_refresh,
|
|
4472
|
+
"object_type": object_type,
|
|
4398
4473
|
}
|
|
4399
4474
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4400
4475
|
return mlrun.common.schemas.HubCatalog(**response.json())
|
|
@@ -4406,6 +4481,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4406
4481
|
version: Optional[str] = None,
|
|
4407
4482
|
tag: str = "latest",
|
|
4408
4483
|
force_refresh: bool = False,
|
|
4484
|
+
item_type: HubSourceType = HubSourceType.functions,
|
|
4409
4485
|
):
|
|
4410
4486
|
"""
|
|
4411
4487
|
Retrieve a specific hub item.
|
|
@@ -4417,13 +4493,15 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4417
4493
|
:param force_refresh: Make the server fetch the information from the actual hub
|
|
4418
4494
|
source, rather than
|
|
4419
4495
|
rely on cached information. Default is ``False``.
|
|
4496
|
+
:param item_type: The type of item to retrieve from the hub source (e.g: functions, modules).
|
|
4420
4497
|
:returns: :py:class:`~mlrun.common.schemas.hub.HubItem`.
|
|
4421
4498
|
"""
|
|
4422
|
-
path =
|
|
4499
|
+
path = f"hub/sources/{source_name}/items/{item_name}"
|
|
4423
4500
|
params = {
|
|
4424
4501
|
"version": version,
|
|
4425
4502
|
"tag": tag,
|
|
4426
4503
|
"force-refresh": force_refresh,
|
|
4504
|
+
"item_type": item_type,
|
|
4427
4505
|
}
|
|
4428
4506
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4429
4507
|
return mlrun.common.schemas.HubItem(**response.json())
|
|
@@ -4435,6 +4513,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4435
4513
|
asset_name: str,
|
|
4436
4514
|
version: Optional[str] = None,
|
|
4437
4515
|
tag: str = "latest",
|
|
4516
|
+
item_type: HubSourceType = HubSourceType.functions,
|
|
4438
4517
|
):
|
|
4439
4518
|
"""
|
|
4440
4519
|
Get hub asset from item.
|
|
@@ -4444,13 +4523,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4444
4523
|
:param asset_name: Name of the asset to retrieve.
|
|
4445
4524
|
:param version: Get a specific version of the item. Default is ``None``.
|
|
4446
4525
|
:param tag: Get a specific version of the item identified by tag. Default is ``latest``.
|
|
4447
|
-
|
|
4526
|
+
:param item_type: The type of item to retrieve from the hub source (e.g: functions, modules).
|
|
4448
4527
|
:returns: http response with the asset in the content attribute
|
|
4449
4528
|
"""
|
|
4450
4529
|
path = f"hub/sources/{source_name}/items/{item_name}/assets/{asset_name}"
|
|
4451
4530
|
params = {
|
|
4452
4531
|
"version": version,
|
|
4453
4532
|
"tag": tag,
|
|
4533
|
+
"item_type": item_type,
|
|
4454
4534
|
}
|
|
4455
4535
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4456
4536
|
return response
|
|
@@ -5205,7 +5285,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
5205
5285
|
|
|
5206
5286
|
:return: A ModelEndpointDriftValues object containing the drift counts over time.
|
|
5207
5287
|
"""
|
|
5208
|
-
endpoint_path = f"projects/{project}/model-
|
|
5288
|
+
endpoint_path = f"projects/{project}/model-monitoring/drift-over-time"
|
|
5209
5289
|
error_message = f"Failed retrieving drift data for {project}"
|
|
5210
5290
|
response = self.api_call(
|
|
5211
5291
|
method="GET",
|
|
@@ -5217,6 +5297,152 @@ class HTTPRunDB(RunDBInterface):
|
|
|
5217
5297
|
**response.json()
|
|
5218
5298
|
)
|
|
5219
5299
|
|
|
5300
|
+
@mlrun.utils.iguazio_v4_only
|
|
5301
|
+
def store_secret_token(
|
|
5302
|
+
self,
|
|
5303
|
+
secret_token: mlrun.common.schemas.SecretToken,
|
|
5304
|
+
log_warning: bool = True,
|
|
5305
|
+
force: bool = False,
|
|
5306
|
+
) -> mlrun.common.schemas.StoreSecretTokensResponse:
|
|
5307
|
+
"""
|
|
5308
|
+
Store or update a single secret token in the MLRun backend.
|
|
5309
|
+
|
|
5310
|
+
Example::
|
|
5311
|
+
|
|
5312
|
+
from mlrun.common.schemas import SecretToken
|
|
5313
|
+
|
|
5314
|
+
secret = SecretToken(name="my-token", token="dummy-token")
|
|
5315
|
+
db.store_secret_token(secret)
|
|
5316
|
+
|
|
5317
|
+
:param secret_token: A SecretToken object with name and token fields.
|
|
5318
|
+
:param force: Whether to force update the token if it already exists. Defaults to False.
|
|
5319
|
+
:param log_warning: Whether to log a warning about local config sync. Defaults to True.
|
|
5320
|
+
:return: A structured response indicating which tokens were created, updated, or skipped.
|
|
5321
|
+
"""
|
|
5322
|
+
if not secret_token:
|
|
5323
|
+
raise MLRunInvalidArgumentError("No secret token provided")
|
|
5324
|
+
|
|
5325
|
+
response = self._store_secret_tokens(
|
|
5326
|
+
secret_tokens=[secret_token],
|
|
5327
|
+
force=force,
|
|
5328
|
+
error=f"store user secret token {secret_token.name}",
|
|
5329
|
+
)
|
|
5330
|
+
|
|
5331
|
+
# Only log if the token was created or updated
|
|
5332
|
+
if log_warning and (
|
|
5333
|
+
secret_token.name in response.created_tokens
|
|
5334
|
+
or secret_token.name in response.updated_tokens
|
|
5335
|
+
):
|
|
5336
|
+
logger.warning(
|
|
5337
|
+
f"Token '{secret_token.name}' was stored in the backend, "
|
|
5338
|
+
f"but the local configuration file ({mlrun.mlconf.auth_with_oauth_token.token_file}) was not "
|
|
5339
|
+
"updated. Update it manually or run `mlrun.sync_secret_tokens()` to sync your local environment."
|
|
5340
|
+
)
|
|
5341
|
+
# maybe the response should not be a list?
|
|
5342
|
+
return response
|
|
5343
|
+
|
|
5344
|
+
@mlrun.utils.iguazio_v4_only
|
|
5345
|
+
def store_secret_tokens(
|
|
5346
|
+
self,
|
|
5347
|
+
secret_tokens: list[mlrun.common.schemas.SecretToken],
|
|
5348
|
+
log_warning: bool = True,
|
|
5349
|
+
force: bool = False,
|
|
5350
|
+
) -> mlrun.common.schemas.StoreSecretTokensResponse:
|
|
5351
|
+
"""
|
|
5352
|
+
Store or update multiple secret tokens in the MLRun backend.
|
|
5353
|
+
|
|
5354
|
+
Example::
|
|
5355
|
+
|
|
5356
|
+
from mlrun.common.schemas import SecretToken
|
|
5357
|
+
|
|
5358
|
+
tokens = [
|
|
5359
|
+
SecretToken(name="token1", token="dummy-token-1"),
|
|
5360
|
+
SecretToken(name="token2", token="dummy-token-2"),
|
|
5361
|
+
]
|
|
5362
|
+
db.store_secret_tokens(tokens)
|
|
5363
|
+
|
|
5364
|
+
:param secret_tokens: List of SecretToken objects with 'name' and 'token' fields.
|
|
5365
|
+
:param force: Whether to force update tokens if they already exist. Defaults to False.
|
|
5366
|
+
:param log_warning: Whether to log a warning about local config file sync. Defaults to True.
|
|
5367
|
+
:return: StoreSecretTokensResponse object indicating which tokens were created, updated, or skipped.
|
|
5368
|
+
"""
|
|
5369
|
+
if not secret_tokens:
|
|
5370
|
+
raise MLRunInvalidArgumentError("No secret tokens provided")
|
|
5371
|
+
|
|
5372
|
+
response = self._store_secret_tokens(
|
|
5373
|
+
secret_tokens=secret_tokens,
|
|
5374
|
+
force=force,
|
|
5375
|
+
error="store multiple user secret tokens",
|
|
5376
|
+
)
|
|
5377
|
+
|
|
5378
|
+
# Only log a warning if at least one token was actually created or updated
|
|
5379
|
+
if log_warning and (response.created_tokens or response.updated_tokens):
|
|
5380
|
+
affected_tokens = response.created_tokens + response.updated_tokens
|
|
5381
|
+
token_names = "', '".join(affected_tokens)
|
|
5382
|
+
logger.warning(
|
|
5383
|
+
f"Tokens '{token_names}' were stored in the backend, "
|
|
5384
|
+
f"but the local configuration file ({mlrun.mlconf.auth_with_oauth_token.token_file}) was not "
|
|
5385
|
+
"updated. Update it manually or run `mlrun.sync_secret_tokens()` to sync your local environment."
|
|
5386
|
+
)
|
|
5387
|
+
|
|
5388
|
+
return response
|
|
5389
|
+
|
|
5390
|
+
@mlrun.utils.iguazio_v4_only
|
|
5391
|
+
def list_secret_tokens(
|
|
5392
|
+
self,
|
|
5393
|
+
) -> mlrun.common.schemas.ListSecretTokensResponse:
|
|
5394
|
+
"""
|
|
5395
|
+
List all secret tokens for the current user.
|
|
5396
|
+
"""
|
|
5397
|
+
endpoint_path = "user-secrets/tokens"
|
|
5398
|
+
response = self.api_call(
|
|
5399
|
+
mlrun.common.types.HTTPMethod.GET,
|
|
5400
|
+
endpoint_path,
|
|
5401
|
+
"list user secret tokens",
|
|
5402
|
+
)
|
|
5403
|
+
|
|
5404
|
+
return mlrun.common.schemas.ListSecretTokensResponse(**response.json())
|
|
5405
|
+
|
|
5406
|
+
@mlrun.utils.iguazio_v4_only
|
|
5407
|
+
def revoke_secret_token(self, token_name: str) -> None:
|
|
5408
|
+
endpoint_path = f"user-secrets/tokens/{token_name}"
|
|
5409
|
+
self.api_call(
|
|
5410
|
+
mlrun.common.types.HTTPMethod.DELETE,
|
|
5411
|
+
endpoint_path,
|
|
5412
|
+
"delete user secret token",
|
|
5413
|
+
)
|
|
5414
|
+
|
|
5415
|
+
@mlrun.utils.iguazio_v4_only
|
|
5416
|
+
def get_secret_token(
|
|
5417
|
+
self,
|
|
5418
|
+
token_name: str,
|
|
5419
|
+
username: Optional[str] = None,
|
|
5420
|
+
) -> mlrun.common.schemas.SecretToken:
|
|
5421
|
+
raise NotImplementedError(
|
|
5422
|
+
"Getting secret token is not supported for security reasons."
|
|
5423
|
+
)
|
|
5424
|
+
|
|
5425
|
+
@mlrun.utils.iguazio_v4_only
|
|
5426
|
+
def _store_secret_tokens(
|
|
5427
|
+
self,
|
|
5428
|
+
secret_tokens: list[mlrun.common.schemas.SecretToken],
|
|
5429
|
+
error: str,
|
|
5430
|
+
force: bool = False,
|
|
5431
|
+
) -> mlrun.common.schemas.StoreSecretTokensResponse:
|
|
5432
|
+
body = [token.dict() for token in secret_tokens]
|
|
5433
|
+
params = {"force": force} # send as query param
|
|
5434
|
+
endpoint_path = "user-secrets/tokens"
|
|
5435
|
+
|
|
5436
|
+
response = self.api_call(
|
|
5437
|
+
mlrun.common.types.HTTPMethod.PUT,
|
|
5438
|
+
endpoint_path,
|
|
5439
|
+
error,
|
|
5440
|
+
params=params,
|
|
5441
|
+
body=dict_to_json(body),
|
|
5442
|
+
)
|
|
5443
|
+
|
|
5444
|
+
return mlrun.common.schemas.StoreSecretTokensResponse(**response.json())
|
|
5445
|
+
|
|
5220
5446
|
@staticmethod
|
|
5221
5447
|
def _parse_labels(
|
|
5222
5448
|
labels: Optional[Union[str, dict[str, Optional[str]], list[str]]],
|
|
@@ -5257,7 +5483,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
5257
5483
|
format_: Optional[
|
|
5258
5484
|
mlrun.common.formatters.ArtifactFormat
|
|
5259
5485
|
] = mlrun.common.formatters.ArtifactFormat.full,
|
|
5260
|
-
limit: Optional[int] = None,
|
|
5261
5486
|
partition_by: Optional[
|
|
5262
5487
|
Union[mlrun.common.schemas.ArtifactPartitionByField, str]
|
|
5263
5488
|
] = None,
|
|
@@ -5278,13 +5503,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
5278
5503
|
project = project or config.active_project
|
|
5279
5504
|
labels = self._parse_labels(labels)
|
|
5280
5505
|
|
|
5281
|
-
if limit:
|
|
5282
|
-
# TODO: Remove this in 1.11.0
|
|
5283
|
-
warnings.warn(
|
|
5284
|
-
"'limit' is deprecated and will be removed in 1.11.0. Use 'page' and 'page_size' instead.",
|
|
5285
|
-
FutureWarning,
|
|
5286
|
-
)
|
|
5287
|
-
|
|
5288
5506
|
params = {
|
|
5289
5507
|
"name": name,
|
|
5290
5508
|
"tag": tag,
|
|
@@ -5298,7 +5516,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
5298
5516
|
"producer_uri": producer_uri,
|
|
5299
5517
|
"since": datetime_to_iso(since),
|
|
5300
5518
|
"until": datetime_to_iso(until),
|
|
5301
|
-
"limit": limit,
|
|
5302
5519
|
"page": page,
|
|
5303
5520
|
"page-size": page_size,
|
|
5304
5521
|
"page-token": page_token,
|
|
@@ -5550,24 +5767,27 @@ class HTTPRunDB(RunDBInterface):
|
|
|
5550
5767
|
if page_params.get("page-token") is None and page_params.get("page") is None:
|
|
5551
5768
|
page_params["page"] = 1
|
|
5552
5769
|
if page_params.get("page-size") is None:
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
if page_params.get("limit") is not None:
|
|
5556
|
-
page_size = page_params["limit"]
|
|
5770
|
+
page_params["page-size"] = config.httpdb.pagination.default_page_size
|
|
5557
5771
|
|
|
5558
|
-
|
|
5559
|
-
page_params.pop("limit")
|
|
5560
|
-
page_params["page-size"] = page_size
|
|
5772
|
+
return page_params
|
|
5561
5773
|
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5774
|
+
def _resolve_api_urls(self, url: str) -> tuple[str, str]:
|
|
5775
|
+
"""
|
|
5776
|
+
Resolves the base url and parsed url from the given url.
|
|
5777
|
+
"""
|
|
5778
|
+
parsed_url = urlparse(url)
|
|
5779
|
+
scheme = parsed_url.scheme.lower()
|
|
5780
|
+
if scheme not in ("http", "https"):
|
|
5781
|
+
raise ValueError(
|
|
5782
|
+
f"Invalid URL scheme {scheme} for HTTPRunDB, only http(s) is supported"
|
|
5568
5783
|
)
|
|
5569
|
-
|
|
5570
|
-
|
|
5784
|
+
|
|
5785
|
+
endpoint = parsed_url.hostname
|
|
5786
|
+
if parsed_url.port:
|
|
5787
|
+
endpoint += f":{parsed_url.port}"
|
|
5788
|
+
base_url = f"{parsed_url.scheme}://{endpoint}{parsed_url.path}"
|
|
5789
|
+
|
|
5790
|
+
return base_url, parsed_url
|
|
5571
5791
|
|
|
5572
5792
|
|
|
5573
5793
|
def _as_json(obj):
|