mlrun 1.7.0rc7__py3-none-any.whl → 1.7.0rc11__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 +1 -0
- mlrun/__main__.py +2 -0
- mlrun/artifacts/model.py +29 -25
- mlrun/common/schemas/__init__.py +4 -0
- mlrun/common/schemas/alert.py +122 -0
- mlrun/common/schemas/api_gateway.py +8 -1
- mlrun/common/schemas/auth.py +4 -0
- mlrun/common/schemas/client_spec.py +1 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/constants.py +4 -2
- mlrun/{datastore/helpers.py → common/schemas/pagination.py} +11 -3
- mlrun/common/schemas/project.py +15 -10
- mlrun/config.py +35 -13
- mlrun/datastore/__init__.py +3 -7
- mlrun/datastore/base.py +6 -5
- mlrun/datastore/datastore_profile.py +19 -1
- mlrun/datastore/snowflake_utils.py +43 -0
- mlrun/datastore/sources.py +18 -30
- mlrun/datastore/targets.py +140 -12
- mlrun/datastore/utils.py +10 -5
- mlrun/datastore/v3io.py +27 -50
- mlrun/db/base.py +88 -2
- mlrun/db/httpdb.py +314 -41
- mlrun/db/nopdb.py +142 -0
- mlrun/execution.py +21 -14
- mlrun/feature_store/api.py +9 -5
- mlrun/feature_store/feature_set.py +39 -23
- mlrun/feature_store/feature_vector.py +2 -1
- mlrun/feature_store/retrieval/spark_merger.py +27 -23
- mlrun/feature_store/steps.py +30 -19
- mlrun/features.py +4 -13
- 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/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/tf_keras/__init__.py +1 -1
- 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/kfpops.py +2 -5
- mlrun/launcher/base.py +1 -1
- mlrun/launcher/client.py +2 -2
- mlrun/model.py +2 -2
- mlrun/model_monitoring/application.py +11 -2
- mlrun/model_monitoring/applications/histogram_data_drift.py +3 -3
- mlrun/model_monitoring/controller.py +2 -3
- mlrun/model_monitoring/helpers.py +3 -1
- mlrun/model_monitoring/stream_processing.py +0 -1
- mlrun/model_monitoring/writer.py +32 -0
- mlrun/package/packagers_manager.py +1 -0
- mlrun/platforms/__init__.py +1 -1
- mlrun/platforms/other.py +1 -1
- mlrun/projects/operations.py +11 -4
- mlrun/projects/pipelines.py +1 -1
- mlrun/projects/project.py +180 -73
- mlrun/run.py +77 -41
- mlrun/runtimes/__init__.py +16 -0
- mlrun/runtimes/base.py +4 -1
- mlrun/runtimes/kubejob.py +26 -121
- mlrun/runtimes/mpijob/abstract.py +8 -8
- mlrun/runtimes/nuclio/api_gateway.py +58 -8
- mlrun/runtimes/nuclio/application/application.py +79 -1
- mlrun/runtimes/nuclio/application/reverse_proxy.go +9 -1
- mlrun/runtimes/nuclio/function.py +20 -13
- mlrun/runtimes/nuclio/serving.py +11 -10
- mlrun/runtimes/pod.py +148 -3
- mlrun/runtimes/utils.py +0 -28
- mlrun/secrets.py +6 -2
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +7 -4
- mlrun/serving/server.py +1 -1
- mlrun/serving/states.py +14 -38
- mlrun/serving/v2_serving.py +8 -7
- mlrun/utils/helpers.py +1 -1
- mlrun/utils/http.py +1 -1
- 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 +41 -13
- mlrun/utils/notifications/notification/webhook.py +11 -1
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/METADATA +15 -15
- {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/RECORD +91 -89
- {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/WHEEL +0 -0
- {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/top_level.txt +0 -0
mlrun/db/base.py
CHANGED
|
@@ -634,6 +634,58 @@ class RunDBInterface(ABC):
|
|
|
634
634
|
def delete_api_gateway(self, name, project=None):
|
|
635
635
|
pass
|
|
636
636
|
|
|
637
|
+
@abstractmethod
|
|
638
|
+
def remote_builder(
|
|
639
|
+
self,
|
|
640
|
+
func: "mlrun.runtimes.BaseRuntime",
|
|
641
|
+
with_mlrun: bool,
|
|
642
|
+
mlrun_version_specifier: Optional[str] = None,
|
|
643
|
+
skip_deployed: bool = False,
|
|
644
|
+
builder_env: Optional[dict] = None,
|
|
645
|
+
force_build: bool = False,
|
|
646
|
+
):
|
|
647
|
+
pass
|
|
648
|
+
|
|
649
|
+
@abstractmethod
|
|
650
|
+
def deploy_nuclio_function(
|
|
651
|
+
self,
|
|
652
|
+
func: "mlrun.runtimes.RemoteRuntime",
|
|
653
|
+
builder_env: Optional[dict] = None,
|
|
654
|
+
):
|
|
655
|
+
pass
|
|
656
|
+
|
|
657
|
+
@abstractmethod
|
|
658
|
+
def generate_event(
|
|
659
|
+
self, name: str, event_data: Union[dict, mlrun.common.schemas.Event], project=""
|
|
660
|
+
):
|
|
661
|
+
pass
|
|
662
|
+
|
|
663
|
+
@abstractmethod
|
|
664
|
+
def store_alert_config(
|
|
665
|
+
self,
|
|
666
|
+
alert_name: str,
|
|
667
|
+
alert_data: Union[dict, mlrun.common.schemas.AlertConfig],
|
|
668
|
+
project="",
|
|
669
|
+
):
|
|
670
|
+
pass
|
|
671
|
+
|
|
672
|
+
@abstractmethod
|
|
673
|
+
def get_alert_config(self, alert_name: str, project=""):
|
|
674
|
+
pass
|
|
675
|
+
|
|
676
|
+
@abstractmethod
|
|
677
|
+
def list_alerts_configs(self, project=""):
|
|
678
|
+
pass
|
|
679
|
+
|
|
680
|
+
@abstractmethod
|
|
681
|
+
def delete_alert_config(self, alert_name: str, project=""):
|
|
682
|
+
pass
|
|
683
|
+
|
|
684
|
+
@abstractmethod
|
|
685
|
+
def reset_alert_config(self, alert_name: str, project=""):
|
|
686
|
+
pass
|
|
687
|
+
|
|
688
|
+
@abstractmethod
|
|
637
689
|
def get_builder_status(
|
|
638
690
|
self,
|
|
639
691
|
func: "mlrun.runtimes.BaseRuntime",
|
|
@@ -644,6 +696,16 @@ class RunDBInterface(ABC):
|
|
|
644
696
|
):
|
|
645
697
|
pass
|
|
646
698
|
|
|
699
|
+
@abstractmethod
|
|
700
|
+
def get_nuclio_deploy_status(
|
|
701
|
+
self,
|
|
702
|
+
func: "mlrun.runtimes.RemoteRuntime",
|
|
703
|
+
last_log_timestamp: float = 0.0,
|
|
704
|
+
verbose: bool = False,
|
|
705
|
+
):
|
|
706
|
+
pass
|
|
707
|
+
|
|
708
|
+
@abstractmethod
|
|
647
709
|
def set_run_notifications(
|
|
648
710
|
self,
|
|
649
711
|
project: str,
|
|
@@ -652,6 +714,7 @@ class RunDBInterface(ABC):
|
|
|
652
714
|
):
|
|
653
715
|
pass
|
|
654
716
|
|
|
717
|
+
@abstractmethod
|
|
655
718
|
def store_run_notifications(
|
|
656
719
|
self,
|
|
657
720
|
notification_objects: list[mlrun.model.Notification],
|
|
@@ -661,40 +724,60 @@ class RunDBInterface(ABC):
|
|
|
661
724
|
):
|
|
662
725
|
pass
|
|
663
726
|
|
|
727
|
+
@abstractmethod
|
|
664
728
|
def get_log_size(self, uid, project=""):
|
|
665
729
|
pass
|
|
666
730
|
|
|
731
|
+
@abstractmethod
|
|
732
|
+
def store_alert_notifications(
|
|
733
|
+
self,
|
|
734
|
+
session,
|
|
735
|
+
notification_objects: list[mlrun.model.Notification],
|
|
736
|
+
alert_id: str,
|
|
737
|
+
project: str,
|
|
738
|
+
mask_params: bool = True,
|
|
739
|
+
):
|
|
740
|
+
pass
|
|
741
|
+
|
|
742
|
+
@abstractmethod
|
|
667
743
|
def watch_log(self, uid, project="", watch=True, offset=0):
|
|
668
744
|
pass
|
|
669
745
|
|
|
746
|
+
@abstractmethod
|
|
670
747
|
def get_datastore_profile(
|
|
671
748
|
self, name: str, project: str
|
|
672
749
|
) -> Optional[mlrun.common.schemas.DatastoreProfile]:
|
|
673
750
|
pass
|
|
674
751
|
|
|
752
|
+
@abstractmethod
|
|
675
753
|
def delete_datastore_profile(
|
|
676
754
|
self, name: str, project: str
|
|
677
755
|
) -> mlrun.common.schemas.DatastoreProfile:
|
|
678
756
|
pass
|
|
679
757
|
|
|
758
|
+
@abstractmethod
|
|
680
759
|
def list_datastore_profiles(
|
|
681
760
|
self, project: str
|
|
682
761
|
) -> list[mlrun.common.schemas.DatastoreProfile]:
|
|
683
762
|
pass
|
|
684
763
|
|
|
764
|
+
@abstractmethod
|
|
685
765
|
def store_datastore_profile(
|
|
686
766
|
self, profile: mlrun.common.schemas.DatastoreProfile, project: str
|
|
687
767
|
):
|
|
688
768
|
pass
|
|
689
769
|
|
|
770
|
+
@abstractmethod
|
|
690
771
|
def function_status(self, project, name, kind, selector):
|
|
691
772
|
pass
|
|
692
773
|
|
|
774
|
+
@abstractmethod
|
|
693
775
|
def start_function(
|
|
694
776
|
self, func_url: str = None, function: "mlrun.runtimes.BaseRuntime" = None
|
|
695
777
|
):
|
|
696
778
|
pass
|
|
697
779
|
|
|
780
|
+
@abstractmethod
|
|
698
781
|
def submit_workflow(
|
|
699
782
|
self,
|
|
700
783
|
project: str,
|
|
@@ -713,6 +796,7 @@ class RunDBInterface(ABC):
|
|
|
713
796
|
) -> "mlrun.common.schemas.WorkflowResponse":
|
|
714
797
|
pass
|
|
715
798
|
|
|
799
|
+
@abstractmethod
|
|
716
800
|
def update_model_monitoring_controller(
|
|
717
801
|
self,
|
|
718
802
|
project: str,
|
|
@@ -721,6 +805,7 @@ class RunDBInterface(ABC):
|
|
|
721
805
|
):
|
|
722
806
|
pass
|
|
723
807
|
|
|
808
|
+
@abstractmethod
|
|
724
809
|
def enable_model_monitoring(
|
|
725
810
|
self,
|
|
726
811
|
project: str,
|
|
@@ -728,9 +813,10 @@ class RunDBInterface(ABC):
|
|
|
728
813
|
image: str = "mlrun/mlrun",
|
|
729
814
|
deploy_histogram_data_drift_app: bool = True,
|
|
730
815
|
) -> None:
|
|
731
|
-
|
|
816
|
+
pass
|
|
732
817
|
|
|
818
|
+
@abstractmethod
|
|
733
819
|
def deploy_histogram_data_drift_app(
|
|
734
820
|
self, project: str, image: str = "mlrun/mlrun"
|
|
735
821
|
) -> None:
|
|
736
|
-
|
|
822
|
+
pass
|
mlrun/db/httpdb.py
CHANGED
|
@@ -20,6 +20,7 @@ import time
|
|
|
20
20
|
import traceback
|
|
21
21
|
import typing
|
|
22
22
|
import warnings
|
|
23
|
+
from copy import deepcopy
|
|
23
24
|
from datetime import datetime, timedelta
|
|
24
25
|
from os import path, remove
|
|
25
26
|
from typing import Optional, Union
|
|
@@ -282,6 +283,68 @@ class HTTPRunDB(RunDBInterface):
|
|
|
282
283
|
|
|
283
284
|
return response
|
|
284
285
|
|
|
286
|
+
def paginated_api_call(
|
|
287
|
+
self,
|
|
288
|
+
method,
|
|
289
|
+
path,
|
|
290
|
+
error=None,
|
|
291
|
+
params=None,
|
|
292
|
+
body=None,
|
|
293
|
+
json=None,
|
|
294
|
+
headers=None,
|
|
295
|
+
timeout=45,
|
|
296
|
+
version=None,
|
|
297
|
+
) -> typing.Generator[requests.Response, None, None]:
|
|
298
|
+
"""
|
|
299
|
+
Calls the api with pagination, yielding each page of the response
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
def _api_call(_params):
|
|
303
|
+
return self.api_call(
|
|
304
|
+
method=method,
|
|
305
|
+
path=path,
|
|
306
|
+
error=error,
|
|
307
|
+
params=_params,
|
|
308
|
+
body=body,
|
|
309
|
+
json=json,
|
|
310
|
+
headers=headers,
|
|
311
|
+
timeout=timeout,
|
|
312
|
+
version=version,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
first_page_params = deepcopy(params) or {}
|
|
316
|
+
first_page_params["page"] = 1
|
|
317
|
+
first_page_params["page-size"] = config.httpdb.pagination.default_page_size
|
|
318
|
+
response = _api_call(first_page_params)
|
|
319
|
+
page_token = response.json().get("pagination", {}).get("page-token")
|
|
320
|
+
if not page_token:
|
|
321
|
+
yield response
|
|
322
|
+
return
|
|
323
|
+
|
|
324
|
+
params_with_page_token = deepcopy(params) or {}
|
|
325
|
+
params_with_page_token["page-token"] = page_token
|
|
326
|
+
while page_token:
|
|
327
|
+
yield response
|
|
328
|
+
try:
|
|
329
|
+
response = _api_call(params_with_page_token)
|
|
330
|
+
except mlrun.errors.MLRunNotFoundError:
|
|
331
|
+
# pagination token expired
|
|
332
|
+
break
|
|
333
|
+
|
|
334
|
+
page_token = response.json().get("pagination", {}).get("page-token", None)
|
|
335
|
+
|
|
336
|
+
@staticmethod
|
|
337
|
+
def process_paginated_responses(
|
|
338
|
+
responses: typing.Generator[requests.Response, None, None], key: str = "data"
|
|
339
|
+
) -> list[typing.Any]:
|
|
340
|
+
"""
|
|
341
|
+
Processes the paginated responses and returns the combined data
|
|
342
|
+
"""
|
|
343
|
+
data = []
|
|
344
|
+
for response in responses:
|
|
345
|
+
data.extend(response.json().get(key, []))
|
|
346
|
+
return data
|
|
347
|
+
|
|
285
348
|
def _init_session(self, retry_on_post: bool = False):
|
|
286
349
|
return mlrun.utils.HTTPSessionWithRetry(
|
|
287
350
|
retry_on_exception=config.httpdb.retry_api_call_on_exception
|
|
@@ -314,7 +377,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
314
377
|
|
|
315
378
|
For example::
|
|
316
379
|
|
|
317
|
-
config.dbpath = config.dbpath or
|
|
380
|
+
config.dbpath = config.dbpath or "http://mlrun-api:8080"
|
|
318
381
|
db = get_run_db().connect()
|
|
319
382
|
"""
|
|
320
383
|
# hack to allow unit tests to instantiate HTTPRunDB without a real server behind
|
|
@@ -466,6 +529,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
466
529
|
server_cfg.get("feature_store_default_targets")
|
|
467
530
|
or config.feature_store.default_targets
|
|
468
531
|
)
|
|
532
|
+
config.alerts.mode = server_cfg.get("alerts_mode") or config.alerts.mode
|
|
469
533
|
|
|
470
534
|
except Exception as exc:
|
|
471
535
|
logger.warning(
|
|
@@ -698,9 +762,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
698
762
|
|
|
699
763
|
Example::
|
|
700
764
|
|
|
701
|
-
runs = db.list_runs(
|
|
765
|
+
runs = db.list_runs(
|
|
766
|
+
name="download", project="iris", labels=["owner=admin", "kind=job"]
|
|
767
|
+
)
|
|
702
768
|
# If running in Jupyter, can use the .show() function to display the results
|
|
703
|
-
db.list_runs(name=
|
|
769
|
+
db.list_runs(name="", project=project_name).show()
|
|
704
770
|
|
|
705
771
|
|
|
706
772
|
:param name: Name of the run to retrieve.
|
|
@@ -791,15 +857,15 @@ class HTTPRunDB(RunDBInterface):
|
|
|
791
857
|
)
|
|
792
858
|
error = "list runs"
|
|
793
859
|
_path = self._path_of("runs", project)
|
|
794
|
-
|
|
795
|
-
return RunList(
|
|
860
|
+
responses = self.paginated_api_call("GET", _path, error, params=params)
|
|
861
|
+
return RunList(self.process_paginated_responses(responses, "runs"))
|
|
796
862
|
|
|
797
863
|
def del_runs(self, name=None, project=None, labels=None, state=None, days_ago=0):
|
|
798
864
|
"""Delete a group of runs identified by the parameters of the function.
|
|
799
865
|
|
|
800
866
|
Example::
|
|
801
867
|
|
|
802
|
-
db.del_runs(state=
|
|
868
|
+
db.del_runs(state="completed")
|
|
803
869
|
|
|
804
870
|
:param name: Name of the task which the runs belong to.
|
|
805
871
|
:param project: Project to which the runs belong.
|
|
@@ -944,11 +1010,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
944
1010
|
Examples::
|
|
945
1011
|
|
|
946
1012
|
# Show latest version of all artifacts in project
|
|
947
|
-
latest_artifacts = db.list_artifacts(
|
|
1013
|
+
latest_artifacts = db.list_artifacts("", tag="latest", project="iris")
|
|
948
1014
|
# check different artifact versions for a specific artifact
|
|
949
|
-
result_versions = db.list_artifacts(
|
|
1015
|
+
result_versions = db.list_artifacts("results", tag="*", project="iris")
|
|
950
1016
|
# Show artifacts with label filters - both uploaded and of binary type
|
|
951
|
-
result_labels = db.list_artifacts(
|
|
1017
|
+
result_labels = db.list_artifacts(
|
|
1018
|
+
"results", tag="*", project="iris", labels=["uploaded", "type=binary"]
|
|
1019
|
+
)
|
|
952
1020
|
|
|
953
1021
|
:param name: Name of artifacts to retrieve. Name with '~' prefix is used as a like query, and is not
|
|
954
1022
|
case-sensitive. This means that querying for ``~name`` may return artifacts named
|
|
@@ -1093,8 +1161,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1093
1161
|
}
|
|
1094
1162
|
error = "list functions"
|
|
1095
1163
|
path = f"projects/{project}/functions"
|
|
1096
|
-
|
|
1097
|
-
return
|
|
1164
|
+
responses = self.paginated_api_call("GET", path, error, params=params)
|
|
1165
|
+
return self.process_paginated_responses(responses, "funcs")
|
|
1098
1166
|
|
|
1099
1167
|
def list_runtime_resources(
|
|
1100
1168
|
self,
|
|
@@ -1184,7 +1252,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1184
1252
|
period didn't pass.
|
|
1185
1253
|
:param grace_period: Grace period given to the runtime resource before they are actually removed, counted from
|
|
1186
1254
|
the moment they moved to terminal state
|
|
1187
|
-
(defaults to mlrun.
|
|
1255
|
+
(defaults to mlrun.mlconf.runtime_resources_deletion_grace_period).
|
|
1188
1256
|
|
|
1189
1257
|
:returns: :py:class:`~mlrun.common.schemas.GroupedByProjectRuntimeResourcesOutput` listing the runtime resources
|
|
1190
1258
|
that were removed.
|
|
@@ -1240,7 +1308,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1240
1308
|
name="run_func_on_tuesdays",
|
|
1241
1309
|
kind="job",
|
|
1242
1310
|
scheduled_object=get_data_func,
|
|
1243
|
-
cron_trigger=schemas.ScheduleCronTrigger(
|
|
1311
|
+
cron_trigger=schemas.ScheduleCronTrigger(
|
|
1312
|
+
day_of_week="tue", hour=15, minute=30
|
|
1313
|
+
),
|
|
1244
1314
|
)
|
|
1245
1315
|
db.create_schedule(project_name, schedule)
|
|
1246
1316
|
"""
|
|
@@ -1343,21 +1413,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1343
1413
|
:param builder_env: Kaniko builder pod env vars dict (for config/credentials)
|
|
1344
1414
|
:param force_build: Force building the image, even when no changes were made
|
|
1345
1415
|
"""
|
|
1346
|
-
|
|
1347
|
-
"s3://"
|
|
1348
|
-
)
|
|
1349
|
-
is_ecr_image = mlrun.utils.is_ecr_url(config.httpdb.builder.docker_registry)
|
|
1350
|
-
if not func.spec.build.load_source_on_run and is_s3_source and is_ecr_image:
|
|
1351
|
-
logger.warning(
|
|
1352
|
-
"Building a function image to ECR and loading an S3 source to the image may require conflicting access "
|
|
1353
|
-
"keys. Only the permissions granted to the platform's configured secret will take affect "
|
|
1354
|
-
"(see mlrun.config.config.httpdb.builder.docker_registry_secret). "
|
|
1355
|
-
"In case the permissions are limited to ECR scope, you may use pull_at_runtime=True instead",
|
|
1356
|
-
source=func.spec.build.source,
|
|
1357
|
-
load_source_on_run=func.spec.build.load_source_on_run,
|
|
1358
|
-
default_docker_registry=config.httpdb.builder.docker_registry,
|
|
1359
|
-
)
|
|
1360
|
-
|
|
1416
|
+
self.warn_on_s3_and_ecr_permissions_conflict(func)
|
|
1361
1417
|
try:
|
|
1362
1418
|
req = {
|
|
1363
1419
|
"function": func.to_dict(),
|
|
@@ -1376,10 +1432,103 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1376
1432
|
|
|
1377
1433
|
if not resp.ok:
|
|
1378
1434
|
logger.error(f"bad resp!!\n{resp.text}")
|
|
1379
|
-
raise ValueError("bad
|
|
1435
|
+
raise ValueError("bad submit build response")
|
|
1380
1436
|
|
|
1381
1437
|
return resp.json()
|
|
1382
1438
|
|
|
1439
|
+
def deploy_nuclio_function(
|
|
1440
|
+
self,
|
|
1441
|
+
func: mlrun.runtimes.RemoteRuntime,
|
|
1442
|
+
builder_env: Optional[dict] = None,
|
|
1443
|
+
):
|
|
1444
|
+
"""
|
|
1445
|
+
Deploy a Nuclio function.
|
|
1446
|
+
:param func: Function to build.
|
|
1447
|
+
:param builder_env: Kaniko builder pod env vars dict (for config/credentials)
|
|
1448
|
+
"""
|
|
1449
|
+
func.metadata.project = func.metadata.project or config.default_project
|
|
1450
|
+
self.warn_on_s3_and_ecr_permissions_conflict(func)
|
|
1451
|
+
try:
|
|
1452
|
+
req = {
|
|
1453
|
+
"function": func.to_dict(),
|
|
1454
|
+
}
|
|
1455
|
+
if builder_env:
|
|
1456
|
+
req["builder_env"] = builder_env
|
|
1457
|
+
_path = (
|
|
1458
|
+
f"projects/{func.metadata.project}/nuclio/{func.metadata.name}/deploy"
|
|
1459
|
+
)
|
|
1460
|
+
resp = self.api_call("POST", _path, json=req)
|
|
1461
|
+
except OSError as err:
|
|
1462
|
+
logger.error(f"error submitting nuclio deploy task: {err_to_str(err)}")
|
|
1463
|
+
raise OSError(f"error: cannot submit deploy, {err_to_str(err)}")
|
|
1464
|
+
|
|
1465
|
+
if not resp.ok:
|
|
1466
|
+
logger.error(f"deploy nuclio - bad response:\n{resp.text}")
|
|
1467
|
+
raise ValueError("bad nuclio deploy response")
|
|
1468
|
+
|
|
1469
|
+
return resp.json()
|
|
1470
|
+
|
|
1471
|
+
def get_nuclio_deploy_status(
|
|
1472
|
+
self,
|
|
1473
|
+
func: mlrun.runtimes.RemoteRuntime,
|
|
1474
|
+
last_log_timestamp: float = 0.0,
|
|
1475
|
+
verbose: bool = False,
|
|
1476
|
+
):
|
|
1477
|
+
"""Retrieve the status of a deploy operation currently in progress.
|
|
1478
|
+
|
|
1479
|
+
:param func: Function object that is being built.
|
|
1480
|
+
:param last_log_timestamp: Last timestamp of logs that were already retrieved. Function will return only logs
|
|
1481
|
+
later than this parameter.
|
|
1482
|
+
:param verbose: Add verbose logs into the output.
|
|
1483
|
+
|
|
1484
|
+
:returns: The following parameters:
|
|
1485
|
+
|
|
1486
|
+
- Text of builder logs.
|
|
1487
|
+
- Timestamp of last log retrieved, to be used in subsequent calls to this function.
|
|
1488
|
+
"""
|
|
1489
|
+
|
|
1490
|
+
try:
|
|
1491
|
+
params = {
|
|
1492
|
+
"name": normalize_name(func.metadata.name),
|
|
1493
|
+
"project": func.metadata.project,
|
|
1494
|
+
"tag": func.metadata.tag,
|
|
1495
|
+
"last_log_timestamp": str(last_log_timestamp),
|
|
1496
|
+
"verbose": bool2str(verbose),
|
|
1497
|
+
}
|
|
1498
|
+
_path = (
|
|
1499
|
+
f"projects/{func.metadata.project}/nuclio/{func.metadata.name}/deploy"
|
|
1500
|
+
)
|
|
1501
|
+
resp = self.api_call("GET", _path, params=params)
|
|
1502
|
+
except OSError as err:
|
|
1503
|
+
logger.error(f"error getting deploy status: {err_to_str(err)}")
|
|
1504
|
+
raise OSError(f"error: cannot get deploy status, {err_to_str(err)}")
|
|
1505
|
+
|
|
1506
|
+
if not resp.ok:
|
|
1507
|
+
logger.warning(f"failed resp, {resp.text}")
|
|
1508
|
+
raise RunDBError("bad function build response")
|
|
1509
|
+
|
|
1510
|
+
if resp.headers:
|
|
1511
|
+
func.status.state = resp.headers.get("x-mlrun-function-status", "")
|
|
1512
|
+
last_log_timestamp = float(
|
|
1513
|
+
resp.headers.get("x-mlrun-last-timestamp", "0.0")
|
|
1514
|
+
)
|
|
1515
|
+
func.status.address = resp.headers.get("x-mlrun-address", "")
|
|
1516
|
+
func.status.nuclio_name = resp.headers.get("x-mlrun-name", "")
|
|
1517
|
+
func.status.internal_invocation_urls = resp.headers.get(
|
|
1518
|
+
"x-mlrun-internal-invocation-urls", ""
|
|
1519
|
+
).split(",")
|
|
1520
|
+
func.status.external_invocation_urls = resp.headers.get(
|
|
1521
|
+
"x-mlrun-external-invocation-urls", ""
|
|
1522
|
+
).split(",")
|
|
1523
|
+
func.status.container_image = resp.headers.get(
|
|
1524
|
+
"x-mlrun-container-image", ""
|
|
1525
|
+
)
|
|
1526
|
+
|
|
1527
|
+
text = ""
|
|
1528
|
+
if resp.content:
|
|
1529
|
+
text = resp.content.decode()
|
|
1530
|
+
return text, last_log_timestamp
|
|
1531
|
+
|
|
1383
1532
|
def get_builder_status(
|
|
1384
1533
|
self,
|
|
1385
1534
|
func: BaseRuntime,
|
|
@@ -1441,9 +1590,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1441
1590
|
func.status.container_image = resp.headers.get(
|
|
1442
1591
|
"x-mlrun-container-image", ""
|
|
1443
1592
|
)
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1593
|
+
|
|
1594
|
+
builder_pod = resp.headers.get("builder_pod", "")
|
|
1595
|
+
if builder_pod:
|
|
1596
|
+
func.status.build_pod = builder_pod
|
|
1597
|
+
|
|
1598
|
+
function_image = resp.headers.get("function_image", "")
|
|
1599
|
+
if function_image:
|
|
1600
|
+
func.spec.image = function_image
|
|
1447
1601
|
|
|
1448
1602
|
text = ""
|
|
1449
1603
|
if resp.content:
|
|
@@ -1506,7 +1660,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1506
1660
|
Retrieve updated information on project background tasks being executed.
|
|
1507
1661
|
If no filter is provided, will return background tasks from the last week.
|
|
1508
1662
|
|
|
1509
|
-
:param project: Project name (defaults to mlrun.
|
|
1663
|
+
:param project: Project name (defaults to mlrun.mlconf.default_project).
|
|
1510
1664
|
:param state: List only background tasks whose state is specified.
|
|
1511
1665
|
:param created_from: Filter by background task created time in ``[created_from, created_to]``.
|
|
1512
1666
|
:param created_to: Filter by background task created time in ``[created_from, created_to]``.
|
|
@@ -2049,7 +2203,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2049
2203
|
not a full object.
|
|
2050
2204
|
Example::
|
|
2051
2205
|
|
|
2052
|
-
feature_set_update = {"status": {"processed"
|
|
2206
|
+
feature_set_update = {"status": {"processed": True}}
|
|
2053
2207
|
|
|
2054
2208
|
Will apply the field ``status.processed`` to the existing object.
|
|
2055
2209
|
:param project: Project which contains the modified object.
|
|
@@ -2623,11 +2777,11 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2623
2777
|
:param secrets: A set of secret values to store.
|
|
2624
2778
|
Example::
|
|
2625
2779
|
|
|
2626
|
-
secrets = {
|
|
2780
|
+
secrets = {"password": "myPassw0rd", "aws_key": "111222333"}
|
|
2627
2781
|
db.create_project_secrets(
|
|
2628
2782
|
"project1",
|
|
2629
2783
|
provider=mlrun.common.schemas.SecretProviderName.kubernetes,
|
|
2630
|
-
secrets=secrets
|
|
2784
|
+
secrets=secrets,
|
|
2631
2785
|
)
|
|
2632
2786
|
"""
|
|
2633
2787
|
path = f"projects/{project}/secrets"
|
|
@@ -3155,8 +3309,10 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3155
3309
|
metadata=mlrun.common.schemas.HubObjectMetadata(
|
|
3156
3310
|
name="priv", description="a private source"
|
|
3157
3311
|
),
|
|
3158
|
-
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3159
|
-
|
|
3312
|
+
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3313
|
+
path="/local/path/to/source", channel="development"
|
|
3314
|
+
),
|
|
3315
|
+
),
|
|
3160
3316
|
)
|
|
3161
3317
|
db.create_hub_source(private_source)
|
|
3162
3318
|
|
|
@@ -3170,9 +3326,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3170
3326
|
spec=mlrun.common.schemas.HubSourceSpec(
|
|
3171
3327
|
path="/local/path/to/source/2",
|
|
3172
3328
|
channel="development",
|
|
3173
|
-
credentials={...}
|
|
3174
|
-
)
|
|
3175
|
-
)
|
|
3329
|
+
credentials={...},
|
|
3330
|
+
),
|
|
3331
|
+
),
|
|
3176
3332
|
)
|
|
3177
3333
|
db.create_hub_source(another_source)
|
|
3178
3334
|
|
|
@@ -3512,6 +3668,16 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3512
3668
|
"""
|
|
3513
3669
|
pass
|
|
3514
3670
|
|
|
3671
|
+
def store_alert_notifications(
|
|
3672
|
+
self,
|
|
3673
|
+
session,
|
|
3674
|
+
notification_objects: list[mlrun.model.Notification],
|
|
3675
|
+
alert_id: str,
|
|
3676
|
+
project: str,
|
|
3677
|
+
mask_params: bool = True,
|
|
3678
|
+
):
|
|
3679
|
+
pass
|
|
3680
|
+
|
|
3515
3681
|
def submit_workflow(
|
|
3516
3682
|
self,
|
|
3517
3683
|
project: str,
|
|
@@ -3703,6 +3869,113 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3703
3869
|
|
|
3704
3870
|
self.api_call(method="PUT", path=_path, json=profile.dict())
|
|
3705
3871
|
|
|
3872
|
+
@staticmethod
|
|
3873
|
+
def warn_on_s3_and_ecr_permissions_conflict(func):
|
|
3874
|
+
is_s3_source = func.spec.build.source and func.spec.build.source.startswith(
|
|
3875
|
+
"s3://"
|
|
3876
|
+
)
|
|
3877
|
+
is_ecr_image = mlrun.utils.is_ecr_url(config.httpdb.builder.docker_registry)
|
|
3878
|
+
if not func.spec.build.load_source_on_run and is_s3_source and is_ecr_image:
|
|
3879
|
+
logger.warning(
|
|
3880
|
+
"Building a function image to ECR and loading an S3 source to the image may require conflicting access "
|
|
3881
|
+
"keys. Only the permissions granted to the platform's configured secret will take affect "
|
|
3882
|
+
"(see mlrun.config.config.httpdb.builder.docker_registry_secret). "
|
|
3883
|
+
"In case the permissions are limited to ECR scope, you may use pull_at_runtime=True instead",
|
|
3884
|
+
source=func.spec.build.source,
|
|
3885
|
+
load_source_on_run=func.spec.build.load_source_on_run,
|
|
3886
|
+
default_docker_registry=config.httpdb.builder.docker_registry,
|
|
3887
|
+
)
|
|
3888
|
+
|
|
3889
|
+
def generate_event(
|
|
3890
|
+
self, name: str, event_data: Union[dict, mlrun.common.schemas.Event], project=""
|
|
3891
|
+
):
|
|
3892
|
+
"""
|
|
3893
|
+
Generate an event.
|
|
3894
|
+
:param name: The name of the event.
|
|
3895
|
+
:param event_data: The data of the event.
|
|
3896
|
+
:param project: The project that the event belongs to.
|
|
3897
|
+
"""
|
|
3898
|
+
project = project or config.default_project
|
|
3899
|
+
endpoint_path = f"projects/{project}/events/{name}"
|
|
3900
|
+
error_message = f"post event {project}/events/{name}"
|
|
3901
|
+
if isinstance(event_data, mlrun.common.schemas.Event):
|
|
3902
|
+
event_data = event_data.dict()
|
|
3903
|
+
self.api_call(
|
|
3904
|
+
"POST", endpoint_path, error_message, body=dict_to_json(event_data)
|
|
3905
|
+
)
|
|
3906
|
+
|
|
3907
|
+
def store_alert_config(
|
|
3908
|
+
self,
|
|
3909
|
+
alert_name: str,
|
|
3910
|
+
alert_data: Union[dict, mlrun.common.schemas.AlertConfig],
|
|
3911
|
+
project="",
|
|
3912
|
+
):
|
|
3913
|
+
"""
|
|
3914
|
+
Create/modify an alert.
|
|
3915
|
+
:param alert_name: The name of the alert.
|
|
3916
|
+
:param alert_data: The data of the alert.
|
|
3917
|
+
:param project: the project that the alert belongs to.
|
|
3918
|
+
:return: The created/modified alert.
|
|
3919
|
+
"""
|
|
3920
|
+
project = project or config.default_project
|
|
3921
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
3922
|
+
error_message = f"put alert {project}/alerts/{alert_name}"
|
|
3923
|
+
if isinstance(alert_data, mlrun.common.schemas.AlertConfig):
|
|
3924
|
+
alert_data = alert_data.dict()
|
|
3925
|
+
body = _as_json(alert_data)
|
|
3926
|
+
response = self.api_call("PUT", endpoint_path, error_message, body=body)
|
|
3927
|
+
return mlrun.common.schemas.AlertConfig(**response.json())
|
|
3928
|
+
|
|
3929
|
+
def get_alert_config(self, alert_name: str, project=""):
|
|
3930
|
+
"""
|
|
3931
|
+
Retrieve an alert.
|
|
3932
|
+
:param alert_name: The name of the alert to retrieve.
|
|
3933
|
+
:param project: The project that the alert belongs to.
|
|
3934
|
+
:return: The alert object.
|
|
3935
|
+
"""
|
|
3936
|
+
project = project or config.default_project
|
|
3937
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
3938
|
+
error_message = f"get alert {project}/alerts/{alert_name}"
|
|
3939
|
+
response = self.api_call("GET", endpoint_path, error_message)
|
|
3940
|
+
return mlrun.common.schemas.AlertConfig(**response.json())
|
|
3941
|
+
|
|
3942
|
+
def list_alerts_configs(self, project=""):
|
|
3943
|
+
"""
|
|
3944
|
+
Retrieve list of alerts of a project.
|
|
3945
|
+
:param project: The project name.
|
|
3946
|
+
:return: All the alerts objects of the project.
|
|
3947
|
+
"""
|
|
3948
|
+
project = project or config.default_project
|
|
3949
|
+
endpoint_path = f"projects/{project}/alerts"
|
|
3950
|
+
error_message = f"get alerts {project}/alerts"
|
|
3951
|
+
response = self.api_call("GET", endpoint_path, error_message).json()
|
|
3952
|
+
results = []
|
|
3953
|
+
for item in response:
|
|
3954
|
+
results.append(mlrun.common.schemas.AlertConfig(**item))
|
|
3955
|
+
return results
|
|
3956
|
+
|
|
3957
|
+
def delete_alert_config(self, alert_name: str, project=""):
|
|
3958
|
+
"""
|
|
3959
|
+
Delete an alert.
|
|
3960
|
+
:param alert_name: The name of the alert to delete.
|
|
3961
|
+
:param project: The project that the alert belongs to.
|
|
3962
|
+
"""
|
|
3963
|
+
project = project or config.default_project
|
|
3964
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
3965
|
+
error_message = f"delete alert {project}/alerts/{alert_name}"
|
|
3966
|
+
self.api_call("DELETE", endpoint_path, error_message)
|
|
3967
|
+
|
|
3968
|
+
def reset_alert_config(self, alert_name: str, project=""):
|
|
3969
|
+
"""
|
|
3970
|
+
Reset an alert.
|
|
3971
|
+
:param alert_name: The name of the alert to reset.
|
|
3972
|
+
:param project: The project that the alert belongs to.
|
|
3973
|
+
"""
|
|
3974
|
+
project = project or config.default_project
|
|
3975
|
+
endpoint_path = f"projects/{project}/alerts/{alert_name}/reset"
|
|
3976
|
+
error_message = f"post alert {project}/alerts/{alert_name}/reset"
|
|
3977
|
+
self.api_call("POST", endpoint_path, error_message)
|
|
3978
|
+
|
|
3706
3979
|
|
|
3707
3980
|
def _as_json(obj):
|
|
3708
3981
|
fn = getattr(obj, "to_json", None)
|