mlrun 1.8.0rc5__py3-none-any.whl → 1.8.0rc9__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 (74) hide show
  1. mlrun/__init__.py +1 -0
  2. mlrun/artifacts/__init__.py +1 -1
  3. mlrun/artifacts/base.py +21 -1
  4. mlrun/artifacts/document.py +62 -39
  5. mlrun/artifacts/manager.py +12 -5
  6. mlrun/common/constants.py +1 -0
  7. mlrun/common/model_monitoring/__init__.py +0 -2
  8. mlrun/common/model_monitoring/helpers.py +0 -28
  9. mlrun/common/schemas/__init__.py +2 -4
  10. mlrun/common/schemas/alert.py +77 -1
  11. mlrun/common/schemas/client_spec.py +0 -1
  12. mlrun/common/schemas/model_monitoring/__init__.py +0 -6
  13. mlrun/common/schemas/model_monitoring/constants.py +11 -9
  14. mlrun/common/schemas/model_monitoring/model_endpoints.py +77 -149
  15. mlrun/common/schemas/notification.py +6 -0
  16. mlrun/common/schemas/project.py +3 -0
  17. mlrun/config.py +2 -3
  18. mlrun/datastore/datastore_profile.py +57 -17
  19. mlrun/datastore/sources.py +1 -2
  20. mlrun/datastore/store_resources.py +7 -2
  21. mlrun/datastore/vectorstore.py +99 -62
  22. mlrun/db/base.py +34 -20
  23. mlrun/db/httpdb.py +249 -163
  24. mlrun/db/nopdb.py +40 -17
  25. mlrun/execution.py +14 -7
  26. mlrun/feature_store/api.py +1 -0
  27. mlrun/model.py +3 -0
  28. mlrun/model_monitoring/__init__.py +3 -2
  29. mlrun/model_monitoring/api.py +64 -53
  30. mlrun/model_monitoring/applications/_application_steps.py +3 -1
  31. mlrun/model_monitoring/applications/base.py +115 -15
  32. mlrun/model_monitoring/applications/context.py +42 -24
  33. mlrun/model_monitoring/applications/histogram_data_drift.py +1 -1
  34. mlrun/model_monitoring/controller.py +43 -37
  35. mlrun/model_monitoring/db/__init__.py +0 -2
  36. mlrun/model_monitoring/db/tsdb/base.py +2 -1
  37. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +2 -1
  38. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +43 -0
  39. mlrun/model_monitoring/helpers.py +78 -66
  40. mlrun/model_monitoring/stream_processing.py +83 -270
  41. mlrun/model_monitoring/writer.py +1 -10
  42. mlrun/projects/pipelines.py +37 -1
  43. mlrun/projects/project.py +173 -70
  44. mlrun/run.py +40 -0
  45. mlrun/runtimes/nuclio/function.py +7 -6
  46. mlrun/runtimes/nuclio/serving.py +9 -4
  47. mlrun/serving/routers.py +158 -145
  48. mlrun/serving/server.py +6 -0
  49. mlrun/serving/states.py +21 -7
  50. mlrun/serving/v2_serving.py +94 -68
  51. mlrun/utils/helpers.py +23 -33
  52. mlrun/utils/notifications/notification/mail.py +17 -6
  53. mlrun/utils/notifications/notification_pusher.py +9 -5
  54. mlrun/utils/regex.py +8 -1
  55. mlrun/utils/version/version.json +2 -2
  56. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/METADATA +2 -2
  57. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/RECORD +61 -74
  58. mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +0 -149
  59. mlrun/model_monitoring/db/stores/__init__.py +0 -136
  60. mlrun/model_monitoring/db/stores/base/__init__.py +0 -15
  61. mlrun/model_monitoring/db/stores/base/store.py +0 -154
  62. mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
  63. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -46
  64. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -93
  65. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -47
  66. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -25
  67. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -408
  68. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
  69. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -464
  70. mlrun/model_monitoring/model_endpoint.py +0 -120
  71. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/LICENSE +0 -0
  72. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/WHEEL +0 -0
  73. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/entry_points.txt +0 -0
  74. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/top_level.txt +0 -0
mlrun/projects/project.py CHANGED
@@ -59,13 +59,17 @@ import mlrun.utils
59
59
  import mlrun.utils.regex
60
60
  import mlrun_pipelines.common.models
61
61
  from mlrun.alerts.alert import AlertConfig
62
+ from mlrun.common.schemas import alert as alert_constants
62
63
  from mlrun.datastore.datastore_profile import (
63
64
  DatastoreProfile,
64
65
  DatastoreProfile2Json,
65
- VectorStoreProfile,
66
66
  datastore_profile_read,
67
67
  )
68
68
  from mlrun.datastore.vectorstore import VectorStoreCollection
69
+ from mlrun.model_monitoring.helpers import (
70
+ filter_results_by_regex,
71
+ get_result_instance_fqn,
72
+ )
69
73
  from mlrun.runtimes.nuclio.function import RemoteRuntime
70
74
  from mlrun_pipelines.models import PipelineNodeWrapper
71
75
 
@@ -1535,7 +1539,9 @@ class MlrunProject(ModelObj):
1535
1539
 
1536
1540
  def update_artifact(self, artifact_object: Artifact):
1537
1541
  artifacts_manager = self._get_artifact_manager()
1538
- artifacts_manager.update_artifact(artifact_object, artifact_object)
1542
+ project_tag = self._get_project_tag()
1543
+ producer, _ = self._resolve_artifact_producer(artifact_object, project_tag)
1544
+ artifacts_manager.update_artifact(producer, artifact_object)
1539
1545
 
1540
1546
  def _get_artifact_manager(self):
1541
1547
  if self._artifact_manager:
@@ -1862,70 +1868,60 @@ class MlrunProject(ModelObj):
1862
1868
  )
1863
1869
  return item
1864
1870
 
1865
- def get_or_create_vector_store_collection(
1871
+ def get_vector_store_collection(
1866
1872
  self,
1867
- collection_name: str,
1868
- profile: Union[str, VectorStoreProfile],
1869
- **kwargs,
1873
+ vector_store: "VectorStore", # noqa: F821
1874
+ collection_name: Optional[str] = None,
1870
1875
  ) -> VectorStoreCollection:
1871
- """
1872
- Create or retrieve a VectorStoreCollection.
1873
-
1874
- :param collection_name: Name of the collection
1875
- :param profile: Name of the VectorStoreProfile or a VectorStoreProfile object
1876
- :param kwargs: Additional arguments for the VectorStoreCollection
1877
- :return: VectorStoreCollection object
1878
- """
1879
- if isinstance(profile, str):
1880
- profile = datastore_profile_read(f"ds://{profile}")
1881
-
1882
- if not isinstance(profile, VectorStoreProfile):
1883
- raise ValueError(
1884
- "Profile must be a VectorStoreProfile object or a profile name"
1885
- )
1886
1876
  return VectorStoreCollection(
1887
- profile.vector_store_class,
1888
1877
  self,
1889
- profile.name,
1878
+ vector_store,
1890
1879
  collection_name,
1891
- **profile.attributes(kwargs),
1892
1880
  )
1893
1881
 
1894
1882
  def log_document(
1895
1883
  self,
1896
1884
  key: str,
1897
- artifact_path: Optional[str] = None,
1898
- document_loader: DocumentLoaderSpec = DocumentLoaderSpec(),
1899
1885
  tag: str = "",
1886
+ local_path: str = "",
1887
+ artifact_path: Optional[str] = None,
1888
+ document_loader_spec: Optional[DocumentLoaderSpec] = None,
1900
1889
  upload: Optional[bool] = False,
1901
1890
  labels: Optional[dict[str, str]] = None,
1891
+ target_path: Optional[str] = None,
1902
1892
  **kwargs,
1903
1893
  ) -> DocumentArtifact:
1904
1894
  """
1905
1895
  Log a document as an artifact.
1906
1896
 
1907
1897
  :param key: Artifact key
1908
- :param target_path: Path to the local file
1909
- :param artifact_path: Target path for artifact storage
1910
- :param document_loader: Spec to use to load the artifact as langchain document
1911
1898
  :param tag: Version tag
1899
+ :param local_path: path to the local file we upload, will also be use
1900
+ as the destination subpath (under "artifact_path")
1901
+ :param artifact_path: Target path for artifact storage
1902
+ :param document_loader_spec: Spec to use to load the artifact as langchain document
1912
1903
  :param upload: Whether to upload the artifact
1913
1904
  :param labels: Key-value labels
1905
+ :param target_path: Target file path
1914
1906
  :param kwargs: Additional keyword arguments
1915
1907
  :return: DocumentArtifact object
1916
1908
  """
1917
1909
  doc_artifact = DocumentArtifact(
1918
1910
  key=key,
1919
- document_loader=document_loader,
1911
+ original_source=local_path or target_path,
1912
+ document_loader_spec=document_loader_spec
1913
+ if document_loader_spec
1914
+ else DocumentLoaderSpec(),
1920
1915
  **kwargs,
1921
1916
  )
1922
-
1923
1917
  return self.log_artifact(
1924
- doc_artifact,
1925
- artifact_path=artifact_path,
1918
+ item=doc_artifact,
1926
1919
  tag=tag,
1920
+ local_path=local_path,
1921
+ artifact_path=artifact_path,
1927
1922
  upload=upload,
1928
1923
  labels=labels,
1924
+ target_path=target_path,
1929
1925
  )
1930
1926
 
1931
1927
  def import_artifact(
@@ -2040,12 +2036,90 @@ class MlrunProject(ModelObj):
2040
2036
  )
2041
2037
  return _run_project_setup(self, setup_file_path, save)
2042
2038
 
2039
+ def create_model_monitoring_alert_configs(
2040
+ self,
2041
+ name: str,
2042
+ summary: str,
2043
+ endpoints: mlrun.common.schemas.ModelEndpointList,
2044
+ events: Union[list[alert_constants.EventKind], alert_constants.EventKind],
2045
+ notifications: list[alert_constants.AlertNotification],
2046
+ result_names: Optional[
2047
+ list[str]
2048
+ ] = None, # can use wildcards - see below for explanation.
2049
+ severity: alert_constants.AlertSeverity = alert_constants.AlertSeverity.MEDIUM,
2050
+ criteria: alert_constants.AlertCriteria = alert_constants.AlertCriteria(
2051
+ count=1, period="10m"
2052
+ ),
2053
+ reset_policy: mlrun.common.schemas.alert.ResetPolicy = mlrun.common.schemas.alert.ResetPolicy.AUTO,
2054
+ ) -> list[mlrun.alerts.alert.AlertConfig]:
2055
+ """
2056
+ :param name: AlertConfig name.
2057
+ :param summary: Summary of the alert, will be sent in the generated notifications
2058
+ :param endpoints: The endpoints from which to retrieve the metrics that the
2059
+ alerts will be based on.
2060
+ :param events: AlertTrigger event types (EventKind).
2061
+ :param notifications: List of notifications to invoke once the alert is triggered
2062
+ :param result_names: Optional. Filters the result names used to create the alert configuration,
2063
+ constructed from the app and result_name regex.
2064
+
2065
+ For example:
2066
+ [`app1.result-*`, `*.result1`]
2067
+ will match "mep1.app1.result.result-1" and "mep1.app2.result.result1".
2068
+ :param severity: Severity of the alert.
2069
+ :param criteria: When the alert will be triggered based on the
2070
+ specified number of events within the defined time period.
2071
+ :param reset_policy: When to clear the alert. May be "manual" for manual reset of the alert,
2072
+ or "auto" if the criteria contains a time period.
2073
+ :returns: List of AlertConfig according to endpoints results,
2074
+ filtered by result_names.
2075
+ """
2076
+ db = mlrun.db.get_run_db(secrets=self._secrets)
2077
+ matching_results = []
2078
+ alerts = []
2079
+ # TODO: Refactor to use a single request to improve performance at scale, ML-8473
2080
+ for endpoint in endpoints.endpoints:
2081
+ results_by_endpoint = db.get_model_endpoint_monitoring_metrics(
2082
+ project=self.name, endpoint_id=endpoint.metadata.uid, type="results"
2083
+ )
2084
+ results_fqn_by_endpoint = [
2085
+ get_result_instance_fqn(
2086
+ model_endpoint_id=endpoint.metadata.uid,
2087
+ app_name=result.app,
2088
+ result_name=result.name,
2089
+ )
2090
+ for result in results_by_endpoint
2091
+ ]
2092
+ matching_results += filter_results_by_regex(
2093
+ existing_result_names=results_fqn_by_endpoint,
2094
+ result_name_filters=result_names,
2095
+ )
2096
+ for result_fqn in matching_results:
2097
+ alerts.append(
2098
+ mlrun.alerts.alert.AlertConfig(
2099
+ project=self.name,
2100
+ name=name,
2101
+ summary=summary,
2102
+ severity=severity,
2103
+ entities=alert_constants.EventEntities(
2104
+ kind=alert_constants.EventEntityKind.MODEL_ENDPOINT_RESULT,
2105
+ project=self.name,
2106
+ ids=[result_fqn],
2107
+ ),
2108
+ trigger=alert_constants.AlertTrigger(
2109
+ events=events if isinstance(events, list) else [events]
2110
+ ),
2111
+ criteria=criteria,
2112
+ notifications=notifications,
2113
+ reset_policy=reset_policy,
2114
+ )
2115
+ )
2116
+ return alerts
2117
+
2043
2118
  def set_model_monitoring_function(
2044
2119
  self,
2045
- func: typing.Union[str, mlrun.runtimes.BaseRuntime, None] = None,
2120
+ func: typing.Union[str, mlrun.runtimes.RemoteRuntime, None] = None,
2046
2121
  application_class: typing.Union[
2047
- str,
2048
- mm_app.ModelMonitoringApplicationBase,
2122
+ str, mm_app.ModelMonitoringApplicationBase, None
2049
2123
  ] = None,
2050
2124
  name: Optional[str] = None,
2051
2125
  image: Optional[str] = None,
@@ -2055,7 +2129,7 @@ class MlrunProject(ModelObj):
2055
2129
  requirements: Optional[typing.Union[str, list[str]]] = None,
2056
2130
  requirements_file: str = "",
2057
2131
  **application_kwargs,
2058
- ) -> mlrun.runtimes.BaseRuntime:
2132
+ ) -> mlrun.runtimes.RemoteRuntime:
2059
2133
  """
2060
2134
  Update or add a monitoring function to the project.
2061
2135
  Note: to deploy the function after linking it to the project,
@@ -2067,7 +2141,8 @@ class MlrunProject(ModelObj):
2067
2141
  name="myApp", application_class="MyApp", image="mlrun/mlrun"
2068
2142
  )
2069
2143
 
2070
- :param func: Function object or spec/code url, None refers to current Notebook
2144
+ :param func: Remote function object or spec/code URL. :code:`None` refers to the current
2145
+ notebook.
2071
2146
  :param name: Name of the function (under the project), can be specified with a tag to support
2072
2147
  versions (e.g. myfunc:v1)
2073
2148
  Default: job
@@ -2083,6 +2158,7 @@ class MlrunProject(ModelObj):
2083
2158
  :param application_class: Name or an Instance of a class that implements the monitoring application.
2084
2159
  :param application_kwargs: Additional keyword arguments to be passed to the
2085
2160
  monitoring application's constructor.
2161
+ :returns: The model monitoring remote function object.
2086
2162
  """
2087
2163
  (
2088
2164
  resolved_function_name,
@@ -2120,7 +2196,7 @@ class MlrunProject(ModelObj):
2120
2196
  requirements: Optional[typing.Union[str, list[str]]] = None,
2121
2197
  requirements_file: str = "",
2122
2198
  **application_kwargs,
2123
- ) -> mlrun.runtimes.BaseRuntime:
2199
+ ) -> mlrun.runtimes.RemoteRuntime:
2124
2200
  """
2125
2201
  Create a monitoring function object without setting it to the project
2126
2202
 
@@ -2130,7 +2206,7 @@ class MlrunProject(ModelObj):
2130
2206
  application_class_name="MyApp", image="mlrun/mlrun", name="myApp"
2131
2207
  )
2132
2208
 
2133
- :param func: Code url, None refers to current Notebook
2209
+ :param func: The function's code URL. :code:`None` refers to the current notebook.
2134
2210
  :param name: Name of the function, can be specified with a tag to support
2135
2211
  versions (e.g. myfunc:v1)
2136
2212
  Default: job
@@ -2146,6 +2222,7 @@ class MlrunProject(ModelObj):
2146
2222
  :param application_class: Name or an Instance of a class that implementing the monitoring application.
2147
2223
  :param application_kwargs: Additional keyword arguments to be passed to the
2148
2224
  monitoring application's constructor.
2225
+ :returns: The model monitoring remote function object.
2149
2226
  """
2150
2227
 
2151
2228
  _, function_object, _ = self._instantiate_model_monitoring_function(
@@ -2178,7 +2255,7 @@ class MlrunProject(ModelObj):
2178
2255
  requirements: typing.Union[str, list[str], None] = None,
2179
2256
  requirements_file: str = "",
2180
2257
  **application_kwargs,
2181
- ) -> tuple[str, mlrun.runtimes.BaseRuntime, dict]:
2258
+ ) -> tuple[str, mlrun.runtimes.RemoteRuntime, dict]:
2182
2259
  import mlrun.model_monitoring.api
2183
2260
 
2184
2261
  kind = None
@@ -3413,7 +3490,6 @@ class MlrunProject(ModelObj):
3413
3490
  def set_model_monitoring_credentials(
3414
3491
  self,
3415
3492
  access_key: Optional[str] = None,
3416
- endpoint_store_connection: Optional[str] = None,
3417
3493
  stream_path: Optional[str] = None,
3418
3494
  tsdb_connection: Optional[str] = None,
3419
3495
  replace_creds: bool = False,
@@ -3424,7 +3500,6 @@ class MlrunProject(ModelObj):
3424
3500
  model monitoring or serving function.
3425
3501
 
3426
3502
  :param access_key: Model monitoring access key for managing user permissions.
3427
- :param endpoint_store_connection: Endpoint store connection string. By default, None. Options:
3428
3503
 
3429
3504
  * None - will be set from the system configuration.
3430
3505
  * v3io - for v3io endpoint store, pass `v3io` and the system will generate the
@@ -3457,7 +3532,6 @@ class MlrunProject(ModelObj):
3457
3532
  project=self.name,
3458
3533
  credentials={
3459
3534
  "access_key": access_key,
3460
- "endpoint_store_connection": endpoint_store_connection,
3461
3535
  "stream_path": stream_path,
3462
3536
  "tsdb_connection": tsdb_connection,
3463
3537
  },
@@ -3475,29 +3549,37 @@ class MlrunProject(ModelObj):
3475
3549
 
3476
3550
  def list_model_endpoints(
3477
3551
  self,
3478
- model: Optional[str] = None,
3479
- function: Optional[str] = None,
3552
+ name: Optional[str] = None,
3553
+ model_name: Optional[str] = None,
3554
+ function_name: Optional[str] = None,
3555
+ function_tag: Optional[str] = None,
3480
3556
  labels: Optional[list[str]] = None,
3481
- start: str = "now-1h",
3482
- end: str = "now",
3557
+ start: Optional[datetime.datetime] = None,
3558
+ end: Optional[datetime.datetime] = None,
3483
3559
  top_level: bool = False,
3484
3560
  uids: Optional[list[str]] = None,
3485
- ) -> list[mlrun.model_monitoring.model_endpoint.ModelEndpoint]:
3561
+ latest_only: bool = False,
3562
+ ) -> mlrun.common.schemas.ModelEndpointList:
3486
3563
  """
3487
3564
  Returns a list of `ModelEndpoint` objects. Each `ModelEndpoint` object represents the current state of a
3488
3565
  model endpoint. This functions supports filtering by the following parameters:
3489
- 1) model
3490
- 2) function
3491
- 3) labels
3492
- 4) top level
3493
- 5) uids
3566
+ 1) name
3567
+ 2) model_name
3568
+ 3) function_name
3569
+ 4) function_tag
3570
+ 5) labels
3571
+ 6) top level
3572
+ 7) uids
3573
+ 8) start and end time, corresponding to the `created` field.
3494
3574
  By default, when no filters are applied, all available endpoints for the given project will be listed.
3495
3575
 
3496
3576
  In addition, this functions provides a facade for listing endpoint related metrics. This facade is time-based
3497
3577
  and depends on the 'start' and 'end' parameters.
3498
3578
 
3499
- :param model: The name of the model to filter by
3500
- :param function: The name of the function to filter by
3579
+ :param name: The name of the model to filter by
3580
+ :param model_name: The name of the model to filter by
3581
+ :param function_name: The name of the function to filter by
3582
+ :param function_tag: The tag of the function to filter by
3501
3583
  :param labels: Filter model endpoints by label key-value pairs or key existence. This can be provided as:
3502
3584
  - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
3503
3585
  or `{"label": None}` to check for key existence.
@@ -3505,12 +3587,8 @@ class MlrunProject(ModelObj):
3505
3587
  or just `"label"` for key existence.
3506
3588
  - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
3507
3589
  the specified key-value pairs or key existence.
3508
- :param start: The start time of the metrics. Can be represented by a string containing an RFC 3339 time, a
3509
- Unix timestamp in milliseconds, a relative time (`'now'` or `'now-[0-9]+[mhd]'`, where
3510
- `m` = minutes, `h` = hours, `'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
3511
- :param end: The end time of the metrics. Can be represented by a string containing an RFC 3339 time, a
3512
- Unix timestamp in milliseconds, a relative time (`'now'` or `'now-[0-9]+[mhd]'`, where
3513
- `m` = minutes, `h` = hours, `'d'` = days, and `'s'` = seconds), or 0 for the earliest time.
3590
+ :param start: The start time to filter by.Corresponding to the `created` field.
3591
+ :param end: The end time to filter by. Corresponding to the `created` field.
3514
3592
  :param top_level: if true will return only routers and endpoint that are NOT children of any router
3515
3593
  :param uids: if passed will return a list `ModelEndpoint` object with uid in uids
3516
3594
 
@@ -3519,13 +3597,16 @@ class MlrunProject(ModelObj):
3519
3597
  db = mlrun.db.get_run_db(secrets=self._secrets)
3520
3598
  return db.list_model_endpoints(
3521
3599
  project=self.name,
3522
- model=model,
3523
- function=function,
3600
+ name=name,
3601
+ model_name=model_name,
3602
+ function_name=function_name,
3603
+ function_tag=function_tag,
3524
3604
  labels=labels,
3525
3605
  start=start,
3526
3606
  end=end,
3527
3607
  top_level=top_level,
3528
3608
  uids=uids,
3609
+ latest_only=latest_only,
3529
3610
  )
3530
3611
 
3531
3612
  def run_function(
@@ -3911,18 +3992,21 @@ class MlrunProject(ModelObj):
3911
3992
  mock=mock,
3912
3993
  )
3913
3994
 
3914
- def get_artifact(self, key, tag=None, iter=None, tree=None):
3995
+ def get_artifact(
3996
+ self, key, tag=None, iter=None, tree=None, uid=None
3997
+ ) -> typing.Optional[Artifact]:
3915
3998
  """Return an artifact object
3916
3999
 
3917
- :param key: artifact key
3918
- :param tag: version tag
3919
- :param iter: iteration number (for hyper-param tasks)
3920
- :param tree: the producer id (tree)
4000
+ :param key: Artifact key
4001
+ :param tag: Version tag
4002
+ :param iter: Iteration number (for hyper-param tasks)
4003
+ :param tree: The producer id (tree)
4004
+ :param uid: The artifact uid
3921
4005
  :return: Artifact object
3922
4006
  """
3923
4007
  db = mlrun.db.get_run_db(secrets=self._secrets)
3924
4008
  artifact = db.read_artifact(
3925
- key, tag, iter=iter, project=self.metadata.name, tree=tree
4009
+ key, tag, iter=iter, project=self.metadata.name, tree=tree, uid=uid
3926
4010
  )
3927
4011
 
3928
4012
  # in tests, if an artifact is not found, the db returns None
@@ -4502,6 +4586,25 @@ class MlrunProject(ModelObj):
4502
4586
  profile, self.name
4503
4587
  )
4504
4588
 
4589
+ def get_config_profile_attributes(self, name: str) -> dict:
4590
+ """
4591
+ Get the merged attributes from a named configuration profile.
4592
+
4593
+ Retrieves a profile from the datastore using the provided name and returns its
4594
+ merged public and private attributes as a dictionary.
4595
+
4596
+ Args:
4597
+ name (str): Name of the configuration profile to retrieve. Will be prefixed
4598
+ with "ds://" to form the full profile path.
4599
+
4600
+ Returns:
4601
+ dict: The merged attributes dictionary containing both public and private
4602
+ configuration settings from the profile. Returns nested dictionaries if
4603
+ the profile contains nested configurations.
4604
+ """
4605
+ profile = datastore_profile_read(f"ds://{name}", self.name)
4606
+ return profile.attributes()
4607
+
4505
4608
  def delete_datastore_profile(self, profile: str):
4506
4609
  mlrun.db.get_run_db(secrets=self._secrets).delete_datastore_profile(
4507
4610
  profile, self.name
mlrun/run.py CHANGED
@@ -909,6 +909,46 @@ def _run_pipeline(
909
909
  return pipeline_run_id
910
910
 
911
911
 
912
+ def retry_pipeline(
913
+ run_id: str,
914
+ project: Optional[str] = None,
915
+ namespace: Optional[str] = None,
916
+ ) -> str:
917
+ """Retry a pipeline run.
918
+
919
+ This function retries a previously executed pipeline run using the specified run ID. If the run is not in a
920
+ retryable state, a new run is created as a clone of the original run.
921
+
922
+ :param run_id: ID of the pipeline run to retry.
923
+ :param project: Optional; name of the project associated with the pipeline run.
924
+ :param namespace: Optional; Kubernetes namespace to use if not the default.
925
+
926
+ :returns: ID of the retried pipeline run or the ID of a cloned run if the original run is not retryable.
927
+ :raises ValueError: If access to the remote API service is not available.
928
+ """
929
+ mldb = mlrun.db.get_run_db()
930
+ if mldb.kind != "http":
931
+ raise ValueError(
932
+ "Retrying a pipeline requires access to remote API service. "
933
+ "Please set the dbpath URL."
934
+ )
935
+
936
+ pipeline_run_id = mldb.retry_pipeline(
937
+ run_id=run_id,
938
+ project=project,
939
+ namespace=namespace,
940
+ )
941
+ if pipeline_run_id == run_id:
942
+ logger.info(
943
+ f"Retried pipeline run ID={pipeline_run_id}, check UI for progress."
944
+ )
945
+ else:
946
+ logger.info(
947
+ f"Copy of pipeline {run_id} was retried as run ID={pipeline_run_id}, check UI for progress."
948
+ )
949
+ return pipeline_run_id
950
+
951
+
912
952
  def wait_for_pipeline_completion(
913
953
  run_id,
914
954
  timeout=60 * 60,
@@ -1192,9 +1192,6 @@ class RemoteRuntime(KubeResource):
1192
1192
  return results
1193
1193
 
1194
1194
  def _resolve_invocation_url(self, path, force_external_address):
1195
- if not path.startswith("/") and path != "":
1196
- path = f"/{path}"
1197
-
1198
1195
  # internal / external invocation urls is a nuclio >= 1.6.x feature
1199
1196
  # try to infer the invocation url from the internal and if not exists, use external.
1200
1197
  # $$$$ we do not want to use the external invocation url (e.g.: ingress, nodePort, etc.)
@@ -1203,12 +1200,16 @@ class RemoteRuntime(KubeResource):
1203
1200
  and self.status.internal_invocation_urls
1204
1201
  and mlrun.k8s_utils.is_running_inside_kubernetes_cluster()
1205
1202
  ):
1206
- return f"http://{self.status.internal_invocation_urls[0]}{path}"
1203
+ return mlrun.utils.helpers.join_urls(
1204
+ f"http://{self.status.internal_invocation_urls[0]}", path
1205
+ )
1207
1206
 
1208
1207
  if self.status.external_invocation_urls:
1209
- return f"http://{self.status.external_invocation_urls[0]}{path}"
1208
+ return mlrun.utils.helpers.join_urls(
1209
+ f"http://{self.status.external_invocation_urls[0]}", path
1210
+ )
1210
1211
  else:
1211
- return f"http://{self.status.address}{path}"
1212
+ return mlrun.utils.helpers.join_urls(f"http://{self.status.address}", path)
1212
1213
 
1213
1214
  def _update_credentials_from_remote_build(self, remote_data):
1214
1215
  self.metadata.credentials = remote_data.get("metadata", {}).get(
@@ -39,7 +39,7 @@ from mlrun.serving.states import (
39
39
  )
40
40
  from mlrun.utils import get_caller_globals, logger, set_paths
41
41
 
42
- from .function import NuclioSpec, RemoteRuntime
42
+ from .function import NuclioSpec, RemoteRuntime, min_nuclio_versions
43
43
 
44
44
  serving_subkind = "serving_v2"
45
45
 
@@ -421,8 +421,6 @@ class ServingRuntime(RemoteRuntime):
421
421
  class_name.model_path = model_path
422
422
  key, state = params_to_step(class_name, key)
423
423
  else:
424
- if not model_path and not model_url:
425
- raise ValueError("model_path or model_url must be provided")
426
424
  class_name = class_name or self.spec.default_class
427
425
  if class_name and not isinstance(class_name, str):
428
426
  raise ValueError(
@@ -577,6 +575,7 @@ class ServingRuntime(RemoteRuntime):
577
575
  self.spec.secret_sources.append({"kind": kind, "source": source})
578
576
  return self
579
577
 
578
+ @min_nuclio_versions("1.12.10")
580
579
  def deploy(
581
580
  self,
582
581
  project="",
@@ -644,9 +643,12 @@ class ServingRuntime(RemoteRuntime):
644
643
 
645
644
  def _get_serving_spec(self):
646
645
  function_name_uri_map = {f.name: f.uri(self) for f in self.spec.function_refs}
647
-
648
646
  serving_spec = {
647
+ "function_name": self.metadata.name,
648
+ "function_tag": self.metadata.tag,
649
649
  "function_uri": self._function_uri(),
650
+ "function_hash": self.metadata.hash,
651
+ "project": self.metadata.project,
650
652
  "version": "v2",
651
653
  "parameters": self.spec.parameters,
652
654
  "graph": self.spec.graph.to_dict() if self.spec.graph else {},
@@ -707,6 +709,9 @@ class ServingRuntime(RemoteRuntime):
707
709
  function_uri=self._function_uri(),
708
710
  secret_sources=self.spec.secret_sources,
709
711
  default_content_type=self.spec.default_content_type,
712
+ function_name=self.metadata.name,
713
+ function_tag=self.metadata.tag,
714
+ project=self.metadata.project,
710
715
  **kwargs,
711
716
  )
712
717
  server.init_states(