mlrun 1.7.0rc4__py3-none-any.whl → 1.7.0rc20__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 +25 -111
- mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
- mlrun/alerts/alert.py +144 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +38 -254
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +41 -47
- mlrun/artifacts/model.py +30 -158
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +68 -0
- mlrun/common/formatters/__init__.py +19 -0
- mlrun/{model_monitoring/stores/models/sqlite.py → common/formatters/artifact.py} +6 -8
- mlrun/common/formatters/base.py +78 -0
- mlrun/common/formatters/function.py +41 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +25 -4
- mlrun/common/schemas/alert.py +203 -0
- mlrun/common/schemas/api_gateway.py +148 -0
- mlrun/common/schemas/artifact.py +15 -5
- mlrun/common/schemas/auth.py +8 -2
- mlrun/common/schemas/client_spec.py +2 -0
- mlrun/common/schemas/frontend_spec.py +1 -0
- mlrun/common/schemas/function.py +4 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/__init__.py +19 -3
- mlrun/common/schemas/model_monitoring/constants.py +96 -26
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +86 -2
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +0 -9
- mlrun/common/schemas/project.py +22 -21
- mlrun/common/types.py +7 -1
- mlrun/config.py +87 -19
- mlrun/data_types/data_types.py +4 -0
- mlrun/data_types/to_pandas.py +9 -9
- mlrun/datastore/__init__.py +5 -8
- mlrun/datastore/alibaba_oss.py +130 -0
- mlrun/datastore/azure_blob.py +4 -5
- mlrun/datastore/base.py +69 -30
- mlrun/datastore/datastore.py +10 -2
- mlrun/datastore/datastore_profile.py +90 -6
- mlrun/datastore/google_cloud_storage.py +1 -1
- mlrun/datastore/hdfs.py +5 -0
- mlrun/datastore/inmem.py +2 -2
- mlrun/datastore/redis.py +2 -2
- mlrun/datastore/s3.py +5 -0
- mlrun/datastore/snowflake_utils.py +43 -0
- mlrun/datastore/sources.py +172 -44
- mlrun/datastore/store_resources.py +7 -7
- mlrun/datastore/targets.py +285 -41
- mlrun/datastore/utils.py +68 -5
- mlrun/datastore/v3io.py +27 -50
- mlrun/db/auth_utils.py +152 -0
- mlrun/db/base.py +149 -14
- mlrun/db/factory.py +1 -1
- mlrun/db/httpdb.py +608 -178
- mlrun/db/nopdb.py +191 -7
- mlrun/errors.py +11 -0
- mlrun/execution.py +37 -20
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +21 -52
- mlrun/feature_store/feature_set.py +48 -23
- mlrun/feature_store/feature_vector.py +2 -1
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/conversion.py +9 -9
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +9 -3
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +34 -24
- mlrun/feature_store/steps.py +30 -19
- mlrun/features.py +4 -13
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- 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 +2 -1
- mlrun/frameworks/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- 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 +10 -11
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +6 -5
- mlrun/launcher/client.py +8 -6
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +9 -3
- mlrun/launcher/remote.py +9 -3
- mlrun/lists.py +6 -2
- mlrun/model.py +58 -19
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +127 -301
- mlrun/model_monitoring/application.py +5 -296
- mlrun/model_monitoring/applications/__init__.py +11 -0
- mlrun/model_monitoring/applications/_application_steps.py +157 -0
- mlrun/model_monitoring/applications/base.py +282 -0
- mlrun/model_monitoring/applications/context.py +214 -0
- mlrun/model_monitoring/applications/evidently_base.py +211 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +224 -93
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +30 -36
- mlrun/model_monitoring/db/__init__.py +18 -0
- mlrun/model_monitoring/{stores → db/stores}/__init__.py +43 -36
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/{stores/model_endpoint_store.py → db/stores/base/store.py} +58 -32
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/{stores → db/stores/sqldb}/models/base.py +109 -5
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +88 -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 +684 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/{stores/kv_model_endpoint_store.py → db/stores/v3io_kv/kv_store.py} +302 -155
- mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
- mlrun/model_monitoring/db/tsdb/base.py +329 -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 +240 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +397 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +630 -0
- mlrun/model_monitoring/evidently_application.py +6 -118
- mlrun/model_monitoring/features_drift_table.py +34 -22
- mlrun/model_monitoring/helpers.py +100 -7
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +93 -228
- mlrun/model_monitoring/tracking_policy.py +7 -1
- mlrun/model_monitoring/writer.py +152 -124
- mlrun/package/packagers_manager.py +1 -0
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +21 -202
- mlrun/projects/operations.py +30 -16
- mlrun/projects/pipelines.py +92 -99
- mlrun/projects/project.py +757 -268
- mlrun/render.py +15 -14
- mlrun/run.py +160 -162
- mlrun/runtimes/__init__.py +55 -3
- mlrun/runtimes/base.py +33 -19
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +0 -28
- mlrun/runtimes/kubejob.py +28 -122
- mlrun/runtimes/local.py +5 -2
- 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 +709 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +523 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/nuclio/function.py +98 -58
- mlrun/runtimes/nuclio/serving.py +36 -42
- mlrun/runtimes/pod.py +196 -45
- mlrun/runtimes/remotesparkjob.py +1 -1
- mlrun/runtimes/sparkjob/spark3job.py +1 -1
- mlrun/runtimes/utils.py +6 -73
- mlrun/secrets.py +6 -2
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +7 -4
- mlrun/serving/server.py +7 -8
- mlrun/serving/states.py +73 -43
- mlrun/serving/v2_serving.py +8 -7
- mlrun/track/tracker.py +2 -1
- mlrun/utils/async_http.py +25 -5
- mlrun/utils/helpers.py +141 -75
- mlrun/utils/http.py +1 -1
- mlrun/utils/logger.py +39 -7
- mlrun/utils/notifications/notification/__init__.py +14 -9
- mlrun/utils/notifications/notification/base.py +12 -0
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +3 -1
- mlrun/utils/notifications/notification/ipython.py +2 -0
- mlrun/utils/notifications/notification/slack.py +101 -21
- mlrun/utils/notifications/notification/webhook.py +11 -1
- mlrun/utils/notifications/notification_pusher.py +147 -16
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/v3io_clients.py +0 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/METADATA +33 -18
- mlrun-1.7.0rc20.dist-info/RECORD +353 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/WHEEL +1 -1
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/batch.py +0 -974
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
- mlrun/platforms/other.py +0 -305
- mlrun-1.7.0rc4.dist-info/RECORD +0 -321
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/top_level.txt +0 -0
mlrun/db/httpdb.py
CHANGED
|
@@ -11,28 +11,36 @@
|
|
|
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.utils
|
|
42
|
+
from mlrun.alerts.alert import AlertConfig
|
|
43
|
+
from mlrun.db.auth_utils import OAuthClientIDTokenProvider, StaticTokenProvider
|
|
36
44
|
from mlrun.errors import MLRunInvalidArgumentError, err_to_str
|
|
37
45
|
|
|
38
46
|
from ..artifacts import Artifact
|
|
@@ -45,7 +53,6 @@ from ..utils import (
|
|
|
45
53
|
datetime_to_iso,
|
|
46
54
|
dict_to_json,
|
|
47
55
|
logger,
|
|
48
|
-
new_pipe_metadata,
|
|
49
56
|
normalize_name,
|
|
50
57
|
version,
|
|
51
58
|
)
|
|
@@ -133,17 +140,28 @@ class HTTPRunDB(RunDBInterface):
|
|
|
133
140
|
endpoint += f":{parsed_url.port}"
|
|
134
141
|
base_url = f"{parsed_url.scheme}://{endpoint}{parsed_url.path}"
|
|
135
142
|
|
|
143
|
+
self.base_url = base_url
|
|
136
144
|
username = parsed_url.username or config.httpdb.user
|
|
137
145
|
password = parsed_url.password or config.httpdb.password
|
|
146
|
+
self.token_provider = None
|
|
138
147
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
148
|
+
if config.auth_with_client_id.enabled:
|
|
149
|
+
self.token_provider = OAuthClientIDTokenProvider(
|
|
150
|
+
token_endpoint=mlrun.get_secret_or_env("MLRUN_AUTH_TOKEN_ENDPOINT"),
|
|
151
|
+
client_id=mlrun.get_secret_or_env("MLRUN_AUTH_CLIENT_ID"),
|
|
152
|
+
client_secret=mlrun.get_secret_or_env("MLRUN_AUTH_CLIENT_SECRET"),
|
|
153
|
+
timeout=config.auth_with_client_id.request_timeout,
|
|
154
|
+
)
|
|
155
|
+
else:
|
|
156
|
+
username, password, token = mlrun.platforms.add_or_refresh_credentials(
|
|
157
|
+
parsed_url.hostname, username, password, config.httpdb.token
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
if token:
|
|
161
|
+
self.token_provider = StaticTokenProvider(token)
|
|
142
162
|
|
|
143
|
-
self.base_url = base_url
|
|
144
163
|
self.user = username
|
|
145
164
|
self.password = password
|
|
146
|
-
self.token = token
|
|
147
165
|
|
|
148
166
|
def __repr__(self):
|
|
149
167
|
cls = self.__class__.__name__
|
|
@@ -179,7 +197,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
179
197
|
headers=None,
|
|
180
198
|
timeout=45,
|
|
181
199
|
version=None,
|
|
182
|
-
):
|
|
200
|
+
) -> requests.Response:
|
|
183
201
|
"""Perform a direct REST API call on the :py:mod:`mlrun` API server.
|
|
184
202
|
|
|
185
203
|
Caution:
|
|
@@ -197,7 +215,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
197
215
|
:param version: API version to use, None (the default) will mean to use the default value from config,
|
|
198
216
|
for un-versioned api set an empty string.
|
|
199
217
|
|
|
200
|
-
:return:
|
|
218
|
+
:return: `requests.Response` HTTP response object
|
|
201
219
|
"""
|
|
202
220
|
url = self.get_base_api_url(path, version)
|
|
203
221
|
kw = {
|
|
@@ -213,17 +231,19 @@ class HTTPRunDB(RunDBInterface):
|
|
|
213
231
|
|
|
214
232
|
if self.user:
|
|
215
233
|
kw["auth"] = (self.user, self.password)
|
|
216
|
-
elif self.
|
|
217
|
-
|
|
218
|
-
if
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
"
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
234
|
+
elif self.token_provider:
|
|
235
|
+
token = self.token_provider.get_token()
|
|
236
|
+
if token:
|
|
237
|
+
# Iguazio auth doesn't support passing token through bearer, so use cookie instead
|
|
238
|
+
if self.token_provider.is_iguazio_session():
|
|
239
|
+
session_cookie = f'j:{{"sid": "{token}"}}'
|
|
240
|
+
cookies = {
|
|
241
|
+
"session": session_cookie,
|
|
242
|
+
}
|
|
243
|
+
kw["cookies"] = cookies
|
|
244
|
+
else:
|
|
245
|
+
if "Authorization" not in kw.setdefault("headers", {}):
|
|
246
|
+
kw["headers"].update({"Authorization": "Bearer " + token})
|
|
227
247
|
|
|
228
248
|
if mlrun.common.schemas.HeaderNames.client_version not in kw.setdefault(
|
|
229
249
|
"headers", {}
|
|
@@ -278,6 +298,68 @@ class HTTPRunDB(RunDBInterface):
|
|
|
278
298
|
|
|
279
299
|
return response
|
|
280
300
|
|
|
301
|
+
def paginated_api_call(
|
|
302
|
+
self,
|
|
303
|
+
method,
|
|
304
|
+
path,
|
|
305
|
+
error=None,
|
|
306
|
+
params=None,
|
|
307
|
+
body=None,
|
|
308
|
+
json=None,
|
|
309
|
+
headers=None,
|
|
310
|
+
timeout=45,
|
|
311
|
+
version=None,
|
|
312
|
+
) -> typing.Generator[requests.Response, None, None]:
|
|
313
|
+
"""
|
|
314
|
+
Calls the api with pagination, yielding each page of the response
|
|
315
|
+
"""
|
|
316
|
+
|
|
317
|
+
def _api_call(_params):
|
|
318
|
+
return self.api_call(
|
|
319
|
+
method=method,
|
|
320
|
+
path=path,
|
|
321
|
+
error=error,
|
|
322
|
+
params=_params,
|
|
323
|
+
body=body,
|
|
324
|
+
json=json,
|
|
325
|
+
headers=headers,
|
|
326
|
+
timeout=timeout,
|
|
327
|
+
version=version,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
first_page_params = deepcopy(params) or {}
|
|
331
|
+
first_page_params["page"] = 1
|
|
332
|
+
first_page_params["page-size"] = config.httpdb.pagination.default_page_size
|
|
333
|
+
response = _api_call(first_page_params)
|
|
334
|
+
page_token = response.json().get("pagination", {}).get("page-token")
|
|
335
|
+
if not page_token:
|
|
336
|
+
yield response
|
|
337
|
+
return
|
|
338
|
+
|
|
339
|
+
params_with_page_token = deepcopy(params) or {}
|
|
340
|
+
params_with_page_token["page-token"] = page_token
|
|
341
|
+
while page_token:
|
|
342
|
+
yield response
|
|
343
|
+
try:
|
|
344
|
+
response = _api_call(params_with_page_token)
|
|
345
|
+
except mlrun.errors.MLRunNotFoundError:
|
|
346
|
+
# pagination token expired
|
|
347
|
+
break
|
|
348
|
+
|
|
349
|
+
page_token = response.json().get("pagination", {}).get("page-token", None)
|
|
350
|
+
|
|
351
|
+
@staticmethod
|
|
352
|
+
def process_paginated_responses(
|
|
353
|
+
responses: typing.Generator[requests.Response, None, None], key: str = "data"
|
|
354
|
+
) -> list[typing.Any]:
|
|
355
|
+
"""
|
|
356
|
+
Processes the paginated responses and returns the combined data
|
|
357
|
+
"""
|
|
358
|
+
data = []
|
|
359
|
+
for response in responses:
|
|
360
|
+
data.extend(response.json().get(key, []))
|
|
361
|
+
return data
|
|
362
|
+
|
|
281
363
|
def _init_session(self, retry_on_post: bool = False):
|
|
282
364
|
return mlrun.utils.HTTPSessionWithRetry(
|
|
283
365
|
retry_on_exception=config.httpdb.retry_api_call_on_exception
|
|
@@ -310,7 +392,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
310
392
|
|
|
311
393
|
For example::
|
|
312
394
|
|
|
313
|
-
config.dbpath = config.dbpath or
|
|
395
|
+
config.dbpath = config.dbpath or "http://mlrun-api:8080"
|
|
314
396
|
db = get_run_db().connect()
|
|
315
397
|
"""
|
|
316
398
|
# hack to allow unit tests to instantiate HTTPRunDB without a real server behind
|
|
@@ -450,6 +532,10 @@ class HTTPRunDB(RunDBInterface):
|
|
|
450
532
|
server_cfg.get("model_endpoint_monitoring_endpoint_store_connection")
|
|
451
533
|
or config.model_endpoint_monitoring.endpoint_store_connection
|
|
452
534
|
)
|
|
535
|
+
config.model_endpoint_monitoring.tsdb_connection = (
|
|
536
|
+
server_cfg.get("model_monitoring_tsdb_connection")
|
|
537
|
+
or config.model_endpoint_monitoring.tsdb_connection
|
|
538
|
+
)
|
|
453
539
|
config.packagers = server_cfg.get("packagers") or config.packagers
|
|
454
540
|
server_data_prefixes = server_cfg.get("feature_store_data_prefixes") or {}
|
|
455
541
|
for prefix in ["default", "nosql", "redisnosql"]:
|
|
@@ -462,6 +548,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
462
548
|
server_cfg.get("feature_store_default_targets")
|
|
463
549
|
or config.feature_store.default_targets
|
|
464
550
|
)
|
|
551
|
+
config.alerts.mode = server_cfg.get("alerts_mode") or config.alerts.mode
|
|
465
552
|
|
|
466
553
|
except Exception as exc:
|
|
467
554
|
logger.warning(
|
|
@@ -508,7 +595,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
508
595
|
if offset < 0:
|
|
509
596
|
raise MLRunInvalidArgumentError("Offset cannot be negative")
|
|
510
597
|
if size is None:
|
|
511
|
-
size = int(
|
|
598
|
+
size = int(mlrun.mlconf.httpdb.logs.pull_logs_default_size_limit)
|
|
512
599
|
elif size == -1:
|
|
513
600
|
logger.warning(
|
|
514
601
|
"Retrieving all logs. This may be inefficient and can result in a large log."
|
|
@@ -554,33 +641,35 @@ class HTTPRunDB(RunDBInterface):
|
|
|
554
641
|
|
|
555
642
|
state, text = self.get_log(uid, project, offset=offset)
|
|
556
643
|
if text:
|
|
557
|
-
print(text.decode(errors=
|
|
644
|
+
print(text.decode(errors=mlrun.mlconf.httpdb.logs.decode.errors))
|
|
558
645
|
nil_resp = 0
|
|
559
646
|
while True:
|
|
560
647
|
offset += len(text)
|
|
561
648
|
# if we get 3 nil responses in a row, increase the sleep time to 10 seconds
|
|
562
649
|
# TODO: refactor this to use a conditional backoff mechanism
|
|
563
650
|
if nil_resp < 3:
|
|
564
|
-
time.sleep(int(
|
|
651
|
+
time.sleep(int(mlrun.mlconf.httpdb.logs.pull_logs_default_interval))
|
|
565
652
|
else:
|
|
566
653
|
time.sleep(
|
|
567
|
-
int(
|
|
654
|
+
int(
|
|
655
|
+
mlrun.mlconf.httpdb.logs.pull_logs_backoff_no_logs_default_interval
|
|
656
|
+
)
|
|
568
657
|
)
|
|
569
658
|
state, text = self.get_log(uid, project, offset=offset)
|
|
570
659
|
if text:
|
|
571
660
|
nil_resp = 0
|
|
572
661
|
print(
|
|
573
|
-
text.decode(errors=
|
|
662
|
+
text.decode(errors=mlrun.mlconf.httpdb.logs.decode.errors),
|
|
574
663
|
end="",
|
|
575
664
|
)
|
|
576
665
|
else:
|
|
577
666
|
nil_resp += 1
|
|
578
667
|
|
|
579
668
|
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,
|
|
669
|
+
mlrun.common.runtimes.constants.RunStates.pending,
|
|
670
|
+
mlrun.common.runtimes.constants.RunStates.running,
|
|
671
|
+
mlrun.common.runtimes.constants.RunStates.created,
|
|
672
|
+
mlrun.common.runtimes.constants.RunStates.aborting,
|
|
584
673
|
]:
|
|
585
674
|
continue
|
|
586
675
|
else:
|
|
@@ -669,7 +758,10 @@ class HTTPRunDB(RunDBInterface):
|
|
|
669
758
|
uid: Optional[Union[str, list[str]]] = None,
|
|
670
759
|
project: Optional[str] = None,
|
|
671
760
|
labels: Optional[Union[str, list[str]]] = None,
|
|
672
|
-
state: Optional[
|
|
761
|
+
state: Optional[
|
|
762
|
+
mlrun.common.runtimes.constants.RunStates
|
|
763
|
+
] = None, # Backward compatibility
|
|
764
|
+
states: typing.Optional[list[mlrun.common.runtimes.constants.RunStates]] = None,
|
|
673
765
|
sort: bool = True,
|
|
674
766
|
last: int = 0,
|
|
675
767
|
iter: bool = False,
|
|
@@ -694,9 +786,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
694
786
|
|
|
695
787
|
Example::
|
|
696
788
|
|
|
697
|
-
runs = db.list_runs(
|
|
789
|
+
runs = db.list_runs(
|
|
790
|
+
name="download", project="iris", labels=["owner=admin", "kind=job"]
|
|
791
|
+
)
|
|
698
792
|
# If running in Jupyter, can use the .show() function to display the results
|
|
699
|
-
db.list_runs(name=
|
|
793
|
+
db.list_runs(name="", project=project_name).show()
|
|
700
794
|
|
|
701
795
|
|
|
702
796
|
:param name: Name of the run to retrieve.
|
|
@@ -705,7 +799,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
705
799
|
:param labels: A list of labels to filter by. Label filters work by either filtering a specific value
|
|
706
800
|
of a label (i.e. list("key=value")) or by looking for the existence of a given
|
|
707
801
|
key (i.e. "key").
|
|
708
|
-
:param state: List only runs whose state is specified.
|
|
802
|
+
:param state: Deprecated - List only runs whose state is specified (will be removed in 1.9.0)
|
|
803
|
+
:param states: List only runs whose state is one of the provided states.
|
|
709
804
|
:param sort: Whether to sort the result according to their start time. Otherwise, results will be
|
|
710
805
|
returned by their internal order in the DB (order will not be guaranteed).
|
|
711
806
|
:param last: Deprecated - currently not used (will be removed in 1.8.0).
|
|
@@ -741,11 +836,19 @@ class HTTPRunDB(RunDBInterface):
|
|
|
741
836
|
FutureWarning,
|
|
742
837
|
)
|
|
743
838
|
|
|
839
|
+
if state:
|
|
840
|
+
# TODO: Remove this in 1.9.0
|
|
841
|
+
warnings.warn(
|
|
842
|
+
"'state' is deprecated and will be removed in 1.9.0. Use 'states' instead.",
|
|
843
|
+
FutureWarning,
|
|
844
|
+
)
|
|
845
|
+
|
|
744
846
|
if (
|
|
745
847
|
not name
|
|
746
848
|
and not uid
|
|
747
849
|
and not labels
|
|
748
850
|
and not state
|
|
851
|
+
and not states
|
|
749
852
|
and not last
|
|
750
853
|
and not start_time_from
|
|
751
854
|
and not start_time_to
|
|
@@ -764,7 +867,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
764
867
|
"name": name,
|
|
765
868
|
"uid": uid,
|
|
766
869
|
"label": labels or [],
|
|
767
|
-
"state": state
|
|
870
|
+
"state": mlrun.utils.helpers.as_list(state)
|
|
871
|
+
if state is not None
|
|
872
|
+
else states or None,
|
|
768
873
|
"sort": bool2str(sort),
|
|
769
874
|
"iter": bool2str(iter),
|
|
770
875
|
"start_time_from": datetime_to_iso(start_time_from),
|
|
@@ -787,15 +892,15 @@ class HTTPRunDB(RunDBInterface):
|
|
|
787
892
|
)
|
|
788
893
|
error = "list runs"
|
|
789
894
|
_path = self._path_of("runs", project)
|
|
790
|
-
|
|
791
|
-
return RunList(
|
|
895
|
+
responses = self.paginated_api_call("GET", _path, error, params=params)
|
|
896
|
+
return RunList(self.process_paginated_responses(responses, "runs"))
|
|
792
897
|
|
|
793
898
|
def del_runs(self, name=None, project=None, labels=None, state=None, days_ago=0):
|
|
794
899
|
"""Delete a group of runs identified by the parameters of the function.
|
|
795
900
|
|
|
796
901
|
Example::
|
|
797
902
|
|
|
798
|
-
db.del_runs(state=
|
|
903
|
+
db.del_runs(state="completed")
|
|
799
904
|
|
|
800
905
|
:param name: Name of the task which the runs belong to.
|
|
801
906
|
:param project: Project to which the runs belong.
|
|
@@ -891,7 +996,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
891
996
|
error = f"read artifact {project}/{key}"
|
|
892
997
|
# explicitly set artifacts format to 'full' since old servers may default to 'legacy'
|
|
893
998
|
params = {
|
|
894
|
-
"format": mlrun.common.
|
|
999
|
+
"format": mlrun.common.formatters.ArtifactFormat.full.value,
|
|
895
1000
|
"tag": tag,
|
|
896
1001
|
"tree": tree,
|
|
897
1002
|
"uid": uid,
|
|
@@ -901,7 +1006,18 @@ class HTTPRunDB(RunDBInterface):
|
|
|
901
1006
|
resp = self.api_call("GET", endpoint_path, error, params=params, version="v2")
|
|
902
1007
|
return resp.json()
|
|
903
1008
|
|
|
904
|
-
def del_artifact(
|
|
1009
|
+
def del_artifact(
|
|
1010
|
+
self,
|
|
1011
|
+
key,
|
|
1012
|
+
tag=None,
|
|
1013
|
+
project="",
|
|
1014
|
+
tree=None,
|
|
1015
|
+
uid=None,
|
|
1016
|
+
deletion_strategy: mlrun.common.schemas.artifact.ArtifactsDeletionStrategies = (
|
|
1017
|
+
mlrun.common.schemas.artifact.ArtifactsDeletionStrategies.metadata_only
|
|
1018
|
+
),
|
|
1019
|
+
secrets: dict = None,
|
|
1020
|
+
):
|
|
905
1021
|
"""Delete an artifact.
|
|
906
1022
|
|
|
907
1023
|
:param key: Identifying key of the artifact.
|
|
@@ -909,6 +1025,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
909
1025
|
:param project: Project that the artifact belongs to.
|
|
910
1026
|
:param tree: The tree which generated this artifact.
|
|
911
1027
|
:param uid: A unique ID for this specific version of the artifact (the uid that was generated in the backend)
|
|
1028
|
+
:param deletion_strategy: The artifact deletion strategy types.
|
|
1029
|
+
:param secrets: Credentials needed to access the artifact data.
|
|
912
1030
|
"""
|
|
913
1031
|
|
|
914
1032
|
endpoint_path = f"projects/{project}/artifacts/{key}"
|
|
@@ -917,9 +1035,17 @@ class HTTPRunDB(RunDBInterface):
|
|
|
917
1035
|
"tag": tag,
|
|
918
1036
|
"tree": tree,
|
|
919
1037
|
"uid": uid,
|
|
1038
|
+
"deletion_strategy": deletion_strategy,
|
|
920
1039
|
}
|
|
921
1040
|
error = f"del artifact {project}/{key}"
|
|
922
|
-
self.api_call(
|
|
1041
|
+
self.api_call(
|
|
1042
|
+
"DELETE",
|
|
1043
|
+
endpoint_path,
|
|
1044
|
+
error,
|
|
1045
|
+
params=params,
|
|
1046
|
+
version="v2",
|
|
1047
|
+
body=dict_to_json(secrets),
|
|
1048
|
+
)
|
|
923
1049
|
|
|
924
1050
|
def list_artifacts(
|
|
925
1051
|
self,
|
|
@@ -934,17 +1060,20 @@ class HTTPRunDB(RunDBInterface):
|
|
|
934
1060
|
kind: str = None,
|
|
935
1061
|
category: Union[str, mlrun.common.schemas.ArtifactCategories] = None,
|
|
936
1062
|
tree: str = None,
|
|
1063
|
+
producer_uri: str = None,
|
|
937
1064
|
) -> ArtifactList:
|
|
938
1065
|
"""List artifacts filtered by various parameters.
|
|
939
1066
|
|
|
940
1067
|
Examples::
|
|
941
1068
|
|
|
942
1069
|
# Show latest version of all artifacts in project
|
|
943
|
-
latest_artifacts = db.list_artifacts(
|
|
1070
|
+
latest_artifacts = db.list_artifacts("", tag="latest", project="iris")
|
|
944
1071
|
# check different artifact versions for a specific artifact
|
|
945
|
-
result_versions = db.list_artifacts(
|
|
1072
|
+
result_versions = db.list_artifacts("results", tag="*", project="iris")
|
|
946
1073
|
# Show artifacts with label filters - both uploaded and of binary type
|
|
947
|
-
result_labels = db.list_artifacts(
|
|
1074
|
+
result_labels = db.list_artifacts(
|
|
1075
|
+
"results", tag="*", project="iris", labels=["uploaded", "type=binary"]
|
|
1076
|
+
)
|
|
948
1077
|
|
|
949
1078
|
:param name: Name of artifacts to retrieve. Name with '~' prefix is used as a like query, and is not
|
|
950
1079
|
case-sensitive. This means that querying for ``~name`` may return artifacts named
|
|
@@ -960,9 +1089,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
960
1089
|
:param best_iteration: Returns the artifact which belongs to the best iteration of a given run, in the case of
|
|
961
1090
|
artifacts generated from a hyper-param run. If only a single iteration exists, will return the artifact
|
|
962
1091
|
from that iteration. If using ``best_iter``, the ``iter`` parameter must not be used.
|
|
963
|
-
:param kind:
|
|
964
|
-
:param category:
|
|
965
|
-
:param tree:
|
|
1092
|
+
:param kind: Return artifacts of the requested kind.
|
|
1093
|
+
:param category: Return artifacts of the requested category.
|
|
1094
|
+
:param tree: Return artifacts of the requested tree.
|
|
1095
|
+
:param producer_uri: Return artifacts produced by the requested producer URI. Producer URI usually
|
|
1096
|
+
points to a run and is used to filter artifacts by the run that produced them when the artifact producer id
|
|
1097
|
+
is a workflow id (artifact was created as part of a workflow).
|
|
966
1098
|
"""
|
|
967
1099
|
|
|
968
1100
|
project = project or config.default_project
|
|
@@ -980,7 +1112,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
980
1112
|
"kind": kind,
|
|
981
1113
|
"category": category,
|
|
982
1114
|
"tree": tree,
|
|
983
|
-
"format": mlrun.common.
|
|
1115
|
+
"format": mlrun.common.formatters.ArtifactFormat.full.value,
|
|
1116
|
+
"producer_uri": producer_uri,
|
|
984
1117
|
}
|
|
985
1118
|
error = "list artifacts"
|
|
986
1119
|
endpoint_path = f"projects/{project}/artifacts"
|
|
@@ -1070,7 +1203,29 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1070
1203
|
project = project or config.default_project
|
|
1071
1204
|
path = f"projects/{project}/functions/{name}"
|
|
1072
1205
|
error_message = f"Failed deleting function {project}/{name}"
|
|
1073
|
-
self.api_call("DELETE", path, error_message)
|
|
1206
|
+
response = self.api_call("DELETE", path, error_message, version="v2")
|
|
1207
|
+
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
1208
|
+
logger.info(
|
|
1209
|
+
"Function is being deleted", project_name=project, function_name=name
|
|
1210
|
+
)
|
|
1211
|
+
background_task = mlrun.common.schemas.BackgroundTask(**response.json())
|
|
1212
|
+
background_task = self._wait_for_background_task_to_reach_terminal_state(
|
|
1213
|
+
background_task.metadata.name, project=project
|
|
1214
|
+
)
|
|
1215
|
+
if (
|
|
1216
|
+
background_task.status.state
|
|
1217
|
+
== mlrun.common.schemas.BackgroundTaskState.succeeded
|
|
1218
|
+
):
|
|
1219
|
+
logger.info(
|
|
1220
|
+
"Function deleted", project_name=project, function_name=name
|
|
1221
|
+
)
|
|
1222
|
+
elif (
|
|
1223
|
+
background_task.status.state
|
|
1224
|
+
== mlrun.common.schemas.BackgroundTaskState.failed
|
|
1225
|
+
):
|
|
1226
|
+
logger.info(
|
|
1227
|
+
"Function deletion failed", project_name=project, function_name=name
|
|
1228
|
+
)
|
|
1074
1229
|
|
|
1075
1230
|
def list_functions(self, name=None, project=None, tag=None, labels=None):
|
|
1076
1231
|
"""Retrieve a list of functions, filtered by specific criteria.
|
|
@@ -1089,8 +1244,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1089
1244
|
}
|
|
1090
1245
|
error = "list functions"
|
|
1091
1246
|
path = f"projects/{project}/functions"
|
|
1092
|
-
|
|
1093
|
-
return
|
|
1247
|
+
responses = self.paginated_api_call("GET", path, error, params=params)
|
|
1248
|
+
return self.process_paginated_responses(responses, "funcs")
|
|
1094
1249
|
|
|
1095
1250
|
def list_runtime_resources(
|
|
1096
1251
|
self,
|
|
@@ -1180,7 +1335,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1180
1335
|
period didn't pass.
|
|
1181
1336
|
:param grace_period: Grace period given to the runtime resource before they are actually removed, counted from
|
|
1182
1337
|
the moment they moved to terminal state
|
|
1183
|
-
(defaults to mlrun.
|
|
1338
|
+
(defaults to mlrun.mlconf.runtime_resources_deletion_grace_period).
|
|
1184
1339
|
|
|
1185
1340
|
:returns: :py:class:`~mlrun.common.schemas.GroupedByProjectRuntimeResourcesOutput` listing the runtime resources
|
|
1186
1341
|
that were removed.
|
|
@@ -1236,7 +1391,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1236
1391
|
name="run_func_on_tuesdays",
|
|
1237
1392
|
kind="job",
|
|
1238
1393
|
scheduled_object=get_data_func,
|
|
1239
|
-
cron_trigger=schemas.ScheduleCronTrigger(
|
|
1394
|
+
cron_trigger=schemas.ScheduleCronTrigger(
|
|
1395
|
+
day_of_week="tue", hour=15, minute=30
|
|
1396
|
+
),
|
|
1240
1397
|
)
|
|
1241
1398
|
db.create_schedule(project_name, schedule)
|
|
1242
1399
|
"""
|
|
@@ -1339,21 +1496,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1339
1496
|
:param builder_env: Kaniko builder pod env vars dict (for config/credentials)
|
|
1340
1497
|
:param force_build: Force building the image, even when no changes were made
|
|
1341
1498
|
"""
|
|
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
|
-
|
|
1499
|
+
self.warn_on_s3_and_ecr_permissions_conflict(func)
|
|
1357
1500
|
try:
|
|
1358
1501
|
req = {
|
|
1359
1502
|
"function": func.to_dict(),
|
|
@@ -1372,10 +1515,102 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1372
1515
|
|
|
1373
1516
|
if not resp.ok:
|
|
1374
1517
|
logger.error(f"bad resp!!\n{resp.text}")
|
|
1375
|
-
raise ValueError("bad
|
|
1518
|
+
raise ValueError("bad submit build response")
|
|
1519
|
+
|
|
1520
|
+
return resp.json()
|
|
1521
|
+
|
|
1522
|
+
def deploy_nuclio_function(
|
|
1523
|
+
self,
|
|
1524
|
+
func: mlrun.runtimes.RemoteRuntime,
|
|
1525
|
+
builder_env: Optional[dict] = None,
|
|
1526
|
+
):
|
|
1527
|
+
"""
|
|
1528
|
+
Deploy a Nuclio function.
|
|
1529
|
+
:param func: Function to build.
|
|
1530
|
+
:param builder_env: Kaniko builder pod env vars dict (for config/credentials)
|
|
1531
|
+
"""
|
|
1532
|
+
func.metadata.project = func.metadata.project or config.default_project
|
|
1533
|
+
self.warn_on_s3_and_ecr_permissions_conflict(func)
|
|
1534
|
+
try:
|
|
1535
|
+
req = {
|
|
1536
|
+
"function": func.to_dict(),
|
|
1537
|
+
}
|
|
1538
|
+
if builder_env:
|
|
1539
|
+
req["builder_env"] = builder_env
|
|
1540
|
+
_path = (
|
|
1541
|
+
f"projects/{func.metadata.project}/nuclio/{func.metadata.name}/deploy"
|
|
1542
|
+
)
|
|
1543
|
+
resp = self.api_call("POST", _path, json=req)
|
|
1544
|
+
except OSError as err:
|
|
1545
|
+
logger.error(f"error submitting nuclio deploy task: {err_to_str(err)}")
|
|
1546
|
+
raise OSError(f"error: cannot submit deploy, {err_to_str(err)}")
|
|
1547
|
+
|
|
1548
|
+
if not resp.ok:
|
|
1549
|
+
logger.error(f"deploy nuclio - bad response:\n{resp.text}")
|
|
1550
|
+
raise ValueError("bad nuclio deploy response")
|
|
1376
1551
|
|
|
1377
1552
|
return resp.json()
|
|
1378
1553
|
|
|
1554
|
+
def get_nuclio_deploy_status(
|
|
1555
|
+
self,
|
|
1556
|
+
func: mlrun.runtimes.RemoteRuntime,
|
|
1557
|
+
last_log_timestamp: float = 0.0,
|
|
1558
|
+
verbose: bool = False,
|
|
1559
|
+
):
|
|
1560
|
+
"""Retrieve the status of a deploy operation currently in progress.
|
|
1561
|
+
|
|
1562
|
+
:param func: Function object that is being built.
|
|
1563
|
+
:param last_log_timestamp: Last timestamp of logs that were already retrieved. Function will return only logs
|
|
1564
|
+
later than this parameter.
|
|
1565
|
+
:param verbose: Add verbose logs into the output.
|
|
1566
|
+
|
|
1567
|
+
:returns: The following parameters:
|
|
1568
|
+
|
|
1569
|
+
- Text of builder logs.
|
|
1570
|
+
- Timestamp of last log retrieved, to be used in subsequent calls to this function.
|
|
1571
|
+
"""
|
|
1572
|
+
|
|
1573
|
+
try:
|
|
1574
|
+
normalized_name = normalize_name(func.metadata.name)
|
|
1575
|
+
params = {
|
|
1576
|
+
"name": normalized_name,
|
|
1577
|
+
"project": func.metadata.project,
|
|
1578
|
+
"tag": func.metadata.tag,
|
|
1579
|
+
"last_log_timestamp": str(last_log_timestamp),
|
|
1580
|
+
"verbose": bool2str(verbose),
|
|
1581
|
+
}
|
|
1582
|
+
_path = f"projects/{func.metadata.project}/nuclio/{normalized_name}/deploy"
|
|
1583
|
+
resp = self.api_call("GET", _path, params=params)
|
|
1584
|
+
except OSError as err:
|
|
1585
|
+
logger.error(f"error getting deploy status: {err_to_str(err)}")
|
|
1586
|
+
raise OSError(f"error: cannot get deploy status, {err_to_str(err)}")
|
|
1587
|
+
|
|
1588
|
+
if not resp.ok:
|
|
1589
|
+
logger.warning(f"failed resp, {resp.text}")
|
|
1590
|
+
raise RunDBError("bad function build response")
|
|
1591
|
+
|
|
1592
|
+
if resp.headers:
|
|
1593
|
+
func.status.state = resp.headers.get("x-mlrun-function-status", "")
|
|
1594
|
+
last_log_timestamp = float(
|
|
1595
|
+
resp.headers.get("x-mlrun-last-timestamp", "0.0")
|
|
1596
|
+
)
|
|
1597
|
+
func.status.address = resp.headers.get("x-mlrun-address", "")
|
|
1598
|
+
func.status.nuclio_name = resp.headers.get("x-mlrun-name", "")
|
|
1599
|
+
func.status.internal_invocation_urls = resp.headers.get(
|
|
1600
|
+
"x-mlrun-internal-invocation-urls", ""
|
|
1601
|
+
).split(",")
|
|
1602
|
+
func.status.external_invocation_urls = resp.headers.get(
|
|
1603
|
+
"x-mlrun-external-invocation-urls", ""
|
|
1604
|
+
).split(",")
|
|
1605
|
+
func.status.container_image = resp.headers.get(
|
|
1606
|
+
"x-mlrun-container-image", ""
|
|
1607
|
+
)
|
|
1608
|
+
|
|
1609
|
+
text = ""
|
|
1610
|
+
if resp.content:
|
|
1611
|
+
text = resp.content.decode()
|
|
1612
|
+
return text, last_log_timestamp
|
|
1613
|
+
|
|
1379
1614
|
def get_builder_status(
|
|
1380
1615
|
self,
|
|
1381
1616
|
func: BaseRuntime,
|
|
@@ -1437,9 +1672,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1437
1672
|
func.status.container_image = resp.headers.get(
|
|
1438
1673
|
"x-mlrun-container-image", ""
|
|
1439
1674
|
)
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1675
|
+
|
|
1676
|
+
builder_pod = resp.headers.get("builder_pod", "")
|
|
1677
|
+
if builder_pod:
|
|
1678
|
+
func.status.build_pod = builder_pod
|
|
1679
|
+
|
|
1680
|
+
function_image = resp.headers.get("function_image", "")
|
|
1681
|
+
if function_image:
|
|
1682
|
+
func.spec.image = function_image
|
|
1443
1683
|
|
|
1444
1684
|
text = ""
|
|
1445
1685
|
if resp.content:
|
|
@@ -1502,7 +1742,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1502
1742
|
Retrieve updated information on project background tasks being executed.
|
|
1503
1743
|
If no filter is provided, will return background tasks from the last week.
|
|
1504
1744
|
|
|
1505
|
-
:param project: Project name (defaults to mlrun.
|
|
1745
|
+
:param project: Project name (defaults to mlrun.mlconf.default_project).
|
|
1506
1746
|
:param state: List only background tasks whose state is specified.
|
|
1507
1747
|
:param created_from: Filter by background task created time in ``[created_from, created_to]``.
|
|
1508
1748
|
:param created_to: Filter by background task created time in ``[created_from, created_to]``.
|
|
@@ -1615,32 +1855,31 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1615
1855
|
artifact_path=None,
|
|
1616
1856
|
ops=None,
|
|
1617
1857
|
cleanup_ttl=None,
|
|
1858
|
+
timeout=60,
|
|
1618
1859
|
):
|
|
1619
1860
|
"""Submit a KFP pipeline for execution.
|
|
1620
1861
|
|
|
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
|
-
|
|
1862
|
+
:param project: The project of the pipeline
|
|
1863
|
+
:param pipeline: Pipeline function or path to .yaml/.zip pipeline file.
|
|
1864
|
+
:param arguments: A dictionary of arguments to pass to the pipeline.
|
|
1865
|
+
:param experiment: A name to assign for the specific experiment.
|
|
1866
|
+
:param run: A name for this specific run.
|
|
1867
|
+
:param namespace: Kubernetes namespace to execute the pipeline in.
|
|
1868
|
+
:param artifact_path: A path to artifacts used by this pipeline.
|
|
1869
|
+
:param ops: Transformers to apply on all ops in the pipeline.
|
|
1870
|
+
:param cleanup_ttl: Pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
|
|
1871
|
+
workflow and all its resources are deleted)
|
|
1872
|
+
:param timeout: Timeout for the API call.
|
|
1631
1873
|
"""
|
|
1632
1874
|
|
|
1633
1875
|
if isinstance(pipeline, str):
|
|
1634
1876
|
pipe_file = pipeline
|
|
1635
1877
|
else:
|
|
1636
|
-
pipe_file =
|
|
1637
|
-
conf = new_pipe_metadata(
|
|
1878
|
+
pipe_file = compile_pipeline(
|
|
1638
1879
|
artifact_path=artifact_path,
|
|
1639
1880
|
cleanup_ttl=cleanup_ttl,
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
kfp.compiler.Compiler().compile(
|
|
1643
|
-
pipeline, pipe_file, type_check=False, pipeline_conf=conf
|
|
1881
|
+
ops=ops,
|
|
1882
|
+
pipeline=pipeline,
|
|
1644
1883
|
)
|
|
1645
1884
|
|
|
1646
1885
|
if pipe_file.endswith(".yaml"):
|
|
@@ -1669,7 +1908,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1669
1908
|
"POST",
|
|
1670
1909
|
f"projects/{project}/pipelines",
|
|
1671
1910
|
params=params,
|
|
1672
|
-
timeout=
|
|
1911
|
+
timeout=timeout,
|
|
1673
1912
|
body=data,
|
|
1674
1913
|
headers=headers,
|
|
1675
1914
|
)
|
|
@@ -1695,8 +1934,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1695
1934
|
page_token: str = "",
|
|
1696
1935
|
filter_: str = "",
|
|
1697
1936
|
format_: Union[
|
|
1698
|
-
str, mlrun.common.
|
|
1699
|
-
] = mlrun.common.
|
|
1937
|
+
str, mlrun.common.formatters.PipelineFormat
|
|
1938
|
+
] = mlrun.common.formatters.PipelineFormat.metadata_only,
|
|
1700
1939
|
page_size: int = None,
|
|
1701
1940
|
) -> mlrun.common.schemas.PipelinesOutput:
|
|
1702
1941
|
"""Retrieve a list of KFP pipelines. This function can be invoked to get all pipelines from all projects,
|
|
@@ -1742,8 +1981,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1742
1981
|
namespace: str = None,
|
|
1743
1982
|
timeout: int = 30,
|
|
1744
1983
|
format_: Union[
|
|
1745
|
-
str, mlrun.common.
|
|
1746
|
-
] = mlrun.common.
|
|
1984
|
+
str, mlrun.common.formatters.PipelineFormat
|
|
1985
|
+
] = mlrun.common.formatters.PipelineFormat.summary,
|
|
1747
1986
|
project: str = None,
|
|
1748
1987
|
):
|
|
1749
1988
|
"""Retrieve details of a specific pipeline using its run ID (as provided when the pipeline was executed)."""
|
|
@@ -2043,7 +2282,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2043
2282
|
not a full object.
|
|
2044
2283
|
Example::
|
|
2045
2284
|
|
|
2046
|
-
feature_set_update = {"status": {"processed"
|
|
2285
|
+
feature_set_update = {"status": {"processed": True}}
|
|
2047
2286
|
|
|
2048
2287
|
Will apply the field ``status.processed`` to the existing object.
|
|
2049
2288
|
:param project: Project which contains the modified object.
|
|
@@ -2385,8 +2624,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2385
2624
|
self,
|
|
2386
2625
|
owner: str = None,
|
|
2387
2626
|
format_: Union[
|
|
2388
|
-
str, mlrun.common.
|
|
2389
|
-
] = mlrun.common.
|
|
2627
|
+
str, mlrun.common.formatters.ProjectFormat
|
|
2628
|
+
] = mlrun.common.formatters.ProjectFormat.name_only,
|
|
2390
2629
|
labels: list[str] = None,
|
|
2391
2630
|
state: Union[str, mlrun.common.schemas.ProjectState] = None,
|
|
2392
2631
|
) -> list[Union[mlrun.projects.MlrunProject, str]]:
|
|
@@ -2412,7 +2651,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2412
2651
|
|
|
2413
2652
|
error_message = f"Failed listing projects, query: {params}"
|
|
2414
2653
|
response = self.api_call("GET", "projects", error_message, params=params)
|
|
2415
|
-
if format_ == mlrun.common.
|
|
2654
|
+
if format_ == mlrun.common.formatters.ProjectFormat.name_only:
|
|
2416
2655
|
# projects is just a list of strings
|
|
2417
2656
|
return response.json()["projects"]
|
|
2418
2657
|
|
|
@@ -2617,11 +2856,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2617
2856
|
:param secrets: A set of secret values to store.
|
|
2618
2857
|
Example::
|
|
2619
2858
|
|
|
2620
|
-
secrets = {
|
|
2859
|
+
secrets = {"password": "myPassw0rd", "aws_key": "111222333"}
|
|
2621
2860
|
db.create_project_secrets(
|
|
2622
2861
|
"project1",
|
|
2623
2862
|
provider=mlrun.common.schemas.SecretProviderName.kubernetes,
|
|
2624
|
-
secrets=secrets
|
|
2863
|
+
secrets=secrets,
|
|
2625
2864
|
)
|
|
2626
2865
|
"""
|
|
2627
2866
|
path = f"projects/{project}/secrets"
|
|
@@ -2917,14 +3156,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2917
3156
|
:param labels: A list of labels to filter by. Label filters work by either filtering a specific value of a
|
|
2918
3157
|
label (i.e. list("key=value")) or by looking for the existence of a given key (i.e. "key")
|
|
2919
3158
|
: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.
|
|
3159
|
+
:param start: The start time of the metrics. Can be represented by a string containing an RFC 3339 time, a
|
|
3160
|
+
Unix timestamp in milliseconds, a relative time (`'now'` or `'now-[0-9]+[mhd]'`, where
|
|
3161
|
+
`m` = minutes, `h` = hours, `'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
|
|
3162
|
+
:param end: The end time of the metrics. Can be represented by a string containing an RFC 3339 time, a
|
|
3163
|
+
Unix timestamp in milliseconds, a relative time (`'now'` or `'now-[0-9]+[mhd]'`, where
|
|
3164
|
+
`m` = minutes, `h` = hours, `'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
|
|
2928
3165
|
:param top_level: if true will return only routers and endpoint that are NOT children of any router
|
|
2929
3166
|
:param uids: if passed will return a list `ModelEndpoint` object with uid in uids
|
|
2930
3167
|
"""
|
|
@@ -2973,13 +3210,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2973
3210
|
:param project: The name of the project
|
|
2974
3211
|
:param endpoint_id: The unique id of the model endpoint.
|
|
2975
3212
|
: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.
|
|
3213
|
+
RFC 3339 time, a Unix timestamp in milliseconds, a relative time
|
|
3214
|
+
(`'now'` or `'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours,
|
|
3215
|
+
`'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
|
|
2979
3216
|
: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.
|
|
3217
|
+
RFC 3339 time, a Unix timestamp in milliseconds, a relative time
|
|
3218
|
+
(`'now'` or `'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours,
|
|
3219
|
+
`'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
|
|
2983
3220
|
:param metrics: A list of metrics to return for the model endpoint. There are pre-defined
|
|
2984
3221
|
metrics for model endpoints such as predictions_per_second and
|
|
2985
3222
|
latency_avg_5m but also custom metrics defined by the user. Please note that
|
|
@@ -3049,41 +3286,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3049
3286
|
params=attributes,
|
|
3050
3287
|
)
|
|
3051
3288
|
|
|
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
3289
|
def update_model_monitoring_controller(
|
|
3082
3290
|
self,
|
|
3083
3291
|
project: str,
|
|
3084
3292
|
base_period: int = 10,
|
|
3085
3293
|
image: str = "mlrun/mlrun",
|
|
3086
|
-
):
|
|
3294
|
+
) -> None:
|
|
3087
3295
|
"""
|
|
3088
3296
|
Redeploy model monitoring application controller function.
|
|
3089
3297
|
|
|
@@ -3093,20 +3301,22 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3093
3301
|
:param image: The image of the model monitoring controller function.
|
|
3094
3302
|
By default, the image is mlrun/mlrun.
|
|
3095
3303
|
"""
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
"
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3304
|
+
self.api_call(
|
|
3305
|
+
method=mlrun.common.types.HTTPMethod.POST,
|
|
3306
|
+
path=f"projects/{project}/model-monitoring/model-monitoring-controller",
|
|
3307
|
+
params={
|
|
3308
|
+
"base_period": base_period,
|
|
3309
|
+
"image": image,
|
|
3310
|
+
},
|
|
3311
|
+
)
|
|
3103
3312
|
|
|
3104
3313
|
def enable_model_monitoring(
|
|
3105
3314
|
self,
|
|
3106
3315
|
project: str,
|
|
3107
3316
|
base_period: int = 10,
|
|
3108
3317
|
image: str = "mlrun/mlrun",
|
|
3109
|
-
|
|
3318
|
+
deploy_histogram_data_drift_app: bool = True,
|
|
3319
|
+
) -> None:
|
|
3110
3320
|
"""
|
|
3111
3321
|
Deploy model monitoring application controller, writer and stream functions.
|
|
3112
3322
|
While the main goal of the controller function is to handle the monitoring processing and triggering
|
|
@@ -3115,21 +3325,38 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3115
3325
|
The stream function goal is to monitor the log of the data stream. It is triggered when a new log entry
|
|
3116
3326
|
is detected. It processes the new events into statistics that are then written to statistics databases.
|
|
3117
3327
|
|
|
3328
|
+
:param project: Project name.
|
|
3329
|
+
:param base_period: The time period in minutes in which the model monitoring controller function
|
|
3330
|
+
triggers. By default, the base period is 10 minutes.
|
|
3331
|
+
:param image: The image of the model monitoring controller, writer & monitoring
|
|
3332
|
+
stream functions, which are real time nuclio functions.
|
|
3333
|
+
By default, the image is mlrun/mlrun.
|
|
3334
|
+
:param deploy_histogram_data_drift_app: If true, deploy the default histogram-based data drift application.
|
|
3335
|
+
"""
|
|
3336
|
+
self.api_call(
|
|
3337
|
+
method=mlrun.common.types.HTTPMethod.POST,
|
|
3338
|
+
path=f"projects/{project}/model-monitoring/enable-model-monitoring",
|
|
3339
|
+
params={
|
|
3340
|
+
"base_period": base_period,
|
|
3341
|
+
"image": image,
|
|
3342
|
+
"deploy_histogram_data_drift_app": deploy_histogram_data_drift_app,
|
|
3343
|
+
},
|
|
3344
|
+
)
|
|
3118
3345
|
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
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.
|
|
3346
|
+
def deploy_histogram_data_drift_app(
|
|
3347
|
+
self, project: str, image: str = "mlrun/mlrun"
|
|
3348
|
+
) -> None:
|
|
3125
3349
|
"""
|
|
3350
|
+
Deploy the histogram data drift application.
|
|
3126
3351
|
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3352
|
+
:param project: Project name.
|
|
3353
|
+
:param image: The image on which the application will run.
|
|
3354
|
+
"""
|
|
3355
|
+
self.api_call(
|
|
3356
|
+
method=mlrun.common.types.HTTPMethod.POST,
|
|
3357
|
+
path=f"projects/{project}/model-monitoring/deploy-histogram-data-drift-app",
|
|
3358
|
+
params={"image": image},
|
|
3359
|
+
)
|
|
3133
3360
|
|
|
3134
3361
|
def create_hub_source(
|
|
3135
3362
|
self, source: Union[dict, mlrun.common.schemas.IndexedHubSource]
|
|
@@ -3160,8 +3387,10 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3160
3387
|
metadata=mlrun.common.schemas.HubObjectMetadata(
|
|
3161
3388
|
name="priv", description="a private source"
|
|
3162
3389
|
),
|
|
3163
|
-
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3164
|
-
|
|
3390
|
+
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3391
|
+
path="/local/path/to/source", channel="development"
|
|
3392
|
+
),
|
|
3393
|
+
),
|
|
3165
3394
|
)
|
|
3166
3395
|
db.create_hub_source(private_source)
|
|
3167
3396
|
|
|
@@ -3175,9 +3404,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3175
3404
|
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3176
3405
|
path="/local/path/to/source/2",
|
|
3177
3406
|
channel="development",
|
|
3178
|
-
credentials={...}
|
|
3179
|
-
)
|
|
3180
|
-
)
|
|
3407
|
+
credentials={...},
|
|
3408
|
+
),
|
|
3409
|
+
),
|
|
3181
3410
|
)
|
|
3182
3411
|
db.create_hub_source(another_source)
|
|
3183
3412
|
|
|
@@ -3369,20 +3598,72 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3369
3598
|
body=dict_to_json(authorization_verification_input.dict()),
|
|
3370
3599
|
)
|
|
3371
3600
|
|
|
3372
|
-
def list_api_gateways(self, project=None):
|
|
3601
|
+
def list_api_gateways(self, project=None) -> mlrun.common.schemas.APIGatewaysOutput:
|
|
3373
3602
|
"""
|
|
3374
3603
|
Returns a list of Nuclio api gateways
|
|
3375
|
-
:param project: optional str parameter to filter by project, if not passed, default
|
|
3604
|
+
:param project: optional str parameter to filter by project, if not passed, default project value is taken
|
|
3376
3605
|
|
|
3377
|
-
:return:
|
|
3378
|
-
(json example is here
|
|
3379
|
-
https://github.com/nuclio/nuclio/blob/development/docs/reference/api/README.md#listing-all-api-gateways)
|
|
3606
|
+
:return: :py:class:`~mlrun.common.schemas.APIGateways`.
|
|
3380
3607
|
"""
|
|
3381
3608
|
project = project or config.default_project
|
|
3382
3609
|
error = "list api gateways"
|
|
3383
|
-
endpoint_path = f"projects/{project}/
|
|
3384
|
-
|
|
3385
|
-
return
|
|
3610
|
+
endpoint_path = f"projects/{project}/api-gateways"
|
|
3611
|
+
response = self.api_call("GET", endpoint_path, error)
|
|
3612
|
+
return mlrun.common.schemas.APIGatewaysOutput(**response.json())
|
|
3613
|
+
|
|
3614
|
+
def get_api_gateway(self, name, project=None) -> mlrun.common.schemas.APIGateway:
|
|
3615
|
+
"""
|
|
3616
|
+
Returns an API gateway
|
|
3617
|
+
:param name: API gateway name
|
|
3618
|
+
:param project: optional str parameter to filter by project, if not passed, default project value is taken
|
|
3619
|
+
|
|
3620
|
+
:return: :py:class:`~mlrun.common.schemas.APIGateway`.
|
|
3621
|
+
"""
|
|
3622
|
+
project = project or config.default_project
|
|
3623
|
+
error = "get api gateway"
|
|
3624
|
+
endpoint_path = f"projects/{project}/api-gateways/{name}"
|
|
3625
|
+
response = self.api_call("GET", endpoint_path, error)
|
|
3626
|
+
return mlrun.common.schemas.APIGateway(**response.json())
|
|
3627
|
+
|
|
3628
|
+
def delete_api_gateway(self, name, project=None):
|
|
3629
|
+
"""
|
|
3630
|
+
Deletes an API gateway
|
|
3631
|
+
:param name: API gateway name
|
|
3632
|
+
:param project: Project name
|
|
3633
|
+
"""
|
|
3634
|
+
project = project or config.default_project
|
|
3635
|
+
error = "delete api gateway"
|
|
3636
|
+
endpoint_path = f"projects/{project}/api-gateways/{name}"
|
|
3637
|
+
self.api_call("DELETE", endpoint_path, error)
|
|
3638
|
+
|
|
3639
|
+
def store_api_gateway(
|
|
3640
|
+
self,
|
|
3641
|
+
api_gateway: Union[
|
|
3642
|
+
mlrun.common.schemas.APIGateway,
|
|
3643
|
+
mlrun.runtimes.nuclio.api_gateway.APIGateway,
|
|
3644
|
+
],
|
|
3645
|
+
project: Optional[str] = None,
|
|
3646
|
+
) -> mlrun.common.schemas.APIGateway:
|
|
3647
|
+
"""
|
|
3648
|
+
Stores an API Gateway.
|
|
3649
|
+
:param api_gateway :py:class:`~mlrun.runtimes.nuclio.APIGateway`
|
|
3650
|
+
or :py:class:`~mlrun.common.schemas.APIGateway`: API Gateway entity.
|
|
3651
|
+
:param project: project name. Mandatory if api_gateway is mlrun.common.schemas.APIGateway.
|
|
3652
|
+
|
|
3653
|
+
:return: :py:class:`~mlrun.common.schemas.APIGateway`.
|
|
3654
|
+
"""
|
|
3655
|
+
|
|
3656
|
+
if isinstance(api_gateway, mlrun.runtimes.nuclio.api_gateway.APIGateway):
|
|
3657
|
+
api_gateway = api_gateway.to_scheme()
|
|
3658
|
+
endpoint_path = f"projects/{project}/api-gateways/{api_gateway.metadata.name}"
|
|
3659
|
+
error = "store api gateways"
|
|
3660
|
+
response = self.api_call(
|
|
3661
|
+
"PUT",
|
|
3662
|
+
endpoint_path,
|
|
3663
|
+
error,
|
|
3664
|
+
json=api_gateway.dict(exclude_none=True),
|
|
3665
|
+
)
|
|
3666
|
+
return mlrun.common.schemas.APIGateway(**response.json())
|
|
3386
3667
|
|
|
3387
3668
|
def trigger_migrations(self) -> Optional[mlrun.common.schemas.BackgroundTask]:
|
|
3388
3669
|
"""Trigger migrations (will do nothing if no migrations are needed) and wait for them to finish if actually
|
|
@@ -3465,6 +3746,16 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3465
3746
|
"""
|
|
3466
3747
|
pass
|
|
3467
3748
|
|
|
3749
|
+
def store_alert_notifications(
|
|
3750
|
+
self,
|
|
3751
|
+
session,
|
|
3752
|
+
notification_objects: list[mlrun.model.Notification],
|
|
3753
|
+
alert_id: str,
|
|
3754
|
+
project: str,
|
|
3755
|
+
mask_params: bool = True,
|
|
3756
|
+
):
|
|
3757
|
+
pass
|
|
3758
|
+
|
|
3468
3759
|
def submit_workflow(
|
|
3469
3760
|
self,
|
|
3470
3761
|
project: str,
|
|
@@ -3656,6 +3947,145 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3656
3947
|
|
|
3657
3948
|
self.api_call(method="PUT", path=_path, json=profile.dict())
|
|
3658
3949
|
|
|
3950
|
+
@staticmethod
|
|
3951
|
+
def warn_on_s3_and_ecr_permissions_conflict(func):
|
|
3952
|
+
is_s3_source = func.spec.build.source and func.spec.build.source.startswith(
|
|
3953
|
+
"s3://"
|
|
3954
|
+
)
|
|
3955
|
+
is_ecr_image = mlrun.utils.is_ecr_url(config.httpdb.builder.docker_registry)
|
|
3956
|
+
if not func.spec.build.load_source_on_run and is_s3_source and is_ecr_image:
|
|
3957
|
+
logger.warning(
|
|
3958
|
+
"Building a function image to ECR and loading an S3 source to the image may require conflicting access "
|
|
3959
|
+
"keys. Only the permissions granted to the platform's configured secret will take affect "
|
|
3960
|
+
"(see mlrun.mlconf.httpdb.builder.docker_registry_secret). "
|
|
3961
|
+
"In case the permissions are limited to ECR scope, you may use pull_at_runtime=True instead",
|
|
3962
|
+
source=func.spec.build.source,
|
|
3963
|
+
load_source_on_run=func.spec.build.load_source_on_run,
|
|
3964
|
+
default_docker_registry=config.httpdb.builder.docker_registry,
|
|
3965
|
+
)
|
|
3966
|
+
|
|
3967
|
+
def generate_event(
|
|
3968
|
+
self, name: str, event_data: Union[dict, mlrun.common.schemas.Event], project=""
|
|
3969
|
+
):
|
|
3970
|
+
"""
|
|
3971
|
+
Generate an event.
|
|
3972
|
+
:param name: The name of the event.
|
|
3973
|
+
:param event_data: The data of the event.
|
|
3974
|
+
:param project: The project that the event belongs to.
|
|
3975
|
+
"""
|
|
3976
|
+
project = project or config.default_project
|
|
3977
|
+
endpoint_path = f"projects/{project}/events/{name}"
|
|
3978
|
+
error_message = f"post event {project}/events/{name}"
|
|
3979
|
+
if isinstance(event_data, mlrun.common.schemas.Event):
|
|
3980
|
+
event_data = event_data.dict()
|
|
3981
|
+
self.api_call(
|
|
3982
|
+
"POST", endpoint_path, error_message, body=dict_to_json(event_data)
|
|
3983
|
+
)
|
|
3984
|
+
|
|
3985
|
+
def store_alert_config(
|
|
3986
|
+
self,
|
|
3987
|
+
alert_name: str,
|
|
3988
|
+
alert_data: Union[dict, AlertConfig],
|
|
3989
|
+
project="",
|
|
3990
|
+
) -> AlertConfig:
|
|
3991
|
+
"""
|
|
3992
|
+
Create/modify an alert.
|
|
3993
|
+
:param alert_name: The name of the alert.
|
|
3994
|
+
:param alert_data: The data of the alert.
|
|
3995
|
+
:param project: the project that the alert belongs to.
|
|
3996
|
+
:return: The created/modified alert.
|
|
3997
|
+
"""
|
|
3998
|
+
project = project or config.default_project
|
|
3999
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
4000
|
+
error_message = f"put alert {project}/alerts/{alert_name}"
|
|
4001
|
+
alert_instance = (
|
|
4002
|
+
alert_data
|
|
4003
|
+
if isinstance(alert_data, AlertConfig)
|
|
4004
|
+
else AlertConfig.from_dict(alert_data)
|
|
4005
|
+
)
|
|
4006
|
+
alert_instance.validate_required_fields()
|
|
4007
|
+
|
|
4008
|
+
alert_data = alert_instance.to_dict()
|
|
4009
|
+
body = _as_json(alert_data)
|
|
4010
|
+
response = self.api_call("PUT", endpoint_path, error_message, body=body)
|
|
4011
|
+
return AlertConfig.from_dict(response.json())
|
|
4012
|
+
|
|
4013
|
+
def get_alert_config(self, alert_name: str, project="") -> AlertConfig:
|
|
4014
|
+
"""
|
|
4015
|
+
Retrieve an alert.
|
|
4016
|
+
:param alert_name: The name of the alert to retrieve.
|
|
4017
|
+
:param project: The project that the alert belongs to.
|
|
4018
|
+
:return: The alert object.
|
|
4019
|
+
"""
|
|
4020
|
+
project = project or config.default_project
|
|
4021
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
4022
|
+
error_message = f"get alert {project}/alerts/{alert_name}"
|
|
4023
|
+
response = self.api_call("GET", endpoint_path, error_message)
|
|
4024
|
+
return AlertConfig.from_dict(response.json())
|
|
4025
|
+
|
|
4026
|
+
def list_alerts_configs(self, project="") -> list[AlertConfig]:
|
|
4027
|
+
"""
|
|
4028
|
+
Retrieve list of alerts of a project.
|
|
4029
|
+
:param project: The project name.
|
|
4030
|
+
:return: All the alerts objects of the project.
|
|
4031
|
+
"""
|
|
4032
|
+
project = project or config.default_project
|
|
4033
|
+
endpoint_path = f"projects/{project}/alerts"
|
|
4034
|
+
error_message = f"get alerts {project}/alerts"
|
|
4035
|
+
response = self.api_call("GET", endpoint_path, error_message).json()
|
|
4036
|
+
results = []
|
|
4037
|
+
for item in response:
|
|
4038
|
+
results.append(AlertConfig(**item))
|
|
4039
|
+
return results
|
|
4040
|
+
|
|
4041
|
+
def delete_alert_config(self, alert_name: str, project=""):
|
|
4042
|
+
"""
|
|
4043
|
+
Delete an alert.
|
|
4044
|
+
:param alert_name: The name of the alert to delete.
|
|
4045
|
+
:param project: The project that the alert belongs to.
|
|
4046
|
+
"""
|
|
4047
|
+
project = project or config.default_project
|
|
4048
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
4049
|
+
error_message = f"delete alert {project}/alerts/{alert_name}"
|
|
4050
|
+
self.api_call("DELETE", endpoint_path, error_message)
|
|
4051
|
+
|
|
4052
|
+
def reset_alert_config(self, alert_name: str, project=""):
|
|
4053
|
+
"""
|
|
4054
|
+
Reset an alert.
|
|
4055
|
+
:param alert_name: The name of the alert to reset.
|
|
4056
|
+
:param project: The project that the alert belongs to.
|
|
4057
|
+
"""
|
|
4058
|
+
project = project or config.default_project
|
|
4059
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}/reset"
|
|
4060
|
+
error_message = f"post alert {project}/alerts/{alert_name}/reset"
|
|
4061
|
+
self.api_call("POST", endpoint_path, error_message)
|
|
4062
|
+
|
|
4063
|
+
def get_alert_template(
|
|
4064
|
+
self, template_name: str
|
|
4065
|
+
) -> mlrun.common.schemas.AlertTemplate:
|
|
4066
|
+
"""
|
|
4067
|
+
Retrieve a specific alert template.
|
|
4068
|
+
:param template_name: The name of the template to retrieve.
|
|
4069
|
+
:return: The template object.
|
|
4070
|
+
"""
|
|
4071
|
+
endpoint_path = f"alert-templates/{template_name}"
|
|
4072
|
+
error_message = f"get template alert-templates/{template_name}"
|
|
4073
|
+
response = self.api_call("GET", endpoint_path, error_message)
|
|
4074
|
+
return mlrun.common.schemas.AlertTemplate(**response.json())
|
|
4075
|
+
|
|
4076
|
+
def list_alert_templates(self) -> list[mlrun.common.schemas.AlertTemplate]:
|
|
4077
|
+
"""
|
|
4078
|
+
Retrieve list of all alert templates.
|
|
4079
|
+
:return: All the alert template objects in the database.
|
|
4080
|
+
"""
|
|
4081
|
+
endpoint_path = "alert-templates"
|
|
4082
|
+
error_message = "get templates /alert-templates"
|
|
4083
|
+
response = self.api_call("GET", endpoint_path, error_message).json()
|
|
4084
|
+
results = []
|
|
4085
|
+
for item in response:
|
|
4086
|
+
results.append(mlrun.common.schemas.AlertTemplate(**item))
|
|
4087
|
+
return results
|
|
4088
|
+
|
|
3659
4089
|
|
|
3660
4090
|
def _as_json(obj):
|
|
3661
4091
|
fn = getattr(obj, "to_json", None)
|