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.

Files changed (200) hide show
  1. mlrun/__init__.py +11 -1
  2. mlrun/__main__.py +25 -111
  3. mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
  4. mlrun/alerts/alert.py +144 -0
  5. mlrun/api/schemas/__init__.py +4 -3
  6. mlrun/artifacts/__init__.py +8 -3
  7. mlrun/artifacts/base.py +38 -254
  8. mlrun/artifacts/dataset.py +9 -190
  9. mlrun/artifacts/manager.py +41 -47
  10. mlrun/artifacts/model.py +30 -158
  11. mlrun/artifacts/plots.py +23 -380
  12. mlrun/common/constants.py +68 -0
  13. mlrun/common/formatters/__init__.py +19 -0
  14. mlrun/{model_monitoring/stores/models/sqlite.py → common/formatters/artifact.py} +6 -8
  15. mlrun/common/formatters/base.py +78 -0
  16. mlrun/common/formatters/function.py +41 -0
  17. mlrun/common/formatters/pipeline.py +53 -0
  18. mlrun/common/formatters/project.py +51 -0
  19. mlrun/{runtimes → common/runtimes}/constants.py +32 -4
  20. mlrun/common/schemas/__init__.py +25 -4
  21. mlrun/common/schemas/alert.py +203 -0
  22. mlrun/common/schemas/api_gateway.py +148 -0
  23. mlrun/common/schemas/artifact.py +15 -5
  24. mlrun/common/schemas/auth.py +8 -2
  25. mlrun/common/schemas/client_spec.py +2 -0
  26. mlrun/common/schemas/frontend_spec.py +1 -0
  27. mlrun/common/schemas/function.py +4 -0
  28. mlrun/common/schemas/hub.py +7 -9
  29. mlrun/common/schemas/model_monitoring/__init__.py +19 -3
  30. mlrun/common/schemas/model_monitoring/constants.py +96 -26
  31. mlrun/common/schemas/model_monitoring/grafana.py +9 -5
  32. mlrun/common/schemas/model_monitoring/model_endpoints.py +86 -2
  33. mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
  34. mlrun/common/schemas/pipeline.py +0 -9
  35. mlrun/common/schemas/project.py +22 -21
  36. mlrun/common/types.py +7 -1
  37. mlrun/config.py +87 -19
  38. mlrun/data_types/data_types.py +4 -0
  39. mlrun/data_types/to_pandas.py +9 -9
  40. mlrun/datastore/__init__.py +5 -8
  41. mlrun/datastore/alibaba_oss.py +130 -0
  42. mlrun/datastore/azure_blob.py +4 -5
  43. mlrun/datastore/base.py +69 -30
  44. mlrun/datastore/datastore.py +10 -2
  45. mlrun/datastore/datastore_profile.py +90 -6
  46. mlrun/datastore/google_cloud_storage.py +1 -1
  47. mlrun/datastore/hdfs.py +5 -0
  48. mlrun/datastore/inmem.py +2 -2
  49. mlrun/datastore/redis.py +2 -2
  50. mlrun/datastore/s3.py +5 -0
  51. mlrun/datastore/snowflake_utils.py +43 -0
  52. mlrun/datastore/sources.py +172 -44
  53. mlrun/datastore/store_resources.py +7 -7
  54. mlrun/datastore/targets.py +285 -41
  55. mlrun/datastore/utils.py +68 -5
  56. mlrun/datastore/v3io.py +27 -50
  57. mlrun/db/auth_utils.py +152 -0
  58. mlrun/db/base.py +149 -14
  59. mlrun/db/factory.py +1 -1
  60. mlrun/db/httpdb.py +608 -178
  61. mlrun/db/nopdb.py +191 -7
  62. mlrun/errors.py +11 -0
  63. mlrun/execution.py +37 -20
  64. mlrun/feature_store/__init__.py +0 -2
  65. mlrun/feature_store/api.py +21 -52
  66. mlrun/feature_store/feature_set.py +48 -23
  67. mlrun/feature_store/feature_vector.py +2 -1
  68. mlrun/feature_store/ingestion.py +7 -6
  69. mlrun/feature_store/retrieval/base.py +9 -4
  70. mlrun/feature_store/retrieval/conversion.py +9 -9
  71. mlrun/feature_store/retrieval/dask_merger.py +2 -0
  72. mlrun/feature_store/retrieval/job.py +9 -3
  73. mlrun/feature_store/retrieval/local_merger.py +2 -0
  74. mlrun/feature_store/retrieval/spark_merger.py +34 -24
  75. mlrun/feature_store/steps.py +30 -19
  76. mlrun/features.py +4 -13
  77. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
  78. mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
  79. mlrun/frameworks/lgbm/__init__.py +1 -1
  80. mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
  81. mlrun/frameworks/lgbm/model_handler.py +1 -1
  82. mlrun/frameworks/parallel_coordinates.py +2 -1
  83. mlrun/frameworks/pytorch/__init__.py +2 -2
  84. mlrun/frameworks/sklearn/__init__.py +1 -1
  85. mlrun/frameworks/tf_keras/__init__.py +5 -2
  86. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
  87. mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
  88. mlrun/frameworks/xgboost/__init__.py +1 -1
  89. mlrun/k8s_utils.py +10 -11
  90. mlrun/launcher/__init__.py +1 -1
  91. mlrun/launcher/base.py +6 -5
  92. mlrun/launcher/client.py +8 -6
  93. mlrun/launcher/factory.py +1 -1
  94. mlrun/launcher/local.py +9 -3
  95. mlrun/launcher/remote.py +9 -3
  96. mlrun/lists.py +6 -2
  97. mlrun/model.py +58 -19
  98. mlrun/model_monitoring/__init__.py +1 -1
  99. mlrun/model_monitoring/api.py +127 -301
  100. mlrun/model_monitoring/application.py +5 -296
  101. mlrun/model_monitoring/applications/__init__.py +11 -0
  102. mlrun/model_monitoring/applications/_application_steps.py +157 -0
  103. mlrun/model_monitoring/applications/base.py +282 -0
  104. mlrun/model_monitoring/applications/context.py +214 -0
  105. mlrun/model_monitoring/applications/evidently_base.py +211 -0
  106. mlrun/model_monitoring/applications/histogram_data_drift.py +224 -93
  107. mlrun/model_monitoring/applications/results.py +99 -0
  108. mlrun/model_monitoring/controller.py +30 -36
  109. mlrun/model_monitoring/db/__init__.py +18 -0
  110. mlrun/model_monitoring/{stores → db/stores}/__init__.py +43 -36
  111. mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
  112. mlrun/model_monitoring/{stores/model_endpoint_store.py → db/stores/base/store.py} +58 -32
  113. mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
  114. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
  115. mlrun/model_monitoring/{stores → db/stores/sqldb}/models/base.py +109 -5
  116. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +88 -0
  117. mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
  118. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +684 -0
  119. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
  120. mlrun/model_monitoring/{stores/kv_model_endpoint_store.py → db/stores/v3io_kv/kv_store.py} +302 -155
  121. mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
  122. mlrun/model_monitoring/db/tsdb/base.py +329 -0
  123. mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
  124. mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
  125. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +240 -0
  126. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
  127. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +397 -0
  128. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  129. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
  130. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +630 -0
  131. mlrun/model_monitoring/evidently_application.py +6 -118
  132. mlrun/model_monitoring/features_drift_table.py +34 -22
  133. mlrun/model_monitoring/helpers.py +100 -7
  134. mlrun/model_monitoring/model_endpoint.py +3 -2
  135. mlrun/model_monitoring/stream_processing.py +93 -228
  136. mlrun/model_monitoring/tracking_policy.py +7 -1
  137. mlrun/model_monitoring/writer.py +152 -124
  138. mlrun/package/packagers_manager.py +1 -0
  139. mlrun/package/utils/_formatter.py +2 -2
  140. mlrun/platforms/__init__.py +11 -10
  141. mlrun/platforms/iguazio.py +21 -202
  142. mlrun/projects/operations.py +30 -16
  143. mlrun/projects/pipelines.py +92 -99
  144. mlrun/projects/project.py +757 -268
  145. mlrun/render.py +15 -14
  146. mlrun/run.py +160 -162
  147. mlrun/runtimes/__init__.py +55 -3
  148. mlrun/runtimes/base.py +33 -19
  149. mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
  150. mlrun/runtimes/funcdoc.py +0 -28
  151. mlrun/runtimes/kubejob.py +28 -122
  152. mlrun/runtimes/local.py +5 -2
  153. mlrun/runtimes/mpijob/__init__.py +0 -20
  154. mlrun/runtimes/mpijob/abstract.py +8 -8
  155. mlrun/runtimes/mpijob/v1.py +1 -1
  156. mlrun/runtimes/nuclio/__init__.py +1 -0
  157. mlrun/runtimes/nuclio/api_gateway.py +709 -0
  158. mlrun/runtimes/nuclio/application/__init__.py +15 -0
  159. mlrun/runtimes/nuclio/application/application.py +523 -0
  160. mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
  161. mlrun/runtimes/nuclio/function.py +98 -58
  162. mlrun/runtimes/nuclio/serving.py +36 -42
  163. mlrun/runtimes/pod.py +196 -45
  164. mlrun/runtimes/remotesparkjob.py +1 -1
  165. mlrun/runtimes/sparkjob/spark3job.py +1 -1
  166. mlrun/runtimes/utils.py +6 -73
  167. mlrun/secrets.py +6 -2
  168. mlrun/serving/remote.py +2 -3
  169. mlrun/serving/routers.py +7 -4
  170. mlrun/serving/server.py +7 -8
  171. mlrun/serving/states.py +73 -43
  172. mlrun/serving/v2_serving.py +8 -7
  173. mlrun/track/tracker.py +2 -1
  174. mlrun/utils/async_http.py +25 -5
  175. mlrun/utils/helpers.py +141 -75
  176. mlrun/utils/http.py +1 -1
  177. mlrun/utils/logger.py +39 -7
  178. mlrun/utils/notifications/notification/__init__.py +14 -9
  179. mlrun/utils/notifications/notification/base.py +12 -0
  180. mlrun/utils/notifications/notification/console.py +2 -0
  181. mlrun/utils/notifications/notification/git.py +3 -1
  182. mlrun/utils/notifications/notification/ipython.py +2 -0
  183. mlrun/utils/notifications/notification/slack.py +101 -21
  184. mlrun/utils/notifications/notification/webhook.py +11 -1
  185. mlrun/utils/notifications/notification_pusher.py +147 -16
  186. mlrun/utils/retryer.py +3 -2
  187. mlrun/utils/v3io_clients.py +0 -1
  188. mlrun/utils/version/version.json +2 -2
  189. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/METADATA +33 -18
  190. mlrun-1.7.0rc20.dist-info/RECORD +353 -0
  191. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/WHEEL +1 -1
  192. mlrun/kfpops.py +0 -868
  193. mlrun/model_monitoring/batch.py +0 -974
  194. mlrun/model_monitoring/stores/models/__init__.py +0 -27
  195. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
  196. mlrun/platforms/other.py +0 -305
  197. mlrun-1.7.0rc4.dist-info/RECORD +0 -321
  198. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/LICENSE +0 -0
  199. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/entry_points.txt +0 -0
  200. {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
- username, password, token = mlrun.platforms.add_or_refresh_credentials(
140
- parsed_url.hostname, username, password, config.httpdb.token
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: Python HTTP response object
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.token:
217
- # Iguazio auth doesn't support passing token through bearer, so use cookie instead
218
- if mlrun.platforms.iguazio.is_iguazio_session(self.token):
219
- session_cookie = f'j:{{"sid": "{self.token}"}}'
220
- cookies = {
221
- "session": session_cookie,
222
- }
223
- kw["cookies"] = cookies
224
- else:
225
- if "Authorization" not in kw.setdefault("headers", {}):
226
- kw["headers"].update({"Authorization": "Bearer " + self.token})
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 'http://mlrun-api:8080'
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(config.httpdb.logs.pull_logs_default_size_limit)
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=config.httpdb.logs.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(config.httpdb.logs.pull_logs_default_interval))
651
+ time.sleep(int(mlrun.mlconf.httpdb.logs.pull_logs_default_interval))
565
652
  else:
566
653
  time.sleep(
567
- int(config.httpdb.logs.pull_logs_backoff_no_logs_default_interval)
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=config.httpdb.logs.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[str] = None,
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(name='download', project='iris', labels=['owner=admin', 'kind=job'])
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='', project=project_name).show()
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
- resp = self.api_call("GET", _path, error, params=params)
791
- return RunList(resp.json()["runs"])
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='completed')
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.schemas.ArtifactsFormat.full.value,
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(self, key, tag=None, project="", tree=None, uid=None):
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("DELETE", endpoint_path, error, params=params, version="v2")
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('', tag='latest', project='iris')
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('results', tag='*', project='iris')
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('results', tag='*', project='iris', labels=['uploaded', 'type=binary'])
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: Return artifacts of the requested kind.
964
- :param category: Return artifacts of the requested category.
965
- :param tree: Return artifacts of the requested 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.schemas.ArtifactsFormat.full.value,
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
- resp = self.api_call("GET", path, error, params=params)
1093
- return resp.json()["funcs"]
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.config.config.runtime_resources_deletion_grace_period).
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(day_of_week='tue', hour=15, minute=30),
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
- is_s3_source = func.spec.build.source and func.spec.build.source.startswith(
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 function run response")
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
- else:
1441
- func.status.build_pod = resp.headers.get("builder_pod", "")
1442
- func.spec.image = resp.headers.get("function_image", "")
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.config.config.default_project).
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: The project of the pipeline
1622
- :param pipeline: Pipeline function or path to .yaml/.zip pipeline file.
1623
- :param arguments: A dictionary of arguments to pass to the pipeline.
1624
- :param experiment: A name to assign for the specific experiment.
1625
- :param run: A name for this specific run.
1626
- :param namespace: Kubernetes namespace to execute the pipeline in.
1627
- :param artifact_path: A path to artifacts used by this pipeline.
1628
- :param ops: Transformers to apply on all ops in the pipeline.
1629
- :param cleanup_ttl: pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
1630
- workflow and all its resources are deleted)
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 = tempfile.NamedTemporaryFile(suffix=".yaml", delete=False).name
1637
- conf = new_pipe_metadata(
1878
+ pipe_file = compile_pipeline(
1638
1879
  artifact_path=artifact_path,
1639
1880
  cleanup_ttl=cleanup_ttl,
1640
- op_transformers=ops,
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=20,
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.schemas.PipelinesFormat
1699
- ] = mlrun.common.schemas.PipelinesFormat.metadata_only,
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.schemas.PipelinesFormat
1746
- ] = mlrun.common.schemas.PipelinesFormat.summary,
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" : True}}
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.schemas.ProjectsFormat
2389
- ] = mlrun.common.schemas.ProjectsFormat.name_only,
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.schemas.ProjectsFormat.name_only:
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 = {'password': 'myPassw0rd', 'aws_key': '111222333'}
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
- time, a Unix timestamp in milliseconds, a relative time (`'now'` or
2922
- `'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours, and `'d'` =
2923
- days), or 0 for the earliest time.
2924
- :param end: The end time of the metrics. Can be represented by a string containing an RFC 3339
2925
- time, a Unix timestamp in milliseconds, a relative time (`'now'` or
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 Unix timestamp in milliseconds, a relative time (`'now'` or
2977
- `'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours, and `'d'` = days), or
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 Unix timestamp in milliseconds, a relative time (`'now'` or
2981
- `'now-[0-9]+[mhd]'`, where `m` = minutes, `h` = hours, and `'d'` = days), or
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
- params = {
3098
- "image": image,
3099
- "base_period": base_period,
3100
- }
3101
- path = f"projects/{project}/model-monitoring/model-monitoring-controller"
3102
- self.api_call(method="POST", path=path, params=params)
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
- :param project: Project name.
3120
- :param base_period: The time period in minutes in which the model monitoring controller function
3121
- triggers. By default, the base period is 10 minutes.
3122
- :param image: The image of the model monitoring controller, writer & monitoring
3123
- stream functions, which are real time nuclio functions.
3124
- By default, the image is mlrun/mlrun.
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
- params = {
3128
- "base_period": base_period,
3129
- "image": image,
3130
- }
3131
- path = f"projects/{project}/model-monitoring/enable-model-monitoring"
3132
- self.api_call(method="POST", path=path, params=params)
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(path="/local/path/to/source", channel="development")
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 Nuclio's value is taken
3604
+ :param project: optional str parameter to filter by project, if not passed, default project value is taken
3376
3605
 
3377
- :return: json with the list of Nuclio Api Gateways
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}/nuclio/api-gateways"
3384
- resp = self.api_call("GET", endpoint_path, error)
3385
- return resp.json()
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)