mlrun 1.7.0rc4__py3-none-any.whl → 1.7.2__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 +11 -1
- mlrun/__main__.py +39 -121
- mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
- mlrun/alerts/alert.py +248 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +39 -254
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +73 -46
- mlrun/artifacts/model.py +30 -158
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +73 -1
- mlrun/common/db/sql_session.py +3 -2
- mlrun/common/formatters/__init__.py +21 -0
- mlrun/common/formatters/artifact.py +46 -0
- mlrun/common/formatters/base.py +113 -0
- mlrun/common/formatters/feature_set.py +44 -0
- mlrun/common/formatters/function.py +46 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/common/formatters/run.py +29 -0
- mlrun/common/helpers.py +11 -1
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +31 -4
- mlrun/common/schemas/alert.py +202 -0
- mlrun/common/schemas/api_gateway.py +196 -0
- mlrun/common/schemas/artifact.py +28 -1
- mlrun/common/schemas/auth.py +13 -2
- mlrun/common/schemas/client_spec.py +2 -1
- mlrun/common/schemas/common.py +7 -4
- mlrun/common/schemas/constants.py +3 -0
- mlrun/common/schemas/feature_store.py +58 -28
- mlrun/common/schemas/frontend_spec.py +8 -0
- mlrun/common/schemas/function.py +11 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/__init__.py +21 -4
- mlrun/common/schemas/model_monitoring/constants.py +136 -42
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +89 -41
- mlrun/common/schemas/notification.py +69 -12
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +7 -0
- mlrun/common/schemas/project.py +67 -16
- mlrun/common/schemas/runs.py +17 -0
- mlrun/common/schemas/schedule.py +1 -1
- mlrun/common/schemas/workflow.py +10 -2
- mlrun/common/types.py +14 -1
- mlrun/config.py +233 -58
- mlrun/data_types/data_types.py +11 -1
- mlrun/data_types/spark.py +5 -4
- mlrun/data_types/to_pandas.py +75 -34
- mlrun/datastore/__init__.py +8 -10
- mlrun/datastore/alibaba_oss.py +131 -0
- mlrun/datastore/azure_blob.py +131 -43
- mlrun/datastore/base.py +107 -47
- mlrun/datastore/datastore.py +17 -7
- mlrun/datastore/datastore_profile.py +91 -7
- mlrun/datastore/dbfs_store.py +3 -7
- mlrun/datastore/filestore.py +1 -3
- mlrun/datastore/google_cloud_storage.py +92 -32
- mlrun/datastore/hdfs.py +5 -0
- mlrun/datastore/inmem.py +6 -3
- mlrun/datastore/redis.py +3 -2
- mlrun/datastore/s3.py +30 -12
- mlrun/datastore/snowflake_utils.py +45 -0
- mlrun/datastore/sources.py +274 -59
- mlrun/datastore/spark_utils.py +30 -0
- mlrun/datastore/store_resources.py +9 -7
- mlrun/datastore/storeytargets.py +151 -0
- mlrun/datastore/targets.py +387 -119
- mlrun/datastore/utils.py +68 -5
- mlrun/datastore/v3io.py +28 -50
- mlrun/db/auth_utils.py +152 -0
- mlrun/db/base.py +245 -20
- mlrun/db/factory.py +1 -4
- mlrun/db/httpdb.py +909 -231
- mlrun/db/nopdb.py +279 -14
- mlrun/errors.py +35 -5
- mlrun/execution.py +111 -38
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +46 -53
- mlrun/feature_store/common.py +6 -11
- mlrun/feature_store/feature_set.py +48 -23
- mlrun/feature_store/feature_vector.py +13 -2
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +13 -4
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +24 -32
- mlrun/feature_store/steps.py +38 -19
- mlrun/features.py +6 -14
- mlrun/frameworks/_common/plan.py +3 -3
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- mlrun/frameworks/_ml_common/plan.py +1 -1
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
- mlrun/frameworks/lgbm/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/model_handler.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +4 -4
- mlrun/frameworks/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/sklearn/mlrun_interface.py +13 -3
- mlrun/frameworks/tf_keras/__init__.py +5 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
- mlrun/frameworks/xgboost/__init__.py +1 -1
- mlrun/k8s_utils.py +57 -12
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +6 -5
- mlrun/launcher/client.py +13 -11
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +15 -5
- mlrun/launcher/remote.py +10 -3
- mlrun/lists.py +6 -2
- mlrun/model.py +297 -48
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +152 -357
- mlrun/model_monitoring/applications/__init__.py +10 -0
- mlrun/model_monitoring/applications/_application_steps.py +190 -0
- mlrun/model_monitoring/applications/base.py +108 -0
- mlrun/model_monitoring/applications/context.py +341 -0
- mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
- mlrun/model_monitoring/applications/histogram_data_drift.py +227 -91
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +130 -303
- mlrun/model_monitoring/{stores/models/sqlite.py → db/__init__.py} +5 -10
- mlrun/model_monitoring/db/stores/__init__.py +136 -0
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/db/stores/base/store.py +213 -0
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
- mlrun/model_monitoring/db/tsdb/base.py +448 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +298 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +522 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
- mlrun/model_monitoring/features_drift_table.py +34 -22
- mlrun/model_monitoring/helpers.py +177 -39
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +165 -398
- mlrun/model_monitoring/tracking_policy.py +7 -1
- mlrun/model_monitoring/writer.py +161 -125
- mlrun/package/packagers/default_packager.py +2 -2
- mlrun/package/packagers_manager.py +1 -0
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +67 -228
- mlrun/projects/__init__.py +6 -1
- mlrun/projects/operations.py +47 -20
- mlrun/projects/pipelines.py +396 -249
- mlrun/projects/project.py +1176 -406
- mlrun/render.py +28 -22
- mlrun/run.py +208 -181
- mlrun/runtimes/__init__.py +76 -11
- mlrun/runtimes/base.py +54 -24
- mlrun/runtimes/daskjob.py +9 -2
- mlrun/runtimes/databricks_job/databricks_runtime.py +1 -0
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +1 -29
- mlrun/runtimes/kubejob.py +34 -128
- mlrun/runtimes/local.py +39 -10
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +8 -8
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/runtimes/nuclio/__init__.py +1 -0
- mlrun/runtimes/nuclio/api_gateway.py +769 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +758 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/nuclio/function.py +188 -68
- mlrun/runtimes/nuclio/serving.py +57 -60
- mlrun/runtimes/pod.py +191 -58
- mlrun/runtimes/remotesparkjob.py +11 -8
- mlrun/runtimes/sparkjob/spark3job.py +17 -18
- mlrun/runtimes/utils.py +40 -73
- mlrun/secrets.py +6 -2
- mlrun/serving/__init__.py +8 -1
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +89 -64
- mlrun/serving/server.py +54 -26
- mlrun/serving/states.py +187 -56
- mlrun/serving/utils.py +19 -11
- mlrun/serving/v2_serving.py +136 -63
- mlrun/track/tracker.py +2 -1
- mlrun/track/trackers/mlflow_tracker.py +5 -0
- mlrun/utils/async_http.py +26 -6
- mlrun/utils/db.py +18 -0
- mlrun/utils/helpers.py +375 -105
- mlrun/utils/http.py +2 -2
- mlrun/utils/logger.py +75 -9
- mlrun/utils/notifications/notification/__init__.py +14 -10
- mlrun/utils/notifications/notification/base.py +48 -0
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +24 -1
- mlrun/utils/notifications/notification/ipython.py +2 -0
- mlrun/utils/notifications/notification/slack.py +96 -21
- mlrun/utils/notifications/notification/webhook.py +63 -2
- mlrun/utils/notifications/notification_pusher.py +146 -16
- mlrun/utils/regex.py +9 -0
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/v3io_clients.py +2 -3
- mlrun/utils/version/version.json +2 -2
- mlrun-1.7.2.dist-info/METADATA +390 -0
- mlrun-1.7.2.dist-info/RECORD +351 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/WHEEL +1 -1
- mlrun/feature_store/retrieval/conversion.py +0 -271
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/application.py +0 -310
- mlrun/model_monitoring/batch.py +0 -974
- mlrun/model_monitoring/controller_handler.py +0 -37
- mlrun/model_monitoring/prometheus.py +0 -216
- mlrun/model_monitoring/stores/__init__.py +0 -111
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -574
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -145
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/models/base.py +0 -84
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
- mlrun/platforms/other.py +0 -305
- mlrun-1.7.0rc4.dist-info/METADATA +0 -269
- mlrun-1.7.0rc4.dist-info/RECORD +0 -321
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/top_level.txt +0 -0
mlrun/db/httpdb.py
CHANGED
|
@@ -11,28 +11,37 @@
|
|
|
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
|
+
|
|
14
15
|
import enum
|
|
15
16
|
import http
|
|
16
17
|
import re
|
|
17
|
-
import tempfile
|
|
18
18
|
import time
|
|
19
19
|
import traceback
|
|
20
20
|
import typing
|
|
21
21
|
import warnings
|
|
22
|
+
from copy import deepcopy
|
|
22
23
|
from datetime import datetime, timedelta
|
|
23
24
|
from os import path, remove
|
|
24
25
|
from typing import Optional, Union
|
|
25
26
|
from urllib.parse import urlparse
|
|
26
27
|
|
|
27
|
-
import kfp
|
|
28
28
|
import requests
|
|
29
29
|
import semver
|
|
30
|
+
from mlrun_pipelines.utils import compile_pipeline
|
|
30
31
|
|
|
31
32
|
import mlrun
|
|
33
|
+
import mlrun.common.formatters
|
|
34
|
+
import mlrun.common.runtimes
|
|
32
35
|
import mlrun.common.schemas
|
|
36
|
+
import mlrun.common.types
|
|
33
37
|
import mlrun.model_monitoring.model_endpoint
|
|
34
38
|
import mlrun.platforms
|
|
35
39
|
import mlrun.projects
|
|
40
|
+
import mlrun.runtimes.nuclio.api_gateway
|
|
41
|
+
import mlrun.runtimes.nuclio.function
|
|
42
|
+
import mlrun.utils
|
|
43
|
+
from mlrun.alerts.alert import AlertConfig
|
|
44
|
+
from mlrun.db.auth_utils import OAuthClientIDTokenProvider, StaticTokenProvider
|
|
36
45
|
from mlrun.errors import MLRunInvalidArgumentError, err_to_str
|
|
37
46
|
|
|
38
47
|
from ..artifacts import Artifact
|
|
@@ -45,7 +54,6 @@ from ..utils import (
|
|
|
45
54
|
datetime_to_iso,
|
|
46
55
|
dict_to_json,
|
|
47
56
|
logger,
|
|
48
|
-
new_pipe_metadata,
|
|
49
57
|
normalize_name,
|
|
50
58
|
version,
|
|
51
59
|
)
|
|
@@ -133,17 +141,28 @@ class HTTPRunDB(RunDBInterface):
|
|
|
133
141
|
endpoint += f":{parsed_url.port}"
|
|
134
142
|
base_url = f"{parsed_url.scheme}://{endpoint}{parsed_url.path}"
|
|
135
143
|
|
|
144
|
+
self.base_url = base_url
|
|
136
145
|
username = parsed_url.username or config.httpdb.user
|
|
137
146
|
password = parsed_url.password or config.httpdb.password
|
|
147
|
+
self.token_provider = None
|
|
148
|
+
|
|
149
|
+
if config.auth_with_client_id.enabled:
|
|
150
|
+
self.token_provider = OAuthClientIDTokenProvider(
|
|
151
|
+
token_endpoint=mlrun.get_secret_or_env("MLRUN_AUTH_TOKEN_ENDPOINT"),
|
|
152
|
+
client_id=mlrun.get_secret_or_env("MLRUN_AUTH_CLIENT_ID"),
|
|
153
|
+
client_secret=mlrun.get_secret_or_env("MLRUN_AUTH_CLIENT_SECRET"),
|
|
154
|
+
timeout=config.auth_with_client_id.request_timeout,
|
|
155
|
+
)
|
|
156
|
+
else:
|
|
157
|
+
username, password, token = mlrun.platforms.add_or_refresh_credentials(
|
|
158
|
+
parsed_url.hostname, username, password, config.httpdb.token
|
|
159
|
+
)
|
|
138
160
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
161
|
+
if token:
|
|
162
|
+
self.token_provider = StaticTokenProvider(token)
|
|
142
163
|
|
|
143
|
-
self.base_url = base_url
|
|
144
164
|
self.user = username
|
|
145
165
|
self.password = password
|
|
146
|
-
self.token = token
|
|
147
166
|
|
|
148
167
|
def __repr__(self):
|
|
149
168
|
cls = self.__class__.__name__
|
|
@@ -179,7 +198,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
179
198
|
headers=None,
|
|
180
199
|
timeout=45,
|
|
181
200
|
version=None,
|
|
182
|
-
):
|
|
201
|
+
) -> requests.Response:
|
|
183
202
|
"""Perform a direct REST API call on the :py:mod:`mlrun` API server.
|
|
184
203
|
|
|
185
204
|
Caution:
|
|
@@ -197,7 +216,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
197
216
|
:param version: API version to use, None (the default) will mean to use the default value from config,
|
|
198
217
|
for un-versioned api set an empty string.
|
|
199
218
|
|
|
200
|
-
:
|
|
219
|
+
:returns: `requests.Response` HTTP response object
|
|
201
220
|
"""
|
|
202
221
|
url = self.get_base_api_url(path, version)
|
|
203
222
|
kw = {
|
|
@@ -213,17 +232,19 @@ class HTTPRunDB(RunDBInterface):
|
|
|
213
232
|
|
|
214
233
|
if self.user:
|
|
215
234
|
kw["auth"] = (self.user, self.password)
|
|
216
|
-
elif self.
|
|
217
|
-
|
|
218
|
-
if
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
"
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
235
|
+
elif self.token_provider:
|
|
236
|
+
token = self.token_provider.get_token()
|
|
237
|
+
if token:
|
|
238
|
+
# Iguazio auth doesn't support passing token through bearer, so use cookie instead
|
|
239
|
+
if self.token_provider.is_iguazio_session():
|
|
240
|
+
session_cookie = f'j:{{"sid": "{token}"}}'
|
|
241
|
+
cookies = {
|
|
242
|
+
"session": session_cookie,
|
|
243
|
+
}
|
|
244
|
+
kw["cookies"] = cookies
|
|
245
|
+
else:
|
|
246
|
+
if "Authorization" not in kw.setdefault("headers", {}):
|
|
247
|
+
kw["headers"].update({"Authorization": "Bearer " + token})
|
|
227
248
|
|
|
228
249
|
if mlrun.common.schemas.HeaderNames.client_version not in kw.setdefault(
|
|
229
250
|
"headers", {}
|
|
@@ -278,6 +299,68 @@ class HTTPRunDB(RunDBInterface):
|
|
|
278
299
|
|
|
279
300
|
return response
|
|
280
301
|
|
|
302
|
+
def paginated_api_call(
|
|
303
|
+
self,
|
|
304
|
+
method,
|
|
305
|
+
path,
|
|
306
|
+
error=None,
|
|
307
|
+
params=None,
|
|
308
|
+
body=None,
|
|
309
|
+
json=None,
|
|
310
|
+
headers=None,
|
|
311
|
+
timeout=45,
|
|
312
|
+
version=None,
|
|
313
|
+
) -> typing.Generator[requests.Response, None, None]:
|
|
314
|
+
"""
|
|
315
|
+
Calls the api with pagination, yielding each page of the response
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
def _api_call(_params):
|
|
319
|
+
return self.api_call(
|
|
320
|
+
method=method,
|
|
321
|
+
path=path,
|
|
322
|
+
error=error,
|
|
323
|
+
params=_params,
|
|
324
|
+
body=body,
|
|
325
|
+
json=json,
|
|
326
|
+
headers=headers,
|
|
327
|
+
timeout=timeout,
|
|
328
|
+
version=version,
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
first_page_params = deepcopy(params) or {}
|
|
332
|
+
first_page_params["page"] = 1
|
|
333
|
+
first_page_params["page-size"] = config.httpdb.pagination.default_page_size
|
|
334
|
+
response = _api_call(first_page_params)
|
|
335
|
+
page_token = response.json().get("pagination", {}).get("page-token")
|
|
336
|
+
if not page_token:
|
|
337
|
+
yield response
|
|
338
|
+
return
|
|
339
|
+
|
|
340
|
+
params_with_page_token = deepcopy(params) or {}
|
|
341
|
+
params_with_page_token["page-token"] = page_token
|
|
342
|
+
while page_token:
|
|
343
|
+
yield response
|
|
344
|
+
try:
|
|
345
|
+
response = _api_call(params_with_page_token)
|
|
346
|
+
except mlrun.errors.MLRunNotFoundError:
|
|
347
|
+
# pagination token expired
|
|
348
|
+
break
|
|
349
|
+
|
|
350
|
+
page_token = response.json().get("pagination", {}).get("page-token", None)
|
|
351
|
+
|
|
352
|
+
@staticmethod
|
|
353
|
+
def process_paginated_responses(
|
|
354
|
+
responses: typing.Generator[requests.Response, None, None], key: str = "data"
|
|
355
|
+
) -> list[typing.Any]:
|
|
356
|
+
"""
|
|
357
|
+
Processes the paginated responses and returns the combined data
|
|
358
|
+
"""
|
|
359
|
+
data = []
|
|
360
|
+
for response in responses:
|
|
361
|
+
data.extend(response.json().get(key, []))
|
|
362
|
+
return data
|
|
363
|
+
|
|
281
364
|
def _init_session(self, retry_on_post: bool = False):
|
|
282
365
|
return mlrun.utils.HTTPSessionWithRetry(
|
|
283
366
|
retry_on_exception=config.httpdb.retry_api_call_on_exception
|
|
@@ -310,7 +393,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
310
393
|
|
|
311
394
|
For example::
|
|
312
395
|
|
|
313
|
-
config.dbpath = config.dbpath or
|
|
396
|
+
config.dbpath = config.dbpath or "http://mlrun-api:8080"
|
|
314
397
|
db = get_run_db().connect()
|
|
315
398
|
"""
|
|
316
399
|
# hack to allow unit tests to instantiate HTTPRunDB without a real server behind
|
|
@@ -442,14 +525,18 @@ class HTTPRunDB(RunDBInterface):
|
|
|
442
525
|
server_cfg.get("external_platform_tracking")
|
|
443
526
|
or config.external_platform_tracking
|
|
444
527
|
)
|
|
445
|
-
config.model_endpoint_monitoring.store_type = (
|
|
446
|
-
server_cfg.get("model_endpoint_monitoring_store_type")
|
|
447
|
-
or config.model_endpoint_monitoring.store_type
|
|
448
|
-
)
|
|
449
528
|
config.model_endpoint_monitoring.endpoint_store_connection = (
|
|
450
529
|
server_cfg.get("model_endpoint_monitoring_endpoint_store_connection")
|
|
451
530
|
or config.model_endpoint_monitoring.endpoint_store_connection
|
|
452
531
|
)
|
|
532
|
+
config.model_endpoint_monitoring.tsdb_connection = (
|
|
533
|
+
server_cfg.get("model_monitoring_tsdb_connection")
|
|
534
|
+
or config.model_endpoint_monitoring.tsdb_connection
|
|
535
|
+
)
|
|
536
|
+
config.model_endpoint_monitoring.stream_connection = (
|
|
537
|
+
server_cfg.get("stream_connection")
|
|
538
|
+
or config.model_endpoint_monitoring.stream_connection
|
|
539
|
+
)
|
|
453
540
|
config.packagers = server_cfg.get("packagers") or config.packagers
|
|
454
541
|
server_data_prefixes = server_cfg.get("feature_store_data_prefixes") or {}
|
|
455
542
|
for prefix in ["default", "nosql", "redisnosql"]:
|
|
@@ -462,6 +549,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
462
549
|
server_cfg.get("feature_store_default_targets")
|
|
463
550
|
or config.feature_store.default_targets
|
|
464
551
|
)
|
|
552
|
+
config.alerts.mode = server_cfg.get("alerts_mode") or config.alerts.mode
|
|
465
553
|
|
|
466
554
|
except Exception as exc:
|
|
467
555
|
logger.warning(
|
|
@@ -508,7 +596,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
508
596
|
if offset < 0:
|
|
509
597
|
raise MLRunInvalidArgumentError("Offset cannot be negative")
|
|
510
598
|
if size is None:
|
|
511
|
-
size = int(
|
|
599
|
+
size = int(mlrun.mlconf.httpdb.logs.pull_logs_default_size_limit)
|
|
512
600
|
elif size == -1:
|
|
513
601
|
logger.warning(
|
|
514
602
|
"Retrieving all logs. This may be inefficient and can result in a large log."
|
|
@@ -554,33 +642,35 @@ class HTTPRunDB(RunDBInterface):
|
|
|
554
642
|
|
|
555
643
|
state, text = self.get_log(uid, project, offset=offset)
|
|
556
644
|
if text:
|
|
557
|
-
print(text.decode(errors=
|
|
645
|
+
print(text.decode(errors=mlrun.mlconf.httpdb.logs.decode.errors))
|
|
558
646
|
nil_resp = 0
|
|
559
647
|
while True:
|
|
560
648
|
offset += len(text)
|
|
561
649
|
# if we get 3 nil responses in a row, increase the sleep time to 10 seconds
|
|
562
650
|
# TODO: refactor this to use a conditional backoff mechanism
|
|
563
651
|
if nil_resp < 3:
|
|
564
|
-
time.sleep(int(
|
|
652
|
+
time.sleep(int(mlrun.mlconf.httpdb.logs.pull_logs_default_interval))
|
|
565
653
|
else:
|
|
566
654
|
time.sleep(
|
|
567
|
-
int(
|
|
655
|
+
int(
|
|
656
|
+
mlrun.mlconf.httpdb.logs.pull_logs_backoff_no_logs_default_interval
|
|
657
|
+
)
|
|
568
658
|
)
|
|
569
659
|
state, text = self.get_log(uid, project, offset=offset)
|
|
570
660
|
if text:
|
|
571
661
|
nil_resp = 0
|
|
572
662
|
print(
|
|
573
|
-
text.decode(errors=
|
|
663
|
+
text.decode(errors=mlrun.mlconf.httpdb.logs.decode.errors),
|
|
574
664
|
end="",
|
|
575
665
|
)
|
|
576
666
|
else:
|
|
577
667
|
nil_resp += 1
|
|
578
668
|
|
|
579
669
|
if watch and state in [
|
|
580
|
-
mlrun.runtimes.constants.RunStates.pending,
|
|
581
|
-
mlrun.runtimes.constants.RunStates.running,
|
|
582
|
-
mlrun.runtimes.constants.RunStates.created,
|
|
583
|
-
mlrun.runtimes.constants.RunStates.aborting,
|
|
670
|
+
mlrun.common.runtimes.constants.RunStates.pending,
|
|
671
|
+
mlrun.common.runtimes.constants.RunStates.running,
|
|
672
|
+
mlrun.common.runtimes.constants.RunStates.created,
|
|
673
|
+
mlrun.common.runtimes.constants.RunStates.aborting,
|
|
584
674
|
]:
|
|
585
675
|
continue
|
|
586
676
|
else:
|
|
@@ -636,16 +726,26 @@ class HTTPRunDB(RunDBInterface):
|
|
|
636
726
|
)
|
|
637
727
|
return None
|
|
638
728
|
|
|
639
|
-
def read_run(
|
|
729
|
+
def read_run(
|
|
730
|
+
self,
|
|
731
|
+
uid,
|
|
732
|
+
project="",
|
|
733
|
+
iter=0,
|
|
734
|
+
format_: mlrun.common.formatters.RunFormat = mlrun.common.formatters.RunFormat.full,
|
|
735
|
+
):
|
|
640
736
|
"""Read the details of a stored run from the DB.
|
|
641
737
|
|
|
642
|
-
:param uid:
|
|
643
|
-
:param project:
|
|
644
|
-
:param iter:
|
|
738
|
+
:param uid: The run's unique ID.
|
|
739
|
+
:param project: Project name.
|
|
740
|
+
:param iter: Iteration within a specific execution.
|
|
741
|
+
:param format_: The format in which to return the run details.
|
|
645
742
|
"""
|
|
646
743
|
|
|
647
744
|
path = self._path_of("runs", project, uid)
|
|
648
|
-
params = {
|
|
745
|
+
params = {
|
|
746
|
+
"iter": iter,
|
|
747
|
+
"format": format_.value,
|
|
748
|
+
}
|
|
649
749
|
error = f"get run {project}/{uid}"
|
|
650
750
|
resp = self.api_call("GET", path, error, params=params)
|
|
651
751
|
return resp.json()["data"]
|
|
@@ -669,7 +769,10 @@ class HTTPRunDB(RunDBInterface):
|
|
|
669
769
|
uid: Optional[Union[str, list[str]]] = None,
|
|
670
770
|
project: Optional[str] = None,
|
|
671
771
|
labels: Optional[Union[str, list[str]]] = None,
|
|
672
|
-
state: Optional[
|
|
772
|
+
state: Optional[
|
|
773
|
+
mlrun.common.runtimes.constants.RunStates
|
|
774
|
+
] = None, # Backward compatibility
|
|
775
|
+
states: typing.Optional[list[mlrun.common.runtimes.constants.RunStates]] = None,
|
|
673
776
|
sort: bool = True,
|
|
674
777
|
last: int = 0,
|
|
675
778
|
iter: bool = False,
|
|
@@ -694,9 +797,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
694
797
|
|
|
695
798
|
Example::
|
|
696
799
|
|
|
697
|
-
runs = db.list_runs(
|
|
800
|
+
runs = db.list_runs(
|
|
801
|
+
name="download", project="iris", labels=["owner=admin", "kind=job"]
|
|
802
|
+
)
|
|
698
803
|
# If running in Jupyter, can use the .show() function to display the results
|
|
699
|
-
db.list_runs(name=
|
|
804
|
+
db.list_runs(name="", project=project_name).show()
|
|
700
805
|
|
|
701
806
|
|
|
702
807
|
:param name: Name of the run to retrieve.
|
|
@@ -705,7 +810,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
705
810
|
:param labels: A list of labels to filter by. Label filters work by either filtering a specific value
|
|
706
811
|
of a label (i.e. list("key=value")) or by looking for the existence of a given
|
|
707
812
|
key (i.e. "key").
|
|
708
|
-
:param state: List only runs whose state is specified.
|
|
813
|
+
:param state: Deprecated - List only runs whose state is specified (will be removed in 1.9.0)
|
|
814
|
+
:param states: List only runs whose state is one of the provided states.
|
|
709
815
|
:param sort: Whether to sort the result according to their start time. Otherwise, results will be
|
|
710
816
|
returned by their internal order in the DB (order will not be guaranteed).
|
|
711
817
|
:param last: Deprecated - currently not used (will be removed in 1.8.0).
|
|
@@ -741,11 +847,19 @@ class HTTPRunDB(RunDBInterface):
|
|
|
741
847
|
FutureWarning,
|
|
742
848
|
)
|
|
743
849
|
|
|
850
|
+
if state:
|
|
851
|
+
# TODO: Remove this in 1.9.0
|
|
852
|
+
warnings.warn(
|
|
853
|
+
"'state' is deprecated and will be removed in 1.9.0. Use 'states' instead.",
|
|
854
|
+
FutureWarning,
|
|
855
|
+
)
|
|
856
|
+
|
|
744
857
|
if (
|
|
745
858
|
not name
|
|
746
859
|
and not uid
|
|
747
860
|
and not labels
|
|
748
861
|
and not state
|
|
862
|
+
and not states
|
|
749
863
|
and not last
|
|
750
864
|
and not start_time_from
|
|
751
865
|
and not start_time_to
|
|
@@ -757,14 +871,16 @@ class HTTPRunDB(RunDBInterface):
|
|
|
757
871
|
):
|
|
758
872
|
# default to last week on no filter
|
|
759
873
|
start_time_from = datetime.now() - timedelta(days=7)
|
|
760
|
-
partition_by = mlrun.common.schemas.RunPartitionByField.
|
|
874
|
+
partition_by = mlrun.common.schemas.RunPartitionByField.project_and_name
|
|
761
875
|
partition_sort_by = mlrun.common.schemas.SortField.updated
|
|
762
876
|
|
|
763
877
|
params = {
|
|
764
878
|
"name": name,
|
|
765
879
|
"uid": uid,
|
|
766
880
|
"label": labels or [],
|
|
767
|
-
"state": state
|
|
881
|
+
"state": mlrun.utils.helpers.as_list(state)
|
|
882
|
+
if state is not None
|
|
883
|
+
else states or None,
|
|
768
884
|
"sort": bool2str(sort),
|
|
769
885
|
"iter": bool2str(iter),
|
|
770
886
|
"start_time_from": datetime_to_iso(start_time_from),
|
|
@@ -787,15 +903,15 @@ class HTTPRunDB(RunDBInterface):
|
|
|
787
903
|
)
|
|
788
904
|
error = "list runs"
|
|
789
905
|
_path = self._path_of("runs", project)
|
|
790
|
-
|
|
791
|
-
return RunList(
|
|
906
|
+
responses = self.paginated_api_call("GET", _path, error, params=params)
|
|
907
|
+
return RunList(self.process_paginated_responses(responses, "runs"))
|
|
792
908
|
|
|
793
909
|
def del_runs(self, name=None, project=None, labels=None, state=None, days_ago=0):
|
|
794
910
|
"""Delete a group of runs identified by the parameters of the function.
|
|
795
911
|
|
|
796
912
|
Example::
|
|
797
913
|
|
|
798
|
-
db.del_runs(state=
|
|
914
|
+
db.del_runs(state="completed")
|
|
799
915
|
|
|
800
916
|
:param name: Name of the task which the runs belong to.
|
|
801
917
|
:param project: Project to which the runs belong.
|
|
@@ -848,7 +964,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
848
964
|
|
|
849
965
|
# we do this because previously the 'uid' name was used for the 'tree' parameter
|
|
850
966
|
tree = tree or uid
|
|
851
|
-
|
|
967
|
+
project = project or mlrun.mlconf.default_project
|
|
852
968
|
endpoint_path = f"projects/{project}/artifacts/{key}"
|
|
853
969
|
|
|
854
970
|
error = f"store artifact {project}/{key}"
|
|
@@ -874,6 +990,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
874
990
|
project="",
|
|
875
991
|
tree=None,
|
|
876
992
|
uid=None,
|
|
993
|
+
format_: mlrun.common.formatters.ArtifactFormat = mlrun.common.formatters.ArtifactFormat.full,
|
|
877
994
|
):
|
|
878
995
|
"""Read an artifact, identified by its key, tag, tree and iteration.
|
|
879
996
|
|
|
@@ -883,25 +1000,37 @@ class HTTPRunDB(RunDBInterface):
|
|
|
883
1000
|
:param project: Project that the artifact belongs to.
|
|
884
1001
|
:param tree: The tree which generated this artifact.
|
|
885
1002
|
:param uid: A unique ID for this specific version of the artifact (the uid that was generated in the backend)
|
|
1003
|
+
:param format_: The format in which to return the artifact. Default is 'full'.
|
|
886
1004
|
"""
|
|
887
1005
|
|
|
888
|
-
project = project or
|
|
1006
|
+
project = project or mlrun.mlconf.default_project
|
|
889
1007
|
tag = tag or "latest"
|
|
890
1008
|
endpoint_path = f"projects/{project}/artifacts/{key}"
|
|
891
1009
|
error = f"read artifact {project}/{key}"
|
|
892
|
-
# explicitly set artifacts format to 'full' since old servers may default to 'legacy'
|
|
893
1010
|
params = {
|
|
894
|
-
"format":
|
|
1011
|
+
"format": format_,
|
|
895
1012
|
"tag": tag,
|
|
896
1013
|
"tree": tree,
|
|
897
|
-
"uid": uid,
|
|
1014
|
+
"object-uid": uid,
|
|
898
1015
|
}
|
|
899
|
-
if iter:
|
|
1016
|
+
if iter is not None:
|
|
900
1017
|
params["iter"] = str(iter)
|
|
901
1018
|
resp = self.api_call("GET", endpoint_path, error, params=params, version="v2")
|
|
902
1019
|
return resp.json()
|
|
903
1020
|
|
|
904
|
-
def del_artifact(
|
|
1021
|
+
def del_artifact(
|
|
1022
|
+
self,
|
|
1023
|
+
key,
|
|
1024
|
+
tag=None,
|
|
1025
|
+
project="",
|
|
1026
|
+
tree=None,
|
|
1027
|
+
uid=None,
|
|
1028
|
+
deletion_strategy: mlrun.common.schemas.artifact.ArtifactsDeletionStrategies = (
|
|
1029
|
+
mlrun.common.schemas.artifact.ArtifactsDeletionStrategies.metadata_only
|
|
1030
|
+
),
|
|
1031
|
+
secrets: dict = None,
|
|
1032
|
+
iter=None,
|
|
1033
|
+
):
|
|
905
1034
|
"""Delete an artifact.
|
|
906
1035
|
|
|
907
1036
|
:param key: Identifying key of the artifact.
|
|
@@ -909,17 +1038,28 @@ class HTTPRunDB(RunDBInterface):
|
|
|
909
1038
|
:param project: Project that the artifact belongs to.
|
|
910
1039
|
:param tree: The tree which generated this artifact.
|
|
911
1040
|
:param uid: A unique ID for this specific version of the artifact (the uid that was generated in the backend)
|
|
1041
|
+
:param deletion_strategy: The artifact deletion strategy types.
|
|
1042
|
+
:param secrets: Credentials needed to access the artifact data.
|
|
912
1043
|
"""
|
|
913
|
-
|
|
1044
|
+
project = project or mlrun.mlconf.default_project
|
|
914
1045
|
endpoint_path = f"projects/{project}/artifacts/{key}"
|
|
915
1046
|
params = {
|
|
916
1047
|
"key": key,
|
|
917
1048
|
"tag": tag,
|
|
918
1049
|
"tree": tree,
|
|
919
|
-
"uid": uid,
|
|
1050
|
+
"object-uid": uid,
|
|
1051
|
+
"iter": iter,
|
|
1052
|
+
"deletion_strategy": deletion_strategy,
|
|
920
1053
|
}
|
|
921
1054
|
error = f"del artifact {project}/{key}"
|
|
922
|
-
self.api_call(
|
|
1055
|
+
self.api_call(
|
|
1056
|
+
"DELETE",
|
|
1057
|
+
endpoint_path,
|
|
1058
|
+
error,
|
|
1059
|
+
params=params,
|
|
1060
|
+
version="v2",
|
|
1061
|
+
body=dict_to_json(secrets),
|
|
1062
|
+
)
|
|
923
1063
|
|
|
924
1064
|
def list_artifacts(
|
|
925
1065
|
self,
|
|
@@ -927,24 +1067,31 @@ class HTTPRunDB(RunDBInterface):
|
|
|
927
1067
|
project=None,
|
|
928
1068
|
tag=None,
|
|
929
1069
|
labels: Optional[Union[dict[str, str], list[str]]] = None,
|
|
930
|
-
since=None,
|
|
931
|
-
until=None,
|
|
1070
|
+
since: Optional[datetime] = None,
|
|
1071
|
+
until: Optional[datetime] = None,
|
|
932
1072
|
iter: int = None,
|
|
933
1073
|
best_iteration: bool = False,
|
|
934
1074
|
kind: str = None,
|
|
935
1075
|
category: Union[str, mlrun.common.schemas.ArtifactCategories] = None,
|
|
936
1076
|
tree: str = None,
|
|
1077
|
+
producer_uri: str = None,
|
|
1078
|
+
format_: Optional[
|
|
1079
|
+
mlrun.common.formatters.ArtifactFormat
|
|
1080
|
+
] = mlrun.common.formatters.ArtifactFormat.full,
|
|
1081
|
+
limit: int = None,
|
|
937
1082
|
) -> ArtifactList:
|
|
938
1083
|
"""List artifacts filtered by various parameters.
|
|
939
1084
|
|
|
940
1085
|
Examples::
|
|
941
1086
|
|
|
942
1087
|
# Show latest version of all artifacts in project
|
|
943
|
-
latest_artifacts = db.list_artifacts(
|
|
1088
|
+
latest_artifacts = db.list_artifacts("", tag="latest", project="iris")
|
|
944
1089
|
# check different artifact versions for a specific artifact
|
|
945
|
-
result_versions = db.list_artifacts(
|
|
1090
|
+
result_versions = db.list_artifacts("results", tag="*", project="iris")
|
|
946
1091
|
# Show artifacts with label filters - both uploaded and of binary type
|
|
947
|
-
result_labels = db.list_artifacts(
|
|
1092
|
+
result_labels = db.list_artifacts(
|
|
1093
|
+
"results", tag="*", project="iris", labels=["uploaded", "type=binary"]
|
|
1094
|
+
)
|
|
948
1095
|
|
|
949
1096
|
:param name: Name of artifacts to retrieve. Name with '~' prefix is used as a like query, and is not
|
|
950
1097
|
case-sensitive. This means that querying for ``~name`` may return artifacts named
|
|
@@ -953,16 +1100,21 @@ class HTTPRunDB(RunDBInterface):
|
|
|
953
1100
|
:param tag: Return artifacts assigned this tag.
|
|
954
1101
|
:param labels: Return artifacts that have these labels. Labels can either be a dictionary {"label": "value"} or
|
|
955
1102
|
a list of "label=value" (match label key and value) or "label" (match just label key) strings.
|
|
956
|
-
:param since:
|
|
957
|
-
:param until:
|
|
1103
|
+
:param since: Return artifacts updated after this date (as datetime object).
|
|
1104
|
+
:param until: Return artifacts updated before this date (as datetime object).
|
|
958
1105
|
:param iter: Return artifacts from a specific iteration (where ``iter=0`` means the root iteration). If
|
|
959
1106
|
``None`` (default) return artifacts from all iterations.
|
|
960
1107
|
:param best_iteration: Returns the artifact which belongs to the best iteration of a given run, in the case of
|
|
961
1108
|
artifacts generated from a hyper-param run. If only a single iteration exists, will return the artifact
|
|
962
1109
|
from that iteration. If using ``best_iter``, the ``iter`` parameter must not be used.
|
|
963
|
-
:param kind:
|
|
964
|
-
:param category:
|
|
965
|
-
:param tree:
|
|
1110
|
+
:param kind: Return artifacts of the requested kind.
|
|
1111
|
+
:param category: Return artifacts of the requested category.
|
|
1112
|
+
:param tree: Return artifacts of the requested tree.
|
|
1113
|
+
:param producer_uri: Return artifacts produced by the requested producer URI. Producer URI usually
|
|
1114
|
+
points to a run and is used to filter artifacts by the run that produced them when the artifact producer id
|
|
1115
|
+
is a workflow id (artifact was created as part of a workflow).
|
|
1116
|
+
:param format_: The format in which to return the artifacts. Default is 'full'.
|
|
1117
|
+
:param limit: Maximum number of artifacts to return.
|
|
966
1118
|
"""
|
|
967
1119
|
|
|
968
1120
|
project = project or config.default_project
|
|
@@ -980,7 +1132,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
980
1132
|
"kind": kind,
|
|
981
1133
|
"category": category,
|
|
982
1134
|
"tree": tree,
|
|
983
|
-
"format":
|
|
1135
|
+
"format": format_,
|
|
1136
|
+
"producer_uri": producer_uri,
|
|
1137
|
+
"limit": limit,
|
|
1138
|
+
"since": datetime_to_iso(since),
|
|
1139
|
+
"until": datetime_to_iso(until),
|
|
984
1140
|
}
|
|
985
1141
|
error = "list artifacts"
|
|
986
1142
|
endpoint_path = f"projects/{project}/artifacts"
|
|
@@ -1070,15 +1226,44 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1070
1226
|
project = project or config.default_project
|
|
1071
1227
|
path = f"projects/{project}/functions/{name}"
|
|
1072
1228
|
error_message = f"Failed deleting function {project}/{name}"
|
|
1073
|
-
self.api_call("DELETE", path, error_message)
|
|
1229
|
+
response = self.api_call("DELETE", path, error_message, version="v2")
|
|
1230
|
+
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
1231
|
+
logger.info(
|
|
1232
|
+
"Function is being deleted", project_name=project, function_name=name
|
|
1233
|
+
)
|
|
1234
|
+
background_task = mlrun.common.schemas.BackgroundTask(**response.json())
|
|
1235
|
+
background_task = self._wait_for_background_task_to_reach_terminal_state(
|
|
1236
|
+
background_task.metadata.name, project=project
|
|
1237
|
+
)
|
|
1238
|
+
if (
|
|
1239
|
+
background_task.status.state
|
|
1240
|
+
== mlrun.common.schemas.BackgroundTaskState.succeeded
|
|
1241
|
+
):
|
|
1242
|
+
logger.info(
|
|
1243
|
+
"Function deleted", project_name=project, function_name=name
|
|
1244
|
+
)
|
|
1245
|
+
elif (
|
|
1246
|
+
background_task.status.state
|
|
1247
|
+
== mlrun.common.schemas.BackgroundTaskState.failed
|
|
1248
|
+
):
|
|
1249
|
+
logger.info(
|
|
1250
|
+
"Function deletion failed",
|
|
1251
|
+
reason=background_task.status.error,
|
|
1252
|
+
project_name=project,
|
|
1253
|
+
function_name=name,
|
|
1254
|
+
)
|
|
1074
1255
|
|
|
1075
|
-
def list_functions(
|
|
1256
|
+
def list_functions(
|
|
1257
|
+
self, name=None, project=None, tag=None, labels=None, since=None, until=None
|
|
1258
|
+
):
|
|
1076
1259
|
"""Retrieve a list of functions, filtered by specific criteria.
|
|
1077
1260
|
|
|
1078
1261
|
:param name: Return only functions with a specific name.
|
|
1079
1262
|
:param project: Return functions belonging to this project. If not specified, the default project is used.
|
|
1080
|
-
:param tag: Return function versions with specific tags.
|
|
1263
|
+
:param tag: Return function versions with specific tags. To return only tagged functions, set tag to ``"*"``.
|
|
1081
1264
|
:param labels: Return functions that have specific labels assigned to them.
|
|
1265
|
+
:param since: Return functions updated after this date (as datetime object).
|
|
1266
|
+
:param until: Return functions updated before this date (as datetime object).
|
|
1082
1267
|
:returns: List of function objects (as dictionary).
|
|
1083
1268
|
"""
|
|
1084
1269
|
project = project or config.default_project
|
|
@@ -1086,11 +1271,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1086
1271
|
"name": name,
|
|
1087
1272
|
"tag": tag,
|
|
1088
1273
|
"label": labels or [],
|
|
1274
|
+
"since": datetime_to_iso(since),
|
|
1275
|
+
"until": datetime_to_iso(until),
|
|
1089
1276
|
}
|
|
1090
1277
|
error = "list functions"
|
|
1091
1278
|
path = f"projects/{project}/functions"
|
|
1092
|
-
|
|
1093
|
-
return
|
|
1279
|
+
responses = self.paginated_api_call("GET", path, error, params=params)
|
|
1280
|
+
return self.process_paginated_responses(responses, "funcs")
|
|
1094
1281
|
|
|
1095
1282
|
def list_runtime_resources(
|
|
1096
1283
|
self,
|
|
@@ -1180,25 +1367,19 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1180
1367
|
period didn't pass.
|
|
1181
1368
|
:param grace_period: Grace period given to the runtime resource before they are actually removed, counted from
|
|
1182
1369
|
the moment they moved to terminal state
|
|
1183
|
-
(defaults to mlrun.
|
|
1370
|
+
(defaults to mlrun.mlconf.runtime_resources_deletion_grace_period).
|
|
1184
1371
|
|
|
1185
1372
|
:returns: :py:class:`~mlrun.common.schemas.GroupedByProjectRuntimeResourcesOutput` listing the runtime resources
|
|
1186
1373
|
that were removed.
|
|
1187
1374
|
"""
|
|
1188
|
-
if grace_period is None:
|
|
1189
|
-
grace_period = config.runtime_resources_deletion_grace_period
|
|
1190
|
-
logger.info(
|
|
1191
|
-
"Using default grace period for runtime resources deletion",
|
|
1192
|
-
grace_period=grace_period,
|
|
1193
|
-
)
|
|
1194
|
-
|
|
1195
1375
|
params = {
|
|
1196
1376
|
"label-selector": label_selector,
|
|
1197
1377
|
"kind": kind,
|
|
1198
1378
|
"object-id": object_id,
|
|
1199
1379
|
"force": force,
|
|
1200
|
-
"grace-period": grace_period,
|
|
1201
1380
|
}
|
|
1381
|
+
if grace_period is not None:
|
|
1382
|
+
params["grace-period"] = grace_period
|
|
1202
1383
|
error = "Failed deleting runtime resources"
|
|
1203
1384
|
project_path = project if project else "*"
|
|
1204
1385
|
response = self.api_call(
|
|
@@ -1236,7 +1417,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1236
1417
|
name="run_func_on_tuesdays",
|
|
1237
1418
|
kind="job",
|
|
1238
1419
|
scheduled_object=get_data_func,
|
|
1239
|
-
cron_trigger=schemas.ScheduleCronTrigger(
|
|
1420
|
+
cron_trigger=schemas.ScheduleCronTrigger(
|
|
1421
|
+
day_of_week="tue", hour=15, minute=30
|
|
1422
|
+
),
|
|
1240
1423
|
)
|
|
1241
1424
|
db.create_schedule(project_name, schedule)
|
|
1242
1425
|
"""
|
|
@@ -1339,21 +1522,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1339
1522
|
:param builder_env: Kaniko builder pod env vars dict (for config/credentials)
|
|
1340
1523
|
:param force_build: Force building the image, even when no changes were made
|
|
1341
1524
|
"""
|
|
1342
|
-
|
|
1343
|
-
"s3://"
|
|
1344
|
-
)
|
|
1345
|
-
is_ecr_image = mlrun.utils.is_ecr_url(config.httpdb.builder.docker_registry)
|
|
1346
|
-
if not func.spec.build.load_source_on_run and is_s3_source and is_ecr_image:
|
|
1347
|
-
logger.warning(
|
|
1348
|
-
"Building a function image to ECR and loading an S3 source to the image may require conflicting access "
|
|
1349
|
-
"keys. Only the permissions granted to the platform's configured secret will take affect "
|
|
1350
|
-
"(see mlrun.config.config.httpdb.builder.docker_registry_secret). "
|
|
1351
|
-
"In case the permissions are limited to ECR scope, you may use pull_at_runtime=True instead",
|
|
1352
|
-
source=func.spec.build.source,
|
|
1353
|
-
load_source_on_run=func.spec.build.load_source_on_run,
|
|
1354
|
-
default_docker_registry=config.httpdb.builder.docker_registry,
|
|
1355
|
-
)
|
|
1356
|
-
|
|
1525
|
+
self.warn_on_s3_and_ecr_permissions_conflict(func)
|
|
1357
1526
|
try:
|
|
1358
1527
|
req = {
|
|
1359
1528
|
"function": func.to_dict(),
|
|
@@ -1372,10 +1541,94 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1372
1541
|
|
|
1373
1542
|
if not resp.ok:
|
|
1374
1543
|
logger.error(f"bad resp!!\n{resp.text}")
|
|
1375
|
-
raise ValueError("bad
|
|
1544
|
+
raise ValueError("bad submit build response")
|
|
1545
|
+
|
|
1546
|
+
return resp.json()
|
|
1547
|
+
|
|
1548
|
+
def deploy_nuclio_function(
|
|
1549
|
+
self,
|
|
1550
|
+
func: mlrun.runtimes.RemoteRuntime,
|
|
1551
|
+
builder_env: Optional[dict] = None,
|
|
1552
|
+
):
|
|
1553
|
+
"""
|
|
1554
|
+
Deploy a Nuclio function.
|
|
1555
|
+
|
|
1556
|
+
:param func: Function to build.
|
|
1557
|
+
:param builder_env: Kaniko builder pod env vars dict (for config/credentials)
|
|
1558
|
+
"""
|
|
1559
|
+
func.metadata.project = func.metadata.project or config.default_project
|
|
1560
|
+
self.warn_on_s3_and_ecr_permissions_conflict(func)
|
|
1561
|
+
try:
|
|
1562
|
+
req = {
|
|
1563
|
+
"function": func.to_dict(),
|
|
1564
|
+
}
|
|
1565
|
+
if builder_env:
|
|
1566
|
+
req["builder_env"] = builder_env
|
|
1567
|
+
_path = (
|
|
1568
|
+
f"projects/{func.metadata.project}/nuclio/{func.metadata.name}/deploy"
|
|
1569
|
+
)
|
|
1570
|
+
resp = self.api_call("POST", _path, json=req)
|
|
1571
|
+
except OSError as err:
|
|
1572
|
+
logger.error(f"error submitting nuclio deploy task: {err_to_str(err)}")
|
|
1573
|
+
raise OSError(f"error: cannot submit deploy, {err_to_str(err)}")
|
|
1574
|
+
|
|
1575
|
+
if not resp.ok:
|
|
1576
|
+
logger.error(f"deploy nuclio - bad response:\n{resp.text}")
|
|
1577
|
+
raise ValueError("bad nuclio deploy response")
|
|
1376
1578
|
|
|
1377
1579
|
return resp.json()
|
|
1378
1580
|
|
|
1581
|
+
def get_nuclio_deploy_status(
|
|
1582
|
+
self,
|
|
1583
|
+
func: mlrun.runtimes.RemoteRuntime,
|
|
1584
|
+
last_log_timestamp: float = 0.0,
|
|
1585
|
+
verbose: bool = False,
|
|
1586
|
+
):
|
|
1587
|
+
"""Retrieve the status of a deploy operation currently in progress.
|
|
1588
|
+
|
|
1589
|
+
:param func: Function object that is being built.
|
|
1590
|
+
:param last_log_timestamp: Last timestamp of logs that were already retrieved. Function will return only logs
|
|
1591
|
+
later than this parameter.
|
|
1592
|
+
:param verbose: Add verbose logs into the output.
|
|
1593
|
+
|
|
1594
|
+
:returns: The following parameters:
|
|
1595
|
+
|
|
1596
|
+
- Text of builder logs.
|
|
1597
|
+
- Timestamp of last log retrieved, to be used in subsequent calls to this function.
|
|
1598
|
+
"""
|
|
1599
|
+
|
|
1600
|
+
try:
|
|
1601
|
+
normalized_name = normalize_name(func.metadata.name)
|
|
1602
|
+
params = {
|
|
1603
|
+
"name": normalized_name,
|
|
1604
|
+
"project": func.metadata.project,
|
|
1605
|
+
"tag": func.metadata.tag,
|
|
1606
|
+
"last_log_timestamp": str(last_log_timestamp),
|
|
1607
|
+
"verbose": bool2str(verbose),
|
|
1608
|
+
}
|
|
1609
|
+
_path = f"projects/{func.metadata.project}/nuclio/{normalized_name}/deploy"
|
|
1610
|
+
resp = self.api_call("GET", _path, params=params)
|
|
1611
|
+
except OSError as err:
|
|
1612
|
+
logger.error(f"error getting deploy status: {err_to_str(err)}")
|
|
1613
|
+
raise OSError(f"error: cannot get deploy status, {err_to_str(err)}")
|
|
1614
|
+
|
|
1615
|
+
if not resp.ok:
|
|
1616
|
+
logger.warning(f"failed resp, {resp.text}")
|
|
1617
|
+
raise RunDBError("bad function build response")
|
|
1618
|
+
|
|
1619
|
+
if resp.headers:
|
|
1620
|
+
last_log_timestamp = float(
|
|
1621
|
+
resp.headers.get("x-mlrun-last-timestamp", "0.0")
|
|
1622
|
+
)
|
|
1623
|
+
mlrun.runtimes.nuclio.function.enrich_nuclio_function_from_headers(
|
|
1624
|
+
func, resp.headers
|
|
1625
|
+
)
|
|
1626
|
+
|
|
1627
|
+
text = ""
|
|
1628
|
+
if resp.content:
|
|
1629
|
+
text = resp.content.decode()
|
|
1630
|
+
return text, last_log_timestamp
|
|
1631
|
+
|
|
1379
1632
|
def get_builder_status(
|
|
1380
1633
|
self,
|
|
1381
1634
|
func: BaseRuntime,
|
|
@@ -1425,21 +1678,18 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1425
1678
|
last_log_timestamp = float(
|
|
1426
1679
|
resp.headers.get("x-mlrun-last-timestamp", "0.0")
|
|
1427
1680
|
)
|
|
1428
|
-
if func.kind in mlrun.runtimes.RuntimeKinds.
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
func.status.internal_invocation_urls = resp.headers.get(
|
|
1432
|
-
"x-mlrun-internal-invocation-urls", ""
|
|
1433
|
-
).split(",")
|
|
1434
|
-
func.status.external_invocation_urls = resp.headers.get(
|
|
1435
|
-
"x-mlrun-external-invocation-urls", ""
|
|
1436
|
-
).split(",")
|
|
1437
|
-
func.status.container_image = resp.headers.get(
|
|
1438
|
-
"x-mlrun-container-image", ""
|
|
1681
|
+
if func.kind in mlrun.runtimes.RuntimeKinds.pure_nuclio_deployed_runtimes():
|
|
1682
|
+
mlrun.runtimes.nuclio.function.enrich_nuclio_function_from_headers(
|
|
1683
|
+
func, resp.headers
|
|
1439
1684
|
)
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1685
|
+
|
|
1686
|
+
builder_pod = resp.headers.get("builder_pod", "")
|
|
1687
|
+
if builder_pod:
|
|
1688
|
+
func.status.build_pod = builder_pod
|
|
1689
|
+
|
|
1690
|
+
function_image = resp.headers.get("function_image", "")
|
|
1691
|
+
if function_image:
|
|
1692
|
+
func.spec.image = function_image
|
|
1443
1693
|
|
|
1444
1694
|
text = ""
|
|
1445
1695
|
if resp.content:
|
|
@@ -1502,7 +1752,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1502
1752
|
Retrieve updated information on project background tasks being executed.
|
|
1503
1753
|
If no filter is provided, will return background tasks from the last week.
|
|
1504
1754
|
|
|
1505
|
-
:param project: Project name (defaults to mlrun.
|
|
1755
|
+
:param project: Project name (defaults to mlrun.mlconf.default_project).
|
|
1506
1756
|
:param state: List only background tasks whose state is specified.
|
|
1507
1757
|
:param created_from: Filter by background task created time in ``[created_from, created_to]``.
|
|
1508
1758
|
:param created_to: Filter by background task created time in ``[created_from, created_to]``.
|
|
@@ -1615,32 +1865,31 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1615
1865
|
artifact_path=None,
|
|
1616
1866
|
ops=None,
|
|
1617
1867
|
cleanup_ttl=None,
|
|
1868
|
+
timeout=60,
|
|
1618
1869
|
):
|
|
1619
1870
|
"""Submit a KFP pipeline for execution.
|
|
1620
1871
|
|
|
1621
|
-
:param project:
|
|
1622
|
-
:param pipeline:
|
|
1623
|
-
:param arguments:
|
|
1624
|
-
:param experiment:
|
|
1625
|
-
:param run:
|
|
1626
|
-
:param namespace:
|
|
1627
|
-
:param artifact_path:
|
|
1628
|
-
:param ops:
|
|
1629
|
-
:param cleanup_ttl:
|
|
1630
|
-
|
|
1872
|
+
:param project: The project of the pipeline
|
|
1873
|
+
:param pipeline: Pipeline function or path to .yaml/.zip pipeline file.
|
|
1874
|
+
:param arguments: A dictionary of arguments to pass to the pipeline.
|
|
1875
|
+
:param experiment: A name to assign for the specific experiment.
|
|
1876
|
+
:param run: A name for this specific run.
|
|
1877
|
+
:param namespace: Kubernetes namespace to execute the pipeline in.
|
|
1878
|
+
:param artifact_path: A path to artifacts used by this pipeline.
|
|
1879
|
+
:param ops: Transformers to apply on all ops in the pipeline.
|
|
1880
|
+
:param cleanup_ttl: Pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
|
|
1881
|
+
workflow and all its resources are deleted)
|
|
1882
|
+
:param timeout: Timeout for the API call.
|
|
1631
1883
|
"""
|
|
1632
1884
|
|
|
1633
1885
|
if isinstance(pipeline, str):
|
|
1634
1886
|
pipe_file = pipeline
|
|
1635
1887
|
else:
|
|
1636
|
-
pipe_file =
|
|
1637
|
-
conf = new_pipe_metadata(
|
|
1888
|
+
pipe_file = compile_pipeline(
|
|
1638
1889
|
artifact_path=artifact_path,
|
|
1639
1890
|
cleanup_ttl=cleanup_ttl,
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
kfp.compiler.Compiler().compile(
|
|
1643
|
-
pipeline, pipe_file, type_check=False, pipeline_conf=conf
|
|
1891
|
+
ops=ops,
|
|
1892
|
+
pipeline=pipeline,
|
|
1644
1893
|
)
|
|
1645
1894
|
|
|
1646
1895
|
if pipe_file.endswith(".yaml"):
|
|
@@ -1669,7 +1918,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1669
1918
|
"POST",
|
|
1670
1919
|
f"projects/{project}/pipelines",
|
|
1671
1920
|
params=params,
|
|
1672
|
-
timeout=
|
|
1921
|
+
timeout=timeout,
|
|
1673
1922
|
body=data,
|
|
1674
1923
|
headers=headers,
|
|
1675
1924
|
)
|
|
@@ -1695,8 +1944,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1695
1944
|
page_token: str = "",
|
|
1696
1945
|
filter_: str = "",
|
|
1697
1946
|
format_: Union[
|
|
1698
|
-
str, mlrun.common.
|
|
1699
|
-
] = mlrun.common.
|
|
1947
|
+
str, mlrun.common.formatters.PipelineFormat
|
|
1948
|
+
] = mlrun.common.formatters.PipelineFormat.metadata_only,
|
|
1700
1949
|
page_size: int = None,
|
|
1701
1950
|
) -> mlrun.common.schemas.PipelinesOutput:
|
|
1702
1951
|
"""Retrieve a list of KFP pipelines. This function can be invoked to get all pipelines from all projects,
|
|
@@ -1742,8 +1991,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1742
1991
|
namespace: str = None,
|
|
1743
1992
|
timeout: int = 30,
|
|
1744
1993
|
format_: Union[
|
|
1745
|
-
str, mlrun.common.
|
|
1746
|
-
] = mlrun.common.
|
|
1994
|
+
str, mlrun.common.formatters.PipelineFormat
|
|
1995
|
+
] = mlrun.common.formatters.PipelineFormat.summary,
|
|
1747
1996
|
project: str = None,
|
|
1748
1997
|
):
|
|
1749
1998
|
"""Retrieve details of a specific pipeline using its run ID (as provided when the pipeline was executed)."""
|
|
@@ -1867,6 +2116,41 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1867
2116
|
resp = self.api_call("GET", path, error_message, params=params)
|
|
1868
2117
|
return resp.json()["features"]
|
|
1869
2118
|
|
|
2119
|
+
def list_features_v2(
|
|
2120
|
+
self,
|
|
2121
|
+
project: str,
|
|
2122
|
+
name: str = None,
|
|
2123
|
+
tag: str = None,
|
|
2124
|
+
entities: list[str] = None,
|
|
2125
|
+
labels: list[str] = None,
|
|
2126
|
+
) -> dict[str, list[dict]]:
|
|
2127
|
+
"""List feature-sets which contain specific features. This function may return multiple versions of the same
|
|
2128
|
+
feature-set if a specific tag is not requested. Note that the various filters of this function actually
|
|
2129
|
+
refer to the feature-set object containing the features, not to the features themselves.
|
|
2130
|
+
|
|
2131
|
+
:param project: Project which contains these features.
|
|
2132
|
+
:param name: Name of the feature to look for. The name is used in a like query, and is not case-sensitive. For
|
|
2133
|
+
example, looking for ``feat`` will return features which are named ``MyFeature`` as well as ``defeat``.
|
|
2134
|
+
:param tag: Return feature-sets which contain the features looked for, and are tagged with the specific tag.
|
|
2135
|
+
:param entities: Return only feature-sets which contain an entity whose name is contained in this list.
|
|
2136
|
+
:param labels: Return only feature-sets which are labeled as requested.
|
|
2137
|
+
:returns: A list of features, and a list of their corresponding feature sets.
|
|
2138
|
+
"""
|
|
2139
|
+
|
|
2140
|
+
project = project or config.default_project
|
|
2141
|
+
params = {
|
|
2142
|
+
"name": name,
|
|
2143
|
+
"tag": tag,
|
|
2144
|
+
"entity": entities or [],
|
|
2145
|
+
"label": labels or [],
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
path = f"projects/{project}/features"
|
|
2149
|
+
|
|
2150
|
+
error_message = f"Failed listing features, project: {project}, query: {params}"
|
|
2151
|
+
resp = self.api_call("GET", path, error_message, params=params, version="v2")
|
|
2152
|
+
return resp.json()
|
|
2153
|
+
|
|
1870
2154
|
def list_entities(
|
|
1871
2155
|
self,
|
|
1872
2156
|
project: str,
|
|
@@ -1892,6 +2176,31 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1892
2176
|
resp = self.api_call("GET", path, error_message, params=params)
|
|
1893
2177
|
return resp.json()["entities"]
|
|
1894
2178
|
|
|
2179
|
+
def list_entities_v2(
|
|
2180
|
+
self,
|
|
2181
|
+
project: str,
|
|
2182
|
+
name: str = None,
|
|
2183
|
+
tag: str = None,
|
|
2184
|
+
labels: list[str] = None,
|
|
2185
|
+
) -> dict[str, list[dict]]:
|
|
2186
|
+
"""Retrieve a list of entities and their mapping to the containing feature-sets. This function is similar
|
|
2187
|
+
to the :py:func:`~list_features_v2` function, and uses the same logic. However, the entities are matched
|
|
2188
|
+
against the name rather than the features.
|
|
2189
|
+
"""
|
|
2190
|
+
|
|
2191
|
+
project = project or config.default_project
|
|
2192
|
+
params = {
|
|
2193
|
+
"name": name,
|
|
2194
|
+
"tag": tag,
|
|
2195
|
+
"label": labels or [],
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
path = f"projects/{project}/entities"
|
|
2199
|
+
|
|
2200
|
+
error_message = f"Failed listing entities, project: {project}, query: {params}"
|
|
2201
|
+
resp = self.api_call("GET", path, error_message, params=params, version="v2")
|
|
2202
|
+
return resp.json()
|
|
2203
|
+
|
|
1895
2204
|
@staticmethod
|
|
1896
2205
|
def _generate_partition_by_params(
|
|
1897
2206
|
partition_by_cls,
|
|
@@ -1928,6 +2237,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1928
2237
|
partition_order: Union[
|
|
1929
2238
|
mlrun.common.schemas.OrderType, str
|
|
1930
2239
|
] = mlrun.common.schemas.OrderType.desc,
|
|
2240
|
+
format_: Union[
|
|
2241
|
+
str, mlrun.common.formatters.FeatureSetFormat
|
|
2242
|
+
] = mlrun.common.formatters.FeatureSetFormat.full,
|
|
1931
2243
|
) -> list[FeatureSet]:
|
|
1932
2244
|
"""Retrieve a list of feature-sets matching the criteria provided.
|
|
1933
2245
|
|
|
@@ -1945,6 +2257,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1945
2257
|
:param partition_sort_by: What field to sort the results by, within each partition defined by `partition_by`.
|
|
1946
2258
|
Currently the only allowed value are `created` and `updated`.
|
|
1947
2259
|
:param partition_order: Order of sorting within partitions - `asc` or `desc`. Default is `desc`.
|
|
2260
|
+
:param format_: Format of the results. Possible values are:
|
|
2261
|
+
- ``minimal`` - Return minimal feature set objects, not including stats and preview for each feature set.
|
|
2262
|
+
- ``full`` - Return full feature set objects.
|
|
1948
2263
|
:returns: List of matching :py:class:`~mlrun.feature_store.FeatureSet` objects.
|
|
1949
2264
|
"""
|
|
1950
2265
|
|
|
@@ -1957,6 +2272,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1957
2272
|
"entity": entities or [],
|
|
1958
2273
|
"feature": features or [],
|
|
1959
2274
|
"label": labels or [],
|
|
2275
|
+
"format": format_,
|
|
1960
2276
|
}
|
|
1961
2277
|
if partition_by:
|
|
1962
2278
|
params.update(
|
|
@@ -2043,7 +2359,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2043
2359
|
not a full object.
|
|
2044
2360
|
Example::
|
|
2045
2361
|
|
|
2046
|
-
feature_set_update = {"status": {"processed"
|
|
2362
|
+
feature_set_update = {"status": {"processed": True}}
|
|
2047
2363
|
|
|
2048
2364
|
Will apply the field ``status.processed`` to the existing object.
|
|
2049
2365
|
:param project: Project which contains the modified object.
|
|
@@ -2385,8 +2701,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2385
2701
|
self,
|
|
2386
2702
|
owner: str = None,
|
|
2387
2703
|
format_: Union[
|
|
2388
|
-
str, mlrun.common.
|
|
2389
|
-
] = mlrun.common.
|
|
2704
|
+
str, mlrun.common.formatters.ProjectFormat
|
|
2705
|
+
] = mlrun.common.formatters.ProjectFormat.name_only,
|
|
2390
2706
|
labels: list[str] = None,
|
|
2391
2707
|
state: Union[str, mlrun.common.schemas.ProjectState] = None,
|
|
2392
2708
|
) -> list[Union[mlrun.projects.MlrunProject, str]]:
|
|
@@ -2412,7 +2728,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2412
2728
|
|
|
2413
2729
|
error_message = f"Failed listing projects, query: {params}"
|
|
2414
2730
|
response = self.api_call("GET", "projects", error_message, params=params)
|
|
2415
|
-
if format_ == mlrun.common.
|
|
2731
|
+
if format_ == mlrun.common.formatters.ProjectFormat.name_only:
|
|
2416
2732
|
# projects is just a list of strings
|
|
2417
2733
|
return response.json()["projects"]
|
|
2418
2734
|
|
|
@@ -2440,7 +2756,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2440
2756
|
deletion_strategy: Union[
|
|
2441
2757
|
str, mlrun.common.schemas.DeletionStrategy
|
|
2442
2758
|
] = mlrun.common.schemas.DeletionStrategy.default(),
|
|
2443
|
-
):
|
|
2759
|
+
) -> None:
|
|
2444
2760
|
"""Delete a project.
|
|
2445
2761
|
|
|
2446
2762
|
:param name: Name of the project to delete.
|
|
@@ -2459,7 +2775,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2459
2775
|
"DELETE", f"projects/{name}", error_message, headers=headers, version="v2"
|
|
2460
2776
|
)
|
|
2461
2777
|
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
2462
|
-
logger.info("
|
|
2778
|
+
logger.info("Waiting for project to be deleted", project_name=name)
|
|
2463
2779
|
background_task = mlrun.common.schemas.BackgroundTask(**response.json())
|
|
2464
2780
|
background_task = self._wait_for_background_task_to_reach_terminal_state(
|
|
2465
2781
|
background_task.metadata.name
|
|
@@ -2469,10 +2785,17 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2469
2785
|
== mlrun.common.schemas.BackgroundTaskState.succeeded
|
|
2470
2786
|
):
|
|
2471
2787
|
logger.info("Project deleted", project_name=name)
|
|
2472
|
-
|
|
2788
|
+
elif (
|
|
2789
|
+
background_task.status.state
|
|
2790
|
+
== mlrun.common.schemas.BackgroundTaskState.failed
|
|
2791
|
+
):
|
|
2792
|
+
logger.error(
|
|
2793
|
+
"Project deletion failed",
|
|
2794
|
+
project_name=name,
|
|
2795
|
+
error=background_task.status.error,
|
|
2796
|
+
)
|
|
2473
2797
|
elif response.status_code == http.HTTPStatus.NO_CONTENT:
|
|
2474
2798
|
logger.info("Project deleted", project_name=name)
|
|
2475
|
-
return
|
|
2476
2799
|
|
|
2477
2800
|
def store_project(
|
|
2478
2801
|
self,
|
|
@@ -2617,11 +2940,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2617
2940
|
:param secrets: A set of secret values to store.
|
|
2618
2941
|
Example::
|
|
2619
2942
|
|
|
2620
|
-
secrets = {
|
|
2943
|
+
secrets = {"password": "myPassw0rd", "aws_key": "111222333"}
|
|
2621
2944
|
db.create_project_secrets(
|
|
2622
2945
|
"project1",
|
|
2623
2946
|
provider=mlrun.common.schemas.SecretProviderName.kubernetes,
|
|
2624
|
-
secrets=secrets
|
|
2947
|
+
secrets=secrets,
|
|
2625
2948
|
)
|
|
2626
2949
|
"""
|
|
2627
2950
|
path = f"projects/{project}/secrets"
|
|
@@ -2917,14 +3240,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2917
3240
|
:param labels: A list of labels to filter by. Label filters work by either filtering a specific value of a
|
|
2918
3241
|
label (i.e. list("key=value")) or by looking for the existence of a given key (i.e. "key")
|
|
2919
3242
|
:param metrics: A list of metrics to return for each endpoint, read more in 'TimeMetric'
|
|
2920
|
-
:param start: The start time of the metrics. Can be represented by a string containing an RFC 3339
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
`'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours, and `'d'` =
|
|
2927
|
-
days), or 0 for the earliest time.
|
|
3243
|
+
:param start: The start time of the metrics. Can be represented by a string containing an RFC 3339 time, a
|
|
3244
|
+
Unix timestamp in milliseconds, a relative time (`'now'` or `'now-[0-9]+[mhd]'`, where
|
|
3245
|
+
`m` = minutes, `h` = hours, `'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
|
|
3246
|
+
:param end: The end time of the metrics. Can be represented by a string containing an RFC 3339 time, a
|
|
3247
|
+
Unix timestamp in milliseconds, a relative time (`'now'` or `'now-[0-9]+[mhd]'`, where
|
|
3248
|
+
`m` = minutes, `h` = hours, `'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
|
|
2928
3249
|
:param top_level: if true will return only routers and endpoint that are NOT children of any router
|
|
2929
3250
|
:param uids: if passed will return a list `ModelEndpoint` object with uid in uids
|
|
2930
3251
|
"""
|
|
@@ -2973,13 +3294,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2973
3294
|
:param project: The name of the project
|
|
2974
3295
|
:param endpoint_id: The unique id of the model endpoint.
|
|
2975
3296
|
:param start: The start time of the metrics. Can be represented by a string containing an
|
|
2976
|
-
RFC 3339 time, a
|
|
2977
|
-
`'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours,
|
|
2978
|
-
0 for the earliest time.
|
|
3297
|
+
RFC 3339 time, a Unix timestamp in milliseconds, a relative time
|
|
3298
|
+
(`'now'` or `'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours,
|
|
3299
|
+
`'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
|
|
2979
3300
|
:param end: The end time of the metrics. Can be represented by a string containing an
|
|
2980
|
-
RFC 3339 time, a
|
|
2981
|
-
`'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours,
|
|
2982
|
-
0 for the earliest time.
|
|
3301
|
+
RFC 3339 time, a Unix timestamp in milliseconds, a relative time
|
|
3302
|
+
(`'now'` or `'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours,
|
|
3303
|
+
`'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
|
|
2983
3304
|
:param metrics: A list of metrics to return for the model endpoint. There are pre-defined
|
|
2984
3305
|
metrics for model endpoints such as predictions_per_second and
|
|
2985
3306
|
latency_avg_5m but also custom metrics defined by the user. Please note that
|
|
@@ -2988,7 +3309,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2988
3309
|
:param feature_analysis: When True, the base feature statistics and current feature statistics will
|
|
2989
3310
|
be added to the output of the resulting object.
|
|
2990
3311
|
|
|
2991
|
-
:
|
|
3312
|
+
:returns: A `ModelEndpoint` object.
|
|
2992
3313
|
"""
|
|
2993
3314
|
|
|
2994
3315
|
path = f"projects/{project}/model-endpoints/{endpoint_id}"
|
|
@@ -3049,41 +3370,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3049
3370
|
params=attributes,
|
|
3050
3371
|
)
|
|
3051
3372
|
|
|
3052
|
-
def deploy_monitoring_batch_job(
|
|
3053
|
-
self,
|
|
3054
|
-
project: str = "",
|
|
3055
|
-
default_batch_image: str = "mlrun/mlrun",
|
|
3056
|
-
with_schedule: bool = False,
|
|
3057
|
-
):
|
|
3058
|
-
"""
|
|
3059
|
-
Submit model monitoring batch job. By default, submit only the batch job as ML function without scheduling.
|
|
3060
|
-
To submit a scheduled job as well, please set with_schedule = True.
|
|
3061
|
-
|
|
3062
|
-
:param project: Project name.
|
|
3063
|
-
:param default_batch_image: The default image of the model monitoring batch job. By default, the image
|
|
3064
|
-
is mlrun/mlrun.
|
|
3065
|
-
:param with_schedule: If true, submit the model monitoring scheduled job as well.
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
:returns: model monitoring batch job as a dictionary. You can easily convert the returned function into a
|
|
3069
|
-
runtime object by calling ~mlrun.new_function.
|
|
3070
|
-
"""
|
|
3071
|
-
|
|
3072
|
-
params = {
|
|
3073
|
-
"default_batch_image": default_batch_image,
|
|
3074
|
-
"with_schedule": with_schedule,
|
|
3075
|
-
}
|
|
3076
|
-
path = f"projects/{project}/jobs/batch-monitoring"
|
|
3077
|
-
|
|
3078
|
-
resp = self.api_call(method="POST", path=path, params=params)
|
|
3079
|
-
return resp.json()["func"]
|
|
3080
|
-
|
|
3081
3373
|
def update_model_monitoring_controller(
|
|
3082
3374
|
self,
|
|
3083
3375
|
project: str,
|
|
3084
3376
|
base_period: int = 10,
|
|
3085
3377
|
image: str = "mlrun/mlrun",
|
|
3086
|
-
):
|
|
3378
|
+
) -> None:
|
|
3087
3379
|
"""
|
|
3088
3380
|
Redeploy model monitoring application controller function.
|
|
3089
3381
|
|
|
@@ -3093,20 +3385,24 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3093
3385
|
:param image: The image of the model monitoring controller function.
|
|
3094
3386
|
By default, the image is mlrun/mlrun.
|
|
3095
3387
|
"""
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
"
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3388
|
+
self.api_call(
|
|
3389
|
+
method=mlrun.common.types.HTTPMethod.PATCH,
|
|
3390
|
+
path=f"projects/{project}/model-monitoring/model-monitoring-controller",
|
|
3391
|
+
params={
|
|
3392
|
+
"base_period": base_period,
|
|
3393
|
+
"image": image,
|
|
3394
|
+
},
|
|
3395
|
+
)
|
|
3103
3396
|
|
|
3104
3397
|
def enable_model_monitoring(
|
|
3105
3398
|
self,
|
|
3106
3399
|
project: str,
|
|
3107
3400
|
base_period: int = 10,
|
|
3108
3401
|
image: str = "mlrun/mlrun",
|
|
3109
|
-
|
|
3402
|
+
deploy_histogram_data_drift_app: bool = True,
|
|
3403
|
+
rebuild_images: bool = False,
|
|
3404
|
+
fetch_credentials_from_sys_config: bool = False,
|
|
3405
|
+
) -> None:
|
|
3110
3406
|
"""
|
|
3111
3407
|
Deploy model monitoring application controller, writer and stream functions.
|
|
3112
3408
|
While the main goal of the controller function is to handle the monitoring processing and triggering
|
|
@@ -3115,21 +3411,169 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3115
3411
|
The stream function goal is to monitor the log of the data stream. It is triggered when a new log entry
|
|
3116
3412
|
is detected. It processes the new events into statistics that are then written to statistics databases.
|
|
3117
3413
|
|
|
3414
|
+
:param project: Project name.
|
|
3415
|
+
:param base_period: The time period in minutes in which the model monitoring controller
|
|
3416
|
+
function triggers. By default, the base period is 10 minutes.
|
|
3417
|
+
:param image: The image of the model monitoring controller, writer & monitoring
|
|
3418
|
+
stream functions, which are real time nuclio functions.
|
|
3419
|
+
By default, the image is mlrun/mlrun.
|
|
3420
|
+
:param deploy_histogram_data_drift_app: If true, deploy the default histogram-based data drift application.
|
|
3421
|
+
:param rebuild_images: If true, force rebuild of model monitoring infrastructure images.
|
|
3422
|
+
:param fetch_credentials_from_sys_config: If true, fetch the credentials from the system configuration.
|
|
3118
3423
|
|
|
3119
|
-
:param project: Project name.
|
|
3120
|
-
:param base_period: The time period in minutes in which the model monitoring controller function
|
|
3121
|
-
triggers. By default, the base period is 10 minutes.
|
|
3122
|
-
:param image: The image of the model monitoring controller, writer & monitoring
|
|
3123
|
-
stream functions, which are real time nuclio functions.
|
|
3124
|
-
By default, the image is mlrun/mlrun.
|
|
3125
3424
|
"""
|
|
3425
|
+
self.api_call(
|
|
3426
|
+
method=mlrun.common.types.HTTPMethod.POST,
|
|
3427
|
+
path=f"projects/{project}/model-monitoring/enable-model-monitoring",
|
|
3428
|
+
params={
|
|
3429
|
+
"base_period": base_period,
|
|
3430
|
+
"image": image,
|
|
3431
|
+
"deploy_histogram_data_drift_app": deploy_histogram_data_drift_app,
|
|
3432
|
+
"rebuild_images": rebuild_images,
|
|
3433
|
+
"fetch_credentials_from_sys_config": fetch_credentials_from_sys_config,
|
|
3434
|
+
},
|
|
3435
|
+
)
|
|
3126
3436
|
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3437
|
+
def disable_model_monitoring(
|
|
3438
|
+
self,
|
|
3439
|
+
project: str,
|
|
3440
|
+
delete_resources: bool = True,
|
|
3441
|
+
delete_stream_function: bool = False,
|
|
3442
|
+
delete_histogram_data_drift_app: bool = True,
|
|
3443
|
+
delete_user_applications: bool = False,
|
|
3444
|
+
user_application_list: list[str] = None,
|
|
3445
|
+
) -> bool:
|
|
3446
|
+
"""
|
|
3447
|
+
Disable model monitoring application controller, writer, stream, histogram data drift application
|
|
3448
|
+
and the user's applications functions, according to the given params.
|
|
3449
|
+
|
|
3450
|
+
:param project: Project name.
|
|
3451
|
+
:param delete_resources: If True, it would delete the model monitoring controller & writer
|
|
3452
|
+
functions. Default True
|
|
3453
|
+
:param delete_stream_function: If True, it would delete model monitoring stream function,
|
|
3454
|
+
need to use wisely because if you're deleting this function
|
|
3455
|
+
this can cause data loss in case you will want to
|
|
3456
|
+
enable the model monitoring capability to the project.
|
|
3457
|
+
Default False.
|
|
3458
|
+
:param delete_histogram_data_drift_app: If True, it would delete the default histogram-based data drift
|
|
3459
|
+
application. Default False.
|
|
3460
|
+
:param delete_user_applications: If True, it would delete the user's model monitoring
|
|
3461
|
+
application according to user_application_list, Default False.
|
|
3462
|
+
:param user_application_list: List of the user's model monitoring application to disable.
|
|
3463
|
+
Default all the applications.
|
|
3464
|
+
Note: you have to set delete_user_applications to True
|
|
3465
|
+
in order to delete the desired application.
|
|
3466
|
+
|
|
3467
|
+
:returns: True if the deletion was successful, False otherwise.
|
|
3468
|
+
"""
|
|
3469
|
+
response = self.api_call(
|
|
3470
|
+
method=mlrun.common.types.HTTPMethod.DELETE,
|
|
3471
|
+
path=f"projects/{project}/model-monitoring/disable-model-monitoring",
|
|
3472
|
+
params={
|
|
3473
|
+
"delete_resources": delete_resources,
|
|
3474
|
+
"delete_stream_function": delete_stream_function,
|
|
3475
|
+
"delete_histogram_data_drift_app": delete_histogram_data_drift_app,
|
|
3476
|
+
"delete_user_applications": delete_user_applications,
|
|
3477
|
+
"user_application_list": user_application_list,
|
|
3478
|
+
},
|
|
3479
|
+
)
|
|
3480
|
+
deletion_failed = False
|
|
3481
|
+
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
3482
|
+
if delete_resources:
|
|
3483
|
+
logger.info(
|
|
3484
|
+
"Model Monitoring is being disabled",
|
|
3485
|
+
project_name=project,
|
|
3486
|
+
)
|
|
3487
|
+
if delete_user_applications:
|
|
3488
|
+
logger.info("User applications are being deleted", project_name=project)
|
|
3489
|
+
background_tasks = mlrun.common.schemas.BackgroundTaskList(
|
|
3490
|
+
**response.json()
|
|
3491
|
+
).background_tasks
|
|
3492
|
+
for task in background_tasks:
|
|
3493
|
+
task = self._wait_for_background_task_to_reach_terminal_state(
|
|
3494
|
+
task.metadata.name, project=project
|
|
3495
|
+
)
|
|
3496
|
+
if (
|
|
3497
|
+
task.status.state
|
|
3498
|
+
== mlrun.common.schemas.BackgroundTaskState.succeeded
|
|
3499
|
+
):
|
|
3500
|
+
continue
|
|
3501
|
+
elif (
|
|
3502
|
+
task.status.state == mlrun.common.schemas.BackgroundTaskState.failed
|
|
3503
|
+
):
|
|
3504
|
+
deletion_failed = True
|
|
3505
|
+
return not deletion_failed
|
|
3506
|
+
|
|
3507
|
+
def delete_model_monitoring_function(
|
|
3508
|
+
self, project: str, functions: list[str]
|
|
3509
|
+
) -> bool:
|
|
3510
|
+
"""
|
|
3511
|
+
Delete a model monitoring application.
|
|
3512
|
+
|
|
3513
|
+
:param functions: List of the model monitoring function to delete.
|
|
3514
|
+
:param project: Project name.
|
|
3515
|
+
|
|
3516
|
+
:returns: True if the deletion was successful, False otherwise.
|
|
3517
|
+
"""
|
|
3518
|
+
response = self.api_call(
|
|
3519
|
+
method=mlrun.common.types.HTTPMethod.DELETE,
|
|
3520
|
+
path=f"projects/{project}/model-monitoring/functions",
|
|
3521
|
+
params={"functions": functions},
|
|
3522
|
+
)
|
|
3523
|
+
deletion_failed = False
|
|
3524
|
+
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
3525
|
+
logger.info("User applications are being deleted", project_name=project)
|
|
3526
|
+
background_tasks = mlrun.common.schemas.BackgroundTaskList(
|
|
3527
|
+
**response.json()
|
|
3528
|
+
).background_tasks
|
|
3529
|
+
for task in background_tasks:
|
|
3530
|
+
task = self._wait_for_background_task_to_reach_terminal_state(
|
|
3531
|
+
task.metadata.name, project=project
|
|
3532
|
+
)
|
|
3533
|
+
if (
|
|
3534
|
+
task.status.state
|
|
3535
|
+
== mlrun.common.schemas.BackgroundTaskState.succeeded
|
|
3536
|
+
):
|
|
3537
|
+
continue
|
|
3538
|
+
elif (
|
|
3539
|
+
task.status.state == mlrun.common.schemas.BackgroundTaskState.failed
|
|
3540
|
+
):
|
|
3541
|
+
deletion_failed = True
|
|
3542
|
+
return not deletion_failed
|
|
3543
|
+
|
|
3544
|
+
def deploy_histogram_data_drift_app(
|
|
3545
|
+
self, project: str, image: str = "mlrun/mlrun"
|
|
3546
|
+
) -> None:
|
|
3547
|
+
"""
|
|
3548
|
+
Deploy the histogram data drift application.
|
|
3549
|
+
|
|
3550
|
+
:param project: Project name.
|
|
3551
|
+
:param image: The image on which the application will run.
|
|
3552
|
+
"""
|
|
3553
|
+
self.api_call(
|
|
3554
|
+
method=mlrun.common.types.HTTPMethod.POST,
|
|
3555
|
+
path=f"projects/{project}/model-monitoring/deploy-histogram-data-drift-app",
|
|
3556
|
+
params={"image": image},
|
|
3557
|
+
)
|
|
3558
|
+
|
|
3559
|
+
def set_model_monitoring_credentials(
|
|
3560
|
+
self,
|
|
3561
|
+
project: str,
|
|
3562
|
+
credentials: dict[str, str],
|
|
3563
|
+
replace_creds: bool,
|
|
3564
|
+
) -> None:
|
|
3565
|
+
"""
|
|
3566
|
+
Set the credentials for the model monitoring application.
|
|
3567
|
+
|
|
3568
|
+
:param project: Project name.
|
|
3569
|
+
:param credentials: Credentials to set.
|
|
3570
|
+
:param replace_creds: If True, will override the existing credentials.
|
|
3571
|
+
"""
|
|
3572
|
+
self.api_call(
|
|
3573
|
+
method=mlrun.common.types.HTTPMethod.POST,
|
|
3574
|
+
path=f"projects/{project}/model-monitoring/set-model-monitoring-credentials",
|
|
3575
|
+
params={**credentials, "replace_creds": replace_creds},
|
|
3576
|
+
)
|
|
3133
3577
|
|
|
3134
3578
|
def create_hub_source(
|
|
3135
3579
|
self, source: Union[dict, mlrun.common.schemas.IndexedHubSource]
|
|
@@ -3160,8 +3604,10 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3160
3604
|
metadata=mlrun.common.schemas.HubObjectMetadata(
|
|
3161
3605
|
name="priv", description="a private source"
|
|
3162
3606
|
),
|
|
3163
|
-
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3164
|
-
|
|
3607
|
+
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3608
|
+
path="/local/path/to/source", channel="development"
|
|
3609
|
+
),
|
|
3610
|
+
),
|
|
3165
3611
|
)
|
|
3166
3612
|
db.create_hub_source(private_source)
|
|
3167
3613
|
|
|
@@ -3175,9 +3621,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3175
3621
|
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3176
3622
|
path="/local/path/to/source/2",
|
|
3177
3623
|
channel="development",
|
|
3178
|
-
credentials={...}
|
|
3179
|
-
)
|
|
3180
|
-
)
|
|
3624
|
+
credentials={...},
|
|
3625
|
+
),
|
|
3626
|
+
),
|
|
3181
3627
|
)
|
|
3182
3628
|
db.create_hub_source(another_source)
|
|
3183
3629
|
|
|
@@ -3341,7 +3787,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3341
3787
|
:param version: Get a specific version of the item. Default is ``None``.
|
|
3342
3788
|
:param tag: Get a specific version of the item identified by tag. Default is ``latest``.
|
|
3343
3789
|
|
|
3344
|
-
:
|
|
3790
|
+
:returns: http response with the asset in the content attribute
|
|
3345
3791
|
"""
|
|
3346
3792
|
path = f"hub/sources/{source_name}/items/{item_name}/assets/{asset_name}"
|
|
3347
3793
|
params = {
|
|
@@ -3369,24 +3815,81 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3369
3815
|
body=dict_to_json(authorization_verification_input.dict()),
|
|
3370
3816
|
)
|
|
3371
3817
|
|
|
3372
|
-
def list_api_gateways(self, project=None):
|
|
3818
|
+
def list_api_gateways(self, project=None) -> mlrun.common.schemas.APIGatewaysOutput:
|
|
3373
3819
|
"""
|
|
3374
3820
|
Returns a list of Nuclio api gateways
|
|
3375
|
-
:param project: optional str parameter to filter by project, if not passed, default Nuclio's value is taken
|
|
3376
3821
|
|
|
3377
|
-
:
|
|
3378
|
-
|
|
3379
|
-
|
|
3822
|
+
:param project: optional str parameter to filter by project, if not passed, default project value is taken
|
|
3823
|
+
|
|
3824
|
+
:returns: :py:class:`~mlrun.common.schemas.APIGateways`.
|
|
3380
3825
|
"""
|
|
3381
3826
|
project = project or config.default_project
|
|
3382
3827
|
error = "list api gateways"
|
|
3383
|
-
endpoint_path = f"projects/{project}/
|
|
3384
|
-
|
|
3385
|
-
return
|
|
3828
|
+
endpoint_path = f"projects/{project}/api-gateways"
|
|
3829
|
+
response = self.api_call("GET", endpoint_path, error)
|
|
3830
|
+
return mlrun.common.schemas.APIGatewaysOutput(**response.json())
|
|
3831
|
+
|
|
3832
|
+
def get_api_gateway(self, name, project=None) -> mlrun.common.schemas.APIGateway:
|
|
3833
|
+
"""
|
|
3834
|
+
Returns an API gateway
|
|
3835
|
+
|
|
3836
|
+
:param name: API gateway name
|
|
3837
|
+
:param project: optional str parameter to filter by project, if not passed, default project value is taken
|
|
3838
|
+
|
|
3839
|
+
:returns: :py:class:`~mlrun.common.schemas.APIGateway`.
|
|
3840
|
+
"""
|
|
3841
|
+
project = project or config.default_project
|
|
3842
|
+
error = "get api gateway"
|
|
3843
|
+
endpoint_path = f"projects/{project}/api-gateways/{name}"
|
|
3844
|
+
response = self.api_call("GET", endpoint_path, error)
|
|
3845
|
+
return mlrun.common.schemas.APIGateway(**response.json())
|
|
3846
|
+
|
|
3847
|
+
def delete_api_gateway(self, name, project=None):
|
|
3848
|
+
"""
|
|
3849
|
+
Deletes an API gateway
|
|
3850
|
+
|
|
3851
|
+
:param name: API gateway name
|
|
3852
|
+
:param project: Project name
|
|
3853
|
+
"""
|
|
3854
|
+
project = project or config.default_project
|
|
3855
|
+
error = "delete api gateway"
|
|
3856
|
+
endpoint_path = f"projects/{project}/api-gateways/{name}"
|
|
3857
|
+
self.api_call("DELETE", endpoint_path, error)
|
|
3858
|
+
|
|
3859
|
+
def store_api_gateway(
|
|
3860
|
+
self,
|
|
3861
|
+
api_gateway: Union[
|
|
3862
|
+
mlrun.common.schemas.APIGateway,
|
|
3863
|
+
mlrun.runtimes.nuclio.api_gateway.APIGateway,
|
|
3864
|
+
],
|
|
3865
|
+
project: Optional[str] = None,
|
|
3866
|
+
) -> mlrun.common.schemas.APIGateway:
|
|
3867
|
+
"""
|
|
3868
|
+
Stores an API Gateway.
|
|
3869
|
+
|
|
3870
|
+
:param api_gateway: :py:class:`~mlrun.runtimes.nuclio.APIGateway`
|
|
3871
|
+
or :py:class:`~mlrun.common.schemas.APIGateway`: API Gateway entity.
|
|
3872
|
+
:param project: project name. Mandatory if api_gateway is mlrun.common.schemas.APIGateway.
|
|
3873
|
+
|
|
3874
|
+
:returns: :py:class:`~mlrun.common.schemas.APIGateway`.
|
|
3875
|
+
"""
|
|
3876
|
+
|
|
3877
|
+
if isinstance(api_gateway, mlrun.runtimes.nuclio.api_gateway.APIGateway):
|
|
3878
|
+
api_gateway = api_gateway.to_scheme()
|
|
3879
|
+
endpoint_path = f"projects/{project}/api-gateways/{api_gateway.metadata.name}"
|
|
3880
|
+
error = "store api gateways"
|
|
3881
|
+
response = self.api_call(
|
|
3882
|
+
"PUT",
|
|
3883
|
+
endpoint_path,
|
|
3884
|
+
error,
|
|
3885
|
+
json=api_gateway.dict(exclude_none=True),
|
|
3886
|
+
)
|
|
3887
|
+
return mlrun.common.schemas.APIGateway(**response.json())
|
|
3386
3888
|
|
|
3387
3889
|
def trigger_migrations(self) -> Optional[mlrun.common.schemas.BackgroundTask]:
|
|
3388
3890
|
"""Trigger migrations (will do nothing if no migrations are needed) and wait for them to finish if actually
|
|
3389
3891
|
triggered
|
|
3892
|
+
|
|
3390
3893
|
:returns: :py:class:`~mlrun.common.schemas.BackgroundTask`.
|
|
3391
3894
|
"""
|
|
3392
3895
|
response = self.api_call(
|
|
@@ -3409,6 +3912,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3409
3912
|
):
|
|
3410
3913
|
"""
|
|
3411
3914
|
Set notifications on a run. This will override any existing notifications on the run.
|
|
3915
|
+
|
|
3412
3916
|
:param project: Project containing the run.
|
|
3413
3917
|
:param run_uid: UID of the run.
|
|
3414
3918
|
:param notifications: List of notifications to set on the run. Default is an empty list.
|
|
@@ -3434,6 +3938,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3434
3938
|
):
|
|
3435
3939
|
"""
|
|
3436
3940
|
Set notifications on a schedule. This will override any existing notifications on the schedule.
|
|
3941
|
+
|
|
3437
3942
|
:param project: Project containing the schedule.
|
|
3438
3943
|
:param schedule_name: Name of the schedule.
|
|
3439
3944
|
:param notifications: List of notifications to set on the schedule. Default is an empty list.
|
|
@@ -3465,6 +3970,16 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3465
3970
|
"""
|
|
3466
3971
|
pass
|
|
3467
3972
|
|
|
3973
|
+
def store_alert_notifications(
|
|
3974
|
+
self,
|
|
3975
|
+
session,
|
|
3976
|
+
notification_objects: list[mlrun.model.Notification],
|
|
3977
|
+
alert_id: str,
|
|
3978
|
+
project: str,
|
|
3979
|
+
mask_params: bool = True,
|
|
3980
|
+
):
|
|
3981
|
+
pass
|
|
3982
|
+
|
|
3468
3983
|
def submit_workflow(
|
|
3469
3984
|
self,
|
|
3470
3985
|
project: str,
|
|
@@ -3572,15 +4087,16 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3572
4087
|
) -> str:
|
|
3573
4088
|
"""
|
|
3574
4089
|
Loading a project remotely from the given source.
|
|
4090
|
+
|
|
3575
4091
|
:param name: project name
|
|
3576
4092
|
:param url: git or tar.gz or .zip sources archive path e.g.:
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
4093
|
+
git://github.com/mlrun/demo-xgb-project.git
|
|
4094
|
+
http://mysite/archived-project.zip
|
|
4095
|
+
The git project should include the project yaml file.
|
|
3580
4096
|
:param secrets: Secrets to store in project in order to load it from the provided url. For more
|
|
3581
|
-
|
|
4097
|
+
information see :py:func:`mlrun.load_project` function.
|
|
3582
4098
|
:param save_secrets: Whether to store secrets in the loaded project. Setting to False will cause waiting
|
|
3583
|
-
|
|
4099
|
+
for the process completion.
|
|
3584
4100
|
|
|
3585
4101
|
:returns: The terminal state of load project process.
|
|
3586
4102
|
"""
|
|
@@ -3656,6 +4172,168 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3656
4172
|
|
|
3657
4173
|
self.api_call(method="PUT", path=_path, json=profile.dict())
|
|
3658
4174
|
|
|
4175
|
+
@staticmethod
|
|
4176
|
+
def warn_on_s3_and_ecr_permissions_conflict(func):
|
|
4177
|
+
is_s3_source = func.spec.build.source and func.spec.build.source.startswith(
|
|
4178
|
+
"s3://"
|
|
4179
|
+
)
|
|
4180
|
+
is_ecr_image = mlrun.utils.is_ecr_url(config.httpdb.builder.docker_registry)
|
|
4181
|
+
if not func.spec.build.load_source_on_run and is_s3_source and is_ecr_image:
|
|
4182
|
+
logger.warning(
|
|
4183
|
+
"Building a function image to ECR and loading an S3 source to the image may require conflicting access "
|
|
4184
|
+
"keys. Only the permissions granted to the platform's configured secret will take affect "
|
|
4185
|
+
"(see mlrun.mlconf.httpdb.builder.docker_registry_secret). "
|
|
4186
|
+
"In case the permissions are limited to ECR scope, you may use pull_at_runtime=True instead",
|
|
4187
|
+
source=func.spec.build.source,
|
|
4188
|
+
load_source_on_run=func.spec.build.load_source_on_run,
|
|
4189
|
+
default_docker_registry=config.httpdb.builder.docker_registry,
|
|
4190
|
+
)
|
|
4191
|
+
|
|
4192
|
+
def generate_event(
|
|
4193
|
+
self, name: str, event_data: Union[dict, mlrun.common.schemas.Event], project=""
|
|
4194
|
+
):
|
|
4195
|
+
"""
|
|
4196
|
+
Generate an event.
|
|
4197
|
+
|
|
4198
|
+
:param name: The name of the event.
|
|
4199
|
+
:param event_data: The data of the event.
|
|
4200
|
+
:param project: The project that the event belongs to.
|
|
4201
|
+
"""
|
|
4202
|
+
if mlrun.mlconf.alerts.mode == mlrun.common.schemas.alert.AlertsModes.disabled:
|
|
4203
|
+
logger.warning("Alerts are disabled, event will not be generated")
|
|
4204
|
+
|
|
4205
|
+
project = project or config.default_project
|
|
4206
|
+
endpoint_path = f"projects/{project}/events/{name}"
|
|
4207
|
+
error_message = f"post event {project}/events/{name}"
|
|
4208
|
+
if isinstance(event_data, mlrun.common.schemas.Event):
|
|
4209
|
+
event_data = event_data.dict()
|
|
4210
|
+
self.api_call(
|
|
4211
|
+
"POST", endpoint_path, error_message, body=dict_to_json(event_data)
|
|
4212
|
+
)
|
|
4213
|
+
|
|
4214
|
+
def store_alert_config(
|
|
4215
|
+
self,
|
|
4216
|
+
alert_name: str,
|
|
4217
|
+
alert_data: Union[dict, AlertConfig],
|
|
4218
|
+
project="",
|
|
4219
|
+
) -> AlertConfig:
|
|
4220
|
+
"""
|
|
4221
|
+
Create/modify an alert.
|
|
4222
|
+
|
|
4223
|
+
:param alert_name: The name of the alert.
|
|
4224
|
+
:param alert_data: The data of the alert.
|
|
4225
|
+
:param project: The project that the alert belongs to.
|
|
4226
|
+
:returns: The created/modified alert.
|
|
4227
|
+
"""
|
|
4228
|
+
if not alert_data:
|
|
4229
|
+
raise mlrun.errors.MLRunInvalidArgumentError("Alert data must be provided")
|
|
4230
|
+
|
|
4231
|
+
if mlrun.mlconf.alerts.mode == mlrun.common.schemas.alert.AlertsModes.disabled:
|
|
4232
|
+
logger.warning(
|
|
4233
|
+
"Alerts are disabled, alert will still be stored but will not be triggered"
|
|
4234
|
+
)
|
|
4235
|
+
|
|
4236
|
+
project = project or config.default_project
|
|
4237
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
4238
|
+
error_message = f"put alert {project}/alerts/{alert_name}"
|
|
4239
|
+
alert_instance = (
|
|
4240
|
+
alert_data
|
|
4241
|
+
if isinstance(alert_data, AlertConfig)
|
|
4242
|
+
else AlertConfig.from_dict(alert_data)
|
|
4243
|
+
)
|
|
4244
|
+
# Validation is necessary here because users can directly invoke this function
|
|
4245
|
+
# through `mlrun.get_run_db().store_alert_config()`.
|
|
4246
|
+
alert_instance.validate_required_fields()
|
|
4247
|
+
|
|
4248
|
+
alert_data = alert_instance.to_dict()
|
|
4249
|
+
body = _as_json(alert_data)
|
|
4250
|
+
response = self.api_call("PUT", endpoint_path, error_message, body=body)
|
|
4251
|
+
return AlertConfig.from_dict(response.json())
|
|
4252
|
+
|
|
4253
|
+
def get_alert_config(self, alert_name: str, project="") -> AlertConfig:
|
|
4254
|
+
"""
|
|
4255
|
+
Retrieve an alert.
|
|
4256
|
+
|
|
4257
|
+
:param alert_name: The name of the alert to retrieve.
|
|
4258
|
+
:param project: The project that the alert belongs to.
|
|
4259
|
+
|
|
4260
|
+
:returns: The alert object.
|
|
4261
|
+
"""
|
|
4262
|
+
project = project or config.default_project
|
|
4263
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
4264
|
+
error_message = f"get alert {project}/alerts/{alert_name}"
|
|
4265
|
+
response = self.api_call("GET", endpoint_path, error_message)
|
|
4266
|
+
return AlertConfig.from_dict(response.json())
|
|
4267
|
+
|
|
4268
|
+
def list_alerts_configs(self, project="") -> list[AlertConfig]:
|
|
4269
|
+
"""
|
|
4270
|
+
Retrieve list of alerts of a project.
|
|
4271
|
+
|
|
4272
|
+
:param project: The project name.
|
|
4273
|
+
|
|
4274
|
+
:returns: All the alerts objects of the project.
|
|
4275
|
+
"""
|
|
4276
|
+
project = project or config.default_project
|
|
4277
|
+
endpoint_path = f"projects/{project}/alerts"
|
|
4278
|
+
error_message = f"get alerts {project}/alerts"
|
|
4279
|
+
response = self.api_call("GET", endpoint_path, error_message).json()
|
|
4280
|
+
results = []
|
|
4281
|
+
for item in response:
|
|
4282
|
+
results.append(AlertConfig(**item))
|
|
4283
|
+
return results
|
|
4284
|
+
|
|
4285
|
+
def delete_alert_config(self, alert_name: str, project=""):
|
|
4286
|
+
"""
|
|
4287
|
+
Delete an alert.
|
|
4288
|
+
:param alert_name: The name of the alert to delete.
|
|
4289
|
+
:param project: The project that the alert belongs to.
|
|
4290
|
+
"""
|
|
4291
|
+
project = project or config.default_project
|
|
4292
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
4293
|
+
error_message = f"delete alert {project}/alerts/{alert_name}"
|
|
4294
|
+
self.api_call("DELETE", endpoint_path, error_message)
|
|
4295
|
+
|
|
4296
|
+
def reset_alert_config(self, alert_name: str, project=""):
|
|
4297
|
+
"""
|
|
4298
|
+
Reset an alert.
|
|
4299
|
+
|
|
4300
|
+
:param alert_name: The name of the alert to reset.
|
|
4301
|
+
:param project: The project that the alert belongs to.
|
|
4302
|
+
"""
|
|
4303
|
+
project = project or config.default_project
|
|
4304
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}/reset"
|
|
4305
|
+
error_message = f"post alert {project}/alerts/{alert_name}/reset"
|
|
4306
|
+
self.api_call("POST", endpoint_path, error_message)
|
|
4307
|
+
|
|
4308
|
+
def get_alert_template(
|
|
4309
|
+
self, template_name: str
|
|
4310
|
+
) -> mlrun.common.schemas.AlertTemplate:
|
|
4311
|
+
"""
|
|
4312
|
+
Retrieve a specific alert template.
|
|
4313
|
+
|
|
4314
|
+
:param template_name: The name of the template to retrieve.
|
|
4315
|
+
|
|
4316
|
+
:returns: The template object.
|
|
4317
|
+
"""
|
|
4318
|
+
endpoint_path = f"alert-templates/{template_name}"
|
|
4319
|
+
error_message = f"get template alert-templates/{template_name}"
|
|
4320
|
+
response = self.api_call("GET", endpoint_path, error_message)
|
|
4321
|
+
return mlrun.common.schemas.AlertTemplate(**response.json())
|
|
4322
|
+
|
|
4323
|
+
def list_alert_templates(self) -> list[mlrun.common.schemas.AlertTemplate]:
|
|
4324
|
+
"""
|
|
4325
|
+
Retrieve list of all alert templates.
|
|
4326
|
+
|
|
4327
|
+
:returns: All the alert template objects in the database.
|
|
4328
|
+
"""
|
|
4329
|
+
endpoint_path = "alert-templates"
|
|
4330
|
+
error_message = "get templates /alert-templates"
|
|
4331
|
+
response = self.api_call("GET", endpoint_path, error_message).json()
|
|
4332
|
+
results = []
|
|
4333
|
+
for item in response:
|
|
4334
|
+
results.append(mlrun.common.schemas.AlertTemplate(**item))
|
|
4335
|
+
return results
|
|
4336
|
+
|
|
3659
4337
|
|
|
3660
4338
|
def _as_json(obj):
|
|
3661
4339
|
fn = getattr(obj, "to_json", None)
|