mlrun 1.10.0rc16__py3-none-any.whl → 1.10.0rc42__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +22 -2
- mlrun/artifacts/document.py +6 -1
- mlrun/artifacts/llm_prompt.py +21 -15
- mlrun/artifacts/model.py +3 -3
- mlrun/common/constants.py +9 -0
- mlrun/common/formatters/artifact.py +1 -0
- mlrun/common/model_monitoring/helpers.py +86 -0
- mlrun/common/schemas/__init__.py +2 -0
- mlrun/common/schemas/auth.py +2 -0
- mlrun/common/schemas/function.py +10 -0
- mlrun/common/schemas/hub.py +30 -18
- mlrun/common/schemas/model_monitoring/__init__.py +2 -0
- mlrun/common/schemas/model_monitoring/constants.py +30 -6
- mlrun/common/schemas/model_monitoring/functions.py +13 -4
- mlrun/common/schemas/model_monitoring/model_endpoints.py +11 -0
- mlrun/common/schemas/pipeline.py +1 -1
- mlrun/common/schemas/serving.py +3 -0
- mlrun/common/schemas/workflow.py +1 -0
- mlrun/common/secrets.py +22 -1
- mlrun/config.py +32 -10
- mlrun/datastore/__init__.py +11 -3
- mlrun/datastore/azure_blob.py +162 -47
- mlrun/datastore/datastore.py +9 -4
- mlrun/datastore/datastore_profile.py +61 -5
- mlrun/datastore/model_provider/huggingface_provider.py +363 -0
- mlrun/datastore/model_provider/mock_model_provider.py +87 -0
- mlrun/datastore/model_provider/model_provider.py +211 -74
- mlrun/datastore/model_provider/openai_provider.py +243 -71
- mlrun/datastore/s3.py +24 -2
- mlrun/datastore/storeytargets.py +2 -3
- mlrun/datastore/utils.py +15 -3
- mlrun/db/base.py +27 -19
- mlrun/db/httpdb.py +57 -48
- mlrun/db/nopdb.py +25 -10
- mlrun/execution.py +55 -13
- mlrun/hub/__init__.py +15 -0
- mlrun/hub/module.py +181 -0
- mlrun/k8s_utils.py +105 -16
- mlrun/launcher/base.py +13 -6
- mlrun/launcher/local.py +2 -0
- mlrun/model.py +9 -3
- mlrun/model_monitoring/api.py +66 -27
- mlrun/model_monitoring/applications/__init__.py +1 -1
- mlrun/model_monitoring/applications/base.py +372 -136
- mlrun/model_monitoring/applications/context.py +2 -4
- mlrun/model_monitoring/applications/results.py +4 -7
- mlrun/model_monitoring/controller.py +239 -101
- mlrun/model_monitoring/db/_schedules.py +36 -13
- mlrun/model_monitoring/db/_stats.py +4 -3
- mlrun/model_monitoring/db/tsdb/base.py +29 -9
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +4 -5
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +154 -50
- mlrun/model_monitoring/db/tsdb/tdengine/writer_graph_steps.py +51 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +17 -4
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +245 -51
- mlrun/model_monitoring/helpers.py +28 -5
- mlrun/model_monitoring/stream_processing.py +45 -14
- mlrun/model_monitoring/writer.py +220 -1
- mlrun/platforms/__init__.py +3 -2
- mlrun/platforms/iguazio.py +7 -3
- mlrun/projects/operations.py +6 -1
- mlrun/projects/pipelines.py +2 -2
- mlrun/projects/project.py +128 -45
- mlrun/run.py +94 -17
- mlrun/runtimes/__init__.py +18 -0
- mlrun/runtimes/base.py +14 -6
- mlrun/runtimes/daskjob.py +1 -0
- mlrun/runtimes/local.py +5 -2
- mlrun/runtimes/mounts.py +20 -2
- mlrun/runtimes/nuclio/__init__.py +1 -0
- mlrun/runtimes/nuclio/application/application.py +147 -17
- mlrun/runtimes/nuclio/function.py +70 -27
- mlrun/runtimes/nuclio/serving.py +85 -4
- mlrun/runtimes/pod.py +213 -21
- mlrun/runtimes/utils.py +49 -9
- mlrun/secrets.py +54 -13
- mlrun/serving/remote.py +79 -6
- mlrun/serving/routers.py +23 -41
- mlrun/serving/server.py +211 -40
- mlrun/serving/states.py +536 -156
- mlrun/serving/steps.py +62 -0
- mlrun/serving/system_steps.py +136 -81
- mlrun/serving/v2_serving.py +9 -10
- mlrun/utils/helpers.py +212 -82
- mlrun/utils/logger.py +3 -1
- mlrun/utils/notifications/notification/base.py +18 -0
- mlrun/utils/notifications/notification/git.py +2 -4
- mlrun/utils/notifications/notification/slack.py +2 -4
- mlrun/utils/notifications/notification/webhook.py +2 -5
- mlrun/utils/notifications/notification_pusher.py +1 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/METADATA +44 -45
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/RECORD +97 -92
- mlrun/api/schemas/__init__.py +0 -259
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/WHEEL +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/entry_points.txt +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/top_level.txt +0 -0
mlrun/projects/project.py
CHANGED
|
@@ -45,6 +45,7 @@ import mlrun.common.runtimes.constants
|
|
|
45
45
|
import mlrun.common.schemas.alert
|
|
46
46
|
import mlrun.common.schemas.artifact
|
|
47
47
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
48
|
+
import mlrun.common.secrets
|
|
48
49
|
import mlrun.datastore.datastore_profile
|
|
49
50
|
import mlrun.db
|
|
50
51
|
import mlrun.errors
|
|
@@ -1888,7 +1889,7 @@ class MlrunProject(ModelObj):
|
|
|
1888
1889
|
prompt_path: Optional[str] = None,
|
|
1889
1890
|
prompt_legend: Optional[dict] = None,
|
|
1890
1891
|
model_artifact: Union[ModelArtifact, str] = None,
|
|
1891
|
-
|
|
1892
|
+
invocation_config: Optional[dict] = None,
|
|
1892
1893
|
description: Optional[str] = None,
|
|
1893
1894
|
target_path: Optional[str] = None,
|
|
1894
1895
|
artifact_path: Optional[str] = None,
|
|
@@ -1908,13 +1909,51 @@ class MlrunProject(ModelObj):
|
|
|
1908
1909
|
|
|
1909
1910
|
Examples::
|
|
1910
1911
|
|
|
1912
|
+
# Log directly with an inline prompt template
|
|
1913
|
+
project.log_llm_prompt(
|
|
1914
|
+
key="customer_support_prompt",
|
|
1915
|
+
prompt_template=[
|
|
1916
|
+
{
|
|
1917
|
+
"role": "system",
|
|
1918
|
+
"content": "You are a helpful customer support assistant.",
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
"role": "user",
|
|
1922
|
+
"content": "The customer reports: {issue_description}",
|
|
1923
|
+
},
|
|
1924
|
+
],
|
|
1925
|
+
prompt_legend={
|
|
1926
|
+
"issue_description": {
|
|
1927
|
+
"field": "user_issue",
|
|
1928
|
+
"description": "Detailed description of the customer's issue",
|
|
1929
|
+
},
|
|
1930
|
+
"solution": {
|
|
1931
|
+
"field": "proposed_solution",
|
|
1932
|
+
"description": "Suggested fix for the customer's issue",
|
|
1933
|
+
},
|
|
1934
|
+
},
|
|
1935
|
+
model_artifact=model,
|
|
1936
|
+
invocation_config={"temperature": 0.5, "max_tokens": 200},
|
|
1937
|
+
description="Prompt for handling customer support queries",
|
|
1938
|
+
tag="support-v1",
|
|
1939
|
+
labels={"domain": "support"},
|
|
1940
|
+
)
|
|
1941
|
+
|
|
1911
1942
|
# Log a prompt from file
|
|
1912
1943
|
project.log_llm_prompt(
|
|
1913
|
-
key="
|
|
1914
|
-
prompt_path="prompts/
|
|
1915
|
-
prompt_legend={
|
|
1944
|
+
key="qa_prompt",
|
|
1945
|
+
prompt_path="prompts/template.json",
|
|
1946
|
+
prompt_legend={
|
|
1947
|
+
"question": {
|
|
1948
|
+
"field": "user_question",
|
|
1949
|
+
"description": "The actual question asked by the user",
|
|
1950
|
+
}
|
|
1951
|
+
},
|
|
1916
1952
|
model_artifact=model,
|
|
1953
|
+
invocation_config={"temperature": 0.7, "max_tokens": 256},
|
|
1954
|
+
description="Q&A prompt template with user-provided question",
|
|
1917
1955
|
tag="v2",
|
|
1956
|
+
labels={"task": "qa", "stage": "experiment"},
|
|
1918
1957
|
)
|
|
1919
1958
|
|
|
1920
1959
|
:param key: Unique key for the prompt artifact.
|
|
@@ -1923,18 +1962,23 @@ class MlrunProject(ModelObj):
|
|
|
1923
1962
|
"role": "user", "content": "I need your help with {profession}"]. only "role" and "content" keys allow in any
|
|
1924
1963
|
str format (upper/lower case), keys will be modified to lower case.
|
|
1925
1964
|
Cannot be used with `prompt_path`.
|
|
1926
|
-
:param prompt_path: Path to a file containing the prompt.
|
|
1965
|
+
:param prompt_path: Path to a JSON file containing the prompt template.
|
|
1966
|
+
Cannot be used together with `prompt_template`.
|
|
1967
|
+
The file should define a list of dictionaries in the same format
|
|
1968
|
+
supported by `prompt_template`.
|
|
1927
1969
|
:param prompt_legend: A dictionary where each key is a placeholder in the prompt (e.g., ``{user_name}``)
|
|
1928
1970
|
and the value is a dictionary holding two keys, "field", "description". "field" points to the field in
|
|
1929
1971
|
the event where the value of the place-holder inside the event, if None or not exist will be replaced
|
|
1930
1972
|
with the place-holder name. "description" will point to explanation of what that placeholder represents.
|
|
1931
1973
|
Useful for documenting and clarifying dynamic parts of the prompt.
|
|
1932
1974
|
:param model_artifact: Reference to the parent model (either `ModelArtifact` or model URI string).
|
|
1933
|
-
:param
|
|
1975
|
+
:param invocation_config: Configuration dictionary for model generation parameters
|
|
1934
1976
|
(e.g., temperature, max tokens).
|
|
1935
|
-
:param description:
|
|
1936
|
-
:param target_path:
|
|
1937
|
-
:param artifact_path:
|
|
1977
|
+
:param description: Optional description of the prompt.
|
|
1978
|
+
:param target_path: Absolute target path (instead of using artifact_path + local_path)
|
|
1979
|
+
:param artifact_path: Target artifact path (when not using the default)
|
|
1980
|
+
To define a subpath under the default location use:
|
|
1981
|
+
`artifact_path=context.artifact_subpath('data')`
|
|
1938
1982
|
:param tag: Version tag for the artifact (e.g., "v1", "latest").
|
|
1939
1983
|
:param labels: Labels to tag the artifact for filtering and organization.
|
|
1940
1984
|
:param upload: Whether to upload the artifact to a remote datastore. Defaults to True.
|
|
@@ -1955,7 +1999,7 @@ class MlrunProject(ModelObj):
|
|
|
1955
1999
|
prompt_path=prompt_path,
|
|
1956
2000
|
prompt_legend=prompt_legend,
|
|
1957
2001
|
model_artifact=model_artifact,
|
|
1958
|
-
|
|
2002
|
+
invocation_config=invocation_config,
|
|
1959
2003
|
target_path=target_path,
|
|
1960
2004
|
description=description,
|
|
1961
2005
|
**kwargs,
|
|
@@ -2343,8 +2387,9 @@ class MlrunProject(ModelObj):
|
|
|
2343
2387
|
handler: Optional[str] = None,
|
|
2344
2388
|
with_repo: Optional[bool] = None,
|
|
2345
2389
|
tag: Optional[str] = None,
|
|
2346
|
-
requirements: Optional[
|
|
2390
|
+
requirements: Optional[list[str]] = None,
|
|
2347
2391
|
requirements_file: str = "",
|
|
2392
|
+
local_path: Optional[str] = None,
|
|
2348
2393
|
**application_kwargs,
|
|
2349
2394
|
) -> mlrun.runtimes.RemoteRuntime:
|
|
2350
2395
|
"""
|
|
@@ -2359,7 +2404,8 @@ class MlrunProject(ModelObj):
|
|
|
2359
2404
|
)
|
|
2360
2405
|
|
|
2361
2406
|
:param func: Remote function object or spec/code URL. :code:`None` refers to the current
|
|
2362
|
-
notebook.
|
|
2407
|
+
notebook. May also be a hub URL of a module of kind model-monitoring-app in the
|
|
2408
|
+
format: hub://[{source}/]{name}[:{tag}].
|
|
2363
2409
|
:param name: Name of the function (under the project), can be specified with a tag to support
|
|
2364
2410
|
versions (e.g. myfunc:v1).
|
|
2365
2411
|
:param image: Docker image to be used, can also be specified in
|
|
@@ -2374,6 +2420,8 @@ class MlrunProject(ModelObj):
|
|
|
2374
2420
|
:param application_class: Name or an Instance of a class that implements the monitoring application.
|
|
2375
2421
|
:param application_kwargs: Additional keyword arguments to be passed to the
|
|
2376
2422
|
monitoring application's constructor.
|
|
2423
|
+
:param local_path: Path to a local directory to save the downloaded monitoring-app code files in,
|
|
2424
|
+
in case 'func' is a hub URL (defaults to current working directory).
|
|
2377
2425
|
:returns: The model monitoring remote function object.
|
|
2378
2426
|
"""
|
|
2379
2427
|
(
|
|
@@ -2390,6 +2438,7 @@ class MlrunProject(ModelObj):
|
|
|
2390
2438
|
tag,
|
|
2391
2439
|
requirements,
|
|
2392
2440
|
requirements_file,
|
|
2441
|
+
local_path,
|
|
2393
2442
|
**application_kwargs,
|
|
2394
2443
|
)
|
|
2395
2444
|
# save to project spec
|
|
@@ -2468,8 +2517,9 @@ class MlrunProject(ModelObj):
|
|
|
2468
2517
|
handler: typing.Optional[str] = None,
|
|
2469
2518
|
with_repo: typing.Optional[bool] = None,
|
|
2470
2519
|
tag: typing.Optional[str] = None,
|
|
2471
|
-
requirements: typing.Union[
|
|
2520
|
+
requirements: typing.Union[list[str], None] = None,
|
|
2472
2521
|
requirements_file: str = "",
|
|
2522
|
+
local_path: typing.Optional[str] = None,
|
|
2473
2523
|
**application_kwargs,
|
|
2474
2524
|
) -> tuple[str, mlrun.runtimes.RemoteRuntime, dict]:
|
|
2475
2525
|
import mlrun.model_monitoring.api
|
|
@@ -2486,6 +2536,7 @@ class MlrunProject(ModelObj):
|
|
|
2486
2536
|
tag=tag,
|
|
2487
2537
|
requirements=requirements,
|
|
2488
2538
|
requirements_file=requirements_file,
|
|
2539
|
+
local_path=local_path,
|
|
2489
2540
|
**application_kwargs,
|
|
2490
2541
|
)
|
|
2491
2542
|
elif isinstance(func, str) and isinstance(handler, str):
|
|
@@ -2531,7 +2582,7 @@ class MlrunProject(ModelObj):
|
|
|
2531
2582
|
*,
|
|
2532
2583
|
deploy_histogram_data_drift_app: bool = True,
|
|
2533
2584
|
wait_for_deployment: bool = False,
|
|
2534
|
-
fetch_credentials_from_sys_config: bool = False,
|
|
2585
|
+
fetch_credentials_from_sys_config: bool = False, # deprecated
|
|
2535
2586
|
) -> None:
|
|
2536
2587
|
"""
|
|
2537
2588
|
Deploy model monitoring application controller, writer and stream functions.
|
|
@@ -2566,14 +2617,20 @@ class MlrunProject(ModelObj):
|
|
|
2566
2617
|
:param wait_for_deployment: If true, return only after the deployment is done on the backend.
|
|
2567
2618
|
Otherwise, deploy the model monitoring infrastructure on the
|
|
2568
2619
|
background, including the histogram data drift app if selected.
|
|
2569
|
-
:param fetch_credentials_from_sys_config: If true, fetch the credentials from the
|
|
2620
|
+
:param fetch_credentials_from_sys_config: Deprecated. If true, fetch the credentials from the project
|
|
2621
|
+
configuration.
|
|
2570
2622
|
"""
|
|
2623
|
+
if fetch_credentials_from_sys_config:
|
|
2624
|
+
warnings.warn(
|
|
2625
|
+
"`fetch_credentials_from_sys_config` is deprecated in 1.10.0 and will be removed in 1.12.0.",
|
|
2626
|
+
# TODO: Remove this in 1.12.0
|
|
2627
|
+
FutureWarning,
|
|
2628
|
+
)
|
|
2571
2629
|
if base_period < 10:
|
|
2572
2630
|
logger.warn(
|
|
2573
2631
|
"enable_model_monitoring: 'base_period' < 10 minutes is not supported in production environments",
|
|
2574
2632
|
project=self.name,
|
|
2575
2633
|
)
|
|
2576
|
-
|
|
2577
2634
|
db = mlrun.db.get_run_db(secrets=self._secrets)
|
|
2578
2635
|
db.enable_model_monitoring(
|
|
2579
2636
|
project=self.name,
|
|
@@ -2706,16 +2763,18 @@ class MlrunProject(ModelObj):
|
|
|
2706
2763
|
| Creating a function with non project source is done by specifying a module ``handler`` and on the
|
|
2707
2764
|
returned function set the source with ``function.with_source_archive(<source>)``.
|
|
2708
2765
|
|
|
2709
|
-
|
|
2766
|
+
Supported URL prefixes:
|
|
2710
2767
|
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2768
|
+
- Object: s3://, v3io://, etc.
|
|
2769
|
+
- MLRun DB: e.g db://project/func:ver
|
|
2770
|
+
- Function hub/market: e.g. hub://auto-trainer:master
|
|
2714
2771
|
|
|
2715
2772
|
Examples::
|
|
2716
2773
|
|
|
2717
2774
|
proj.set_function(func_object)
|
|
2718
|
-
proj.set_function(
|
|
2775
|
+
proj.set_function(
|
|
2776
|
+
"http://.../mynb.ipynb", "train", kind="job", image="mlrun/mlrun"
|
|
2777
|
+
)
|
|
2719
2778
|
proj.set_function("./func.yaml")
|
|
2720
2779
|
proj.set_function("hub://get_toy_data", "getdata")
|
|
2721
2780
|
|
|
@@ -2742,18 +2801,6 @@ class MlrunProject(ModelObj):
|
|
|
2742
2801
|
# By providing a path to a pip requirements file
|
|
2743
2802
|
proj.set_function("my.py", requirements="requirements.txt")
|
|
2744
2803
|
|
|
2745
|
-
One of the most important parameters is 'kind', used to specify the chosen runtime. The options are:
|
|
2746
|
-
- local: execute a local python or shell script
|
|
2747
|
-
- job: insert the code into a Kubernetes pod and execute it
|
|
2748
|
-
- nuclio: insert the code into a real-time serverless nuclio function
|
|
2749
|
-
- serving: insert code into orchestrated nuclio function(s) forming a DAG
|
|
2750
|
-
- dask: run the specified python code / script as Dask Distributed job
|
|
2751
|
-
- mpijob: run distributed Horovod jobs over the MPI job operator
|
|
2752
|
-
- spark: run distributed Spark job using Spark Kubernetes Operator
|
|
2753
|
-
- remote-spark: run distributed Spark job on remote Spark service
|
|
2754
|
-
- databricks: run code on Databricks cluster (python scripts, Spark etc.)
|
|
2755
|
-
- application: run a long living application (e.g. a web server, UI, etc.)
|
|
2756
|
-
|
|
2757
2804
|
Learn more about :doc:`../../concepts/functions-overview`.
|
|
2758
2805
|
|
|
2759
2806
|
:param func: Function object or spec/code url, None refers to current Notebook
|
|
@@ -2761,8 +2808,20 @@ class MlrunProject(ModelObj):
|
|
|
2761
2808
|
Versions (e.g. myfunc:v1). If the `tag` parameter is provided, the tag in the name
|
|
2762
2809
|
must match the tag parameter.
|
|
2763
2810
|
Specifying a tag in the name will update the project's tagged function (myfunc:v1)
|
|
2764
|
-
:param kind:
|
|
2765
|
-
|
|
2811
|
+
:param kind: Default: job. One of
|
|
2812
|
+
|
|
2813
|
+
- local: execute a local python or shell script
|
|
2814
|
+
- job: insert the code into a Kubernetes pod and execute it
|
|
2815
|
+
- nuclio: insert the code into a real-time serverless nuclio function
|
|
2816
|
+
- serving: insert code into orchestrated nuclio function(s) forming a DAG
|
|
2817
|
+
- dask: run the specified python code / script as Dask Distributed job
|
|
2818
|
+
- mpijob: run distributed Horovod jobs over the MPI job operator
|
|
2819
|
+
- spark: run distributed Spark job using Spark Kubernetes Operator
|
|
2820
|
+
- remote-spark: run distributed Spark job on remote Spark service
|
|
2821
|
+
- databricks: run code on Databricks cluster (python scripts, Spark etc.)
|
|
2822
|
+
- application: run a long living application (e.g. a web server, UI, etc.)
|
|
2823
|
+
- handler: execute a python handler (used automatically in notebooks or for debug)
|
|
2824
|
+
|
|
2766
2825
|
:param image: Docker image to be used, can also be specified in the function object/yaml
|
|
2767
2826
|
:param handler: Default function handler to invoke (can only be set with .py/.ipynb files)
|
|
2768
2827
|
:param with_repo: Add (clone) the current repo to the build source - use when the function code is in
|
|
@@ -3360,7 +3419,12 @@ class MlrunProject(ModelObj):
|
|
|
3360
3419
|
self._initialized = True
|
|
3361
3420
|
return self.spec._function_objects
|
|
3362
3421
|
|
|
3363
|
-
def with_secrets(
|
|
3422
|
+
def with_secrets(
|
|
3423
|
+
self,
|
|
3424
|
+
kind,
|
|
3425
|
+
source,
|
|
3426
|
+
prefix="",
|
|
3427
|
+
):
|
|
3364
3428
|
"""register a secrets source (file, env or dict)
|
|
3365
3429
|
|
|
3366
3430
|
read secrets from a source provider to be used in workflows, example::
|
|
@@ -3382,12 +3446,19 @@ class MlrunProject(ModelObj):
|
|
|
3382
3446
|
|
|
3383
3447
|
This will enable access to all secrets in vault registered to the current project.
|
|
3384
3448
|
|
|
3385
|
-
:param kind: secret type (file, inline, env, vault)
|
|
3449
|
+
:param kind: secret type (file, inline, env, vault, azure_vault)
|
|
3386
3450
|
:param source: secret data or link (see example)
|
|
3387
3451
|
:param prefix: add a prefix to the keys in this source
|
|
3388
3452
|
|
|
3389
3453
|
:returns: project object
|
|
3390
3454
|
"""
|
|
3455
|
+
# Block using mlrun-auth-secrets.* via azure_vault's k8s_secret param (client-side only)
|
|
3456
|
+
if kind == "azure_vault" and isinstance(source, dict):
|
|
3457
|
+
candidate_secret_name = (source.get("k8s_secret") or "").strip()
|
|
3458
|
+
if candidate_secret_name:
|
|
3459
|
+
mlrun.common.secrets.validate_not_forbidden_secret(
|
|
3460
|
+
candidate_secret_name
|
|
3461
|
+
)
|
|
3391
3462
|
|
|
3392
3463
|
if kind == "vault" and isinstance(source, list):
|
|
3393
3464
|
source = {"project": self.metadata.name, "secrets": source}
|
|
@@ -3771,7 +3842,7 @@ class MlrunProject(ModelObj):
|
|
|
3771
3842
|
|
|
3772
3843
|
import mlrun
|
|
3773
3844
|
from mlrun.datastore.datastore_profile import (
|
|
3774
|
-
|
|
3845
|
+
DatastoreProfileKafkaStream,
|
|
3775
3846
|
DatastoreProfileTDEngine,
|
|
3776
3847
|
)
|
|
3777
3848
|
|
|
@@ -3788,7 +3859,7 @@ class MlrunProject(ModelObj):
|
|
|
3788
3859
|
project.register_datastore_profile(tsdb_profile)
|
|
3789
3860
|
|
|
3790
3861
|
# Create and register stream profile
|
|
3791
|
-
stream_profile =
|
|
3862
|
+
stream_profile = DatastoreProfileKafkaStream(
|
|
3792
3863
|
name="my-kafka",
|
|
3793
3864
|
brokers=["<kafka-broker-ip-address>:9094"],
|
|
3794
3865
|
topics=[], # Keep the topics list empty
|
|
@@ -3830,9 +3901,9 @@ class MlrunProject(ModelObj):
|
|
|
3830
3901
|
|
|
3831
3902
|
.. code-block:: python
|
|
3832
3903
|
|
|
3833
|
-
from mlrun.datastore.datastore_profile import
|
|
3904
|
+
from mlrun.datastore.datastore_profile import DatastoreProfileKafkaStream
|
|
3834
3905
|
|
|
3835
|
-
stream_profile =
|
|
3906
|
+
stream_profile = DatastoreProfileKafkaStream(
|
|
3836
3907
|
name="confluent-kafka",
|
|
3837
3908
|
brokers=["<server-domain-start>.confluent.cloud:9092"],
|
|
3838
3909
|
topics=[],
|
|
@@ -3861,7 +3932,7 @@ class MlrunProject(ModelObj):
|
|
|
3861
3932
|
The supported profiles are:
|
|
3862
3933
|
|
|
3863
3934
|
* :py:class:`~mlrun.datastore.datastore_profile.DatastoreProfileV3io`
|
|
3864
|
-
* :py:class:`~mlrun.datastore.datastore_profile.
|
|
3935
|
+
* :py:class:`~mlrun.datastore.datastore_profile.DatastoreProfileKafkaStream`
|
|
3865
3936
|
|
|
3866
3937
|
You need to register one of them, and pass the profile's name.
|
|
3867
3938
|
:param replace_creds: If ``True`` - override the existing credentials.
|
|
@@ -3901,6 +3972,9 @@ class MlrunProject(ModelObj):
|
|
|
3901
3972
|
start: Optional[datetime.datetime] = None,
|
|
3902
3973
|
end: Optional[datetime.datetime] = None,
|
|
3903
3974
|
top_level: bool = False,
|
|
3975
|
+
modes: Optional[
|
|
3976
|
+
Union[mm_constants.EndpointMode, list[mm_constants.EndpointMode]]
|
|
3977
|
+
] = None,
|
|
3904
3978
|
uids: Optional[list[str]] = None,
|
|
3905
3979
|
latest_only: bool = False,
|
|
3906
3980
|
tsdb_metrics: bool = False,
|
|
@@ -3916,8 +3990,9 @@ class MlrunProject(ModelObj):
|
|
|
3916
3990
|
5) function_tag
|
|
3917
3991
|
6) labels
|
|
3918
3992
|
7) top level
|
|
3919
|
-
8)
|
|
3920
|
-
9)
|
|
3993
|
+
8) modes
|
|
3994
|
+
9) uids
|
|
3995
|
+
10) start and end time, corresponding to the `created` field.
|
|
3921
3996
|
By default, when no filters are applied, all available endpoints for the given project will be listed.
|
|
3922
3997
|
|
|
3923
3998
|
In addition, this functions provides a facade for listing endpoint related metrics. This facade is time-based
|
|
@@ -3937,6 +4012,8 @@ class MlrunProject(ModelObj):
|
|
|
3937
4012
|
:param start: The start time to filter by.Corresponding to the `created` field.
|
|
3938
4013
|
:param end: The end time to filter by. Corresponding to the `created` field.
|
|
3939
4014
|
:param top_level: If true will return only routers and endpoint that are NOT children of any router.
|
|
4015
|
+
:param modes: Specifies the mode of the model endpoint. Can be "real-time" (0), "batch" (1),
|
|
4016
|
+
"batch_legacy" (2). If set to None, all are included.
|
|
3940
4017
|
:param uids: If passed will return a list `ModelEndpoint` object with uid in uids.
|
|
3941
4018
|
:param tsdb_metrics: When True, the time series metrics will be added to the output
|
|
3942
4019
|
of the resulting.
|
|
@@ -3958,6 +4035,7 @@ class MlrunProject(ModelObj):
|
|
|
3958
4035
|
start=start,
|
|
3959
4036
|
end=end,
|
|
3960
4037
|
top_level=top_level,
|
|
4038
|
+
modes=modes,
|
|
3961
4039
|
uids=uids,
|
|
3962
4040
|
latest_only=latest_only,
|
|
3963
4041
|
tsdb_metrics=tsdb_metrics,
|
|
@@ -4052,7 +4130,12 @@ class MlrunProject(ModelObj):
|
|
|
4052
4130
|
This ensures latest code changes are executed. This argument must be used in
|
|
4053
4131
|
conjunction with the local=True argument.
|
|
4054
4132
|
:param output_path: path to store artifacts, when running in a workflow this will be set automatically
|
|
4055
|
-
:param retry: Retry configuration for the run, can be a dict or an instance of
|
|
4133
|
+
:param retry: Retry configuration for the run, can be a dict or an instance of
|
|
4134
|
+
:py:class:`~mlrun.model.Retry`.
|
|
4135
|
+
The `count` field in the `Retry` object specifies the number of retry attempts.
|
|
4136
|
+
If `count=0`, the run will not be retried.
|
|
4137
|
+
The `backoff` field specifies the retry backoff strategy between retry attempts.
|
|
4138
|
+
If not provided, the default backoff delay is 30 seconds.
|
|
4056
4139
|
:return: MLRun RunObject or PipelineNodeWrapper
|
|
4057
4140
|
"""
|
|
4058
4141
|
if artifact_path:
|
mlrun/run.py
CHANGED
|
@@ -17,6 +17,7 @@ import json
|
|
|
17
17
|
import os
|
|
18
18
|
import pathlib
|
|
19
19
|
import socket
|
|
20
|
+
import sys
|
|
20
21
|
import tempfile
|
|
21
22
|
import time
|
|
22
23
|
import typing
|
|
@@ -117,14 +118,31 @@ def function_to_module(code="", workdir=None, secrets=None, silent=False):
|
|
|
117
118
|
raise ValueError("nothing to run, specify command or function")
|
|
118
119
|
|
|
119
120
|
command = os.path.join(workdir or "", command)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
|
|
122
|
+
source_file_path_object, working_dir_path_object = (
|
|
123
|
+
mlrun.utils.helpers.get_source_and_working_dir_paths(command)
|
|
124
|
+
)
|
|
125
|
+
if source_file_path_object.is_relative_to(working_dir_path_object):
|
|
126
|
+
mod_name = mlrun.utils.helpers.get_relative_module_name_from_path(
|
|
127
|
+
source_file_path_object, working_dir_path_object
|
|
128
|
+
)
|
|
129
|
+
elif source_file_path_object.is_relative_to(
|
|
130
|
+
pathlib.Path(tempfile.gettempdir()).resolve()
|
|
131
|
+
):
|
|
132
|
+
mod_name = Path(command).stem
|
|
133
|
+
else:
|
|
134
|
+
raise mlrun.errors.MLRunRuntimeError(
|
|
135
|
+
f"Cannot run source file '{command}': it must be located either under the current working "
|
|
136
|
+
f"directory ('{working_dir_path_object}') or the system temporary directory ('{tempfile.gettempdir()}'). "
|
|
137
|
+
f"This is required when running with local=True."
|
|
138
|
+
)
|
|
139
|
+
|
|
124
140
|
spec = imputil.spec_from_file_location(mod_name, command)
|
|
125
141
|
if spec is None:
|
|
126
142
|
raise OSError(f"cannot import from {command!r}")
|
|
127
143
|
mod = imputil.module_from_spec(spec)
|
|
144
|
+
# add to system modules, which can be necessary when running in a MockServer (ML-10937)
|
|
145
|
+
sys.modules[mod_name] = mod
|
|
128
146
|
spec.loader.exec_module(mod)
|
|
129
147
|
|
|
130
148
|
return mod
|
|
@@ -141,7 +159,7 @@ def load_func_code(command="", workdir=None, secrets=None, name="name"):
|
|
|
141
159
|
else:
|
|
142
160
|
is_remote = "://" in command
|
|
143
161
|
data = get_object(command, secrets)
|
|
144
|
-
runtime = yaml.
|
|
162
|
+
runtime = yaml.safe_load(data)
|
|
145
163
|
runtime = new_function(runtime=runtime)
|
|
146
164
|
|
|
147
165
|
command = runtime.spec.command or ""
|
|
@@ -222,7 +240,8 @@ def get_or_create_ctx(
|
|
|
222
240
|
:param spec: dictionary holding run spec
|
|
223
241
|
:param with_env: look for context in environment vars, default True
|
|
224
242
|
:param rundb: path/url to the metadata and artifact database
|
|
225
|
-
:param project: project to initiate the context in (by default `mlrun.mlconf.active_project`)
|
|
243
|
+
:param project: project to initiate the context in (by default `mlrun.mlconf.active_project`).
|
|
244
|
+
If not set, an active project must exist.
|
|
226
245
|
:param upload_artifacts: when using local context (not as part of a job/run), upload artifacts to the
|
|
227
246
|
system default artifact path location
|
|
228
247
|
:return: execution context
|
|
@@ -277,6 +296,16 @@ def get_or_create_ctx(
|
|
|
277
296
|
if newspec and not isinstance(newspec, dict):
|
|
278
297
|
newspec = json.loads(newspec)
|
|
279
298
|
|
|
299
|
+
if (
|
|
300
|
+
not newspec.get("metadata", {}).get("project")
|
|
301
|
+
and not project
|
|
302
|
+
and not mlconf.active_project
|
|
303
|
+
):
|
|
304
|
+
raise mlrun.errors.MLRunMissingProjectError(
|
|
305
|
+
"""No active project found. Make sure to set an active project using: mlrun.get_or_create_project()
|
|
306
|
+
You can verify the active project with: mlrun.mlconf.active_project"""
|
|
307
|
+
)
|
|
308
|
+
|
|
280
309
|
if not newspec:
|
|
281
310
|
newspec = {}
|
|
282
311
|
if upload_artifacts:
|
|
@@ -362,10 +391,13 @@ def import_function(url="", secrets=None, db="", project=None, new_name=None):
|
|
|
362
391
|
return function
|
|
363
392
|
|
|
364
393
|
|
|
365
|
-
def import_function_to_dict(
|
|
394
|
+
def import_function_to_dict(
|
|
395
|
+
url: str,
|
|
396
|
+
secrets: Optional[dict] = None,
|
|
397
|
+
) -> dict:
|
|
366
398
|
"""Load function spec from local/remote YAML file"""
|
|
367
399
|
obj = get_object(url, secrets)
|
|
368
|
-
runtime = yaml.
|
|
400
|
+
runtime = yaml.safe_load(obj)
|
|
369
401
|
remote = "://" in url
|
|
370
402
|
|
|
371
403
|
code = get_in(runtime, "spec.build.functionSourceCode")
|
|
@@ -388,20 +420,40 @@ def import_function_to_dict(url, secrets=None):
|
|
|
388
420
|
raise ValueError("exec path (spec.command) must be relative")
|
|
389
421
|
url = url[: url.rfind("/") + 1] + code_file
|
|
390
422
|
code = get_object(url, secrets)
|
|
423
|
+
code_file = _ensure_path_confined_to_base_dir(
|
|
424
|
+
base_directory=".",
|
|
425
|
+
relative_path=code_file,
|
|
426
|
+
error_message_on_escape="Path traversal detected in spec.command",
|
|
427
|
+
)
|
|
391
428
|
dir = path.dirname(code_file)
|
|
392
429
|
if dir:
|
|
393
430
|
makedirs(dir, exist_ok=True)
|
|
394
431
|
with open(code_file, "wb") as fp:
|
|
395
432
|
fp.write(code)
|
|
396
433
|
elif cmd:
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
434
|
+
slash_index = url.rfind("/")
|
|
435
|
+
if slash_index < 0:
|
|
436
|
+
raise ValueError(f"no file in exec path (spec.command={code_file})")
|
|
437
|
+
base_dir = os.path.normpath(url[: slash_index + 1])
|
|
438
|
+
|
|
439
|
+
# Validate and resolve the candidate path before checking existence
|
|
440
|
+
candidate_path = _ensure_path_confined_to_base_dir(
|
|
441
|
+
base_directory=base_dir,
|
|
442
|
+
relative_path=code_file,
|
|
443
|
+
error_message_on_escape=(
|
|
444
|
+
f"exec file spec.command={code_file} is outside of allowed directory"
|
|
445
|
+
),
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
# Only now it's safe to check file existence
|
|
449
|
+
if not path.isfile(candidate_path):
|
|
404
450
|
raise ValueError(f"no file in exec path (spec.command={code_file})")
|
|
451
|
+
|
|
452
|
+
# Check that the path is absolute
|
|
453
|
+
if not os.path.isabs(code_file):
|
|
454
|
+
raise ValueError(
|
|
455
|
+
f"exec file spec.command={code_file} is relative, it must be absolute. Change working dir"
|
|
456
|
+
)
|
|
405
457
|
else:
|
|
406
458
|
raise ValueError("command or code not specified in function spec")
|
|
407
459
|
|
|
@@ -503,6 +555,7 @@ def new_function(
|
|
|
503
555
|
|
|
504
556
|
# make sure function name is valid
|
|
505
557
|
name = mlrun.utils.helpers.normalize_name(name)
|
|
558
|
+
mlrun.utils.helpers.validate_function_name(name)
|
|
506
559
|
|
|
507
560
|
runner.metadata.name = name
|
|
508
561
|
runner.metadata.project = (
|
|
@@ -542,6 +595,7 @@ def new_function(
|
|
|
542
595
|
)
|
|
543
596
|
|
|
544
597
|
runner.prepare_image_for_deploy()
|
|
598
|
+
|
|
545
599
|
return runner
|
|
546
600
|
|
|
547
601
|
|
|
@@ -575,7 +629,7 @@ def code_to_function(
|
|
|
575
629
|
code_output: Optional[str] = "",
|
|
576
630
|
embed_code: bool = True,
|
|
577
631
|
description: Optional[str] = "",
|
|
578
|
-
requirements: Optional[
|
|
632
|
+
requirements: Optional[list[str]] = None,
|
|
579
633
|
categories: Optional[list[str]] = None,
|
|
580
634
|
labels: Optional[dict[str, str]] = None,
|
|
581
635
|
with_doc: Optional[bool] = True,
|
|
@@ -746,6 +800,7 @@ def code_to_function(
|
|
|
746
800
|
kind=sub_kind,
|
|
747
801
|
ignored_tags=ignored_tags,
|
|
748
802
|
)
|
|
803
|
+
|
|
749
804
|
spec["spec"]["env"].append(
|
|
750
805
|
{
|
|
751
806
|
"name": "MLRUN_HTTPDB__NUCLIO__EXPLICIT_ACK",
|
|
@@ -798,6 +853,7 @@ def code_to_function(
|
|
|
798
853
|
runtime.spec.build.code_origin = code_origin
|
|
799
854
|
runtime.spec.build.origin_filename = filename or (name + ".ipynb")
|
|
800
855
|
update_common(runtime, spec)
|
|
856
|
+
|
|
801
857
|
return runtime
|
|
802
858
|
|
|
803
859
|
if kind is None or kind in ["", "Function"]:
|
|
@@ -811,6 +867,7 @@ def code_to_function(
|
|
|
811
867
|
|
|
812
868
|
if not name:
|
|
813
869
|
raise ValueError("name must be specified")
|
|
870
|
+
|
|
814
871
|
h = get_in(spec, "spec.handler", "").split(":")
|
|
815
872
|
runtime.handler = h[0] if len(h) <= 1 else h[1]
|
|
816
873
|
runtime.metadata = get_in(spec, "spec.metadata")
|
|
@@ -1184,11 +1241,13 @@ def get_model_provider(
|
|
|
1184
1241
|
raise_missing_schema_exception=True,
|
|
1185
1242
|
) -> ModelProvider:
|
|
1186
1243
|
"""get mlrun dataitem object (from path/url)"""
|
|
1187
|
-
|
|
1244
|
+
# without caching secrets
|
|
1245
|
+
store_manager.set(db=db)
|
|
1188
1246
|
return store_manager.model_provider_object(
|
|
1189
1247
|
url=url,
|
|
1190
1248
|
default_invoke_kwargs=default_invoke_kwargs,
|
|
1191
1249
|
raise_missing_schema_exception=raise_missing_schema_exception,
|
|
1250
|
+
secrets=secrets,
|
|
1192
1251
|
)
|
|
1193
1252
|
|
|
1194
1253
|
|
|
@@ -1256,3 +1315,21 @@ def wait_for_runs_completion(
|
|
|
1256
1315
|
runs = running
|
|
1257
1316
|
|
|
1258
1317
|
return completed
|
|
1318
|
+
|
|
1319
|
+
|
|
1320
|
+
def _ensure_path_confined_to_base_dir(
|
|
1321
|
+
base_directory: str,
|
|
1322
|
+
relative_path: str,
|
|
1323
|
+
error_message_on_escape: str,
|
|
1324
|
+
) -> str:
|
|
1325
|
+
"""
|
|
1326
|
+
Join `user_supplied_relative_path` to `allowed_base_directory`, normalise the result,
|
|
1327
|
+
and guarantee it stays inside `allowed_base_directory`.
|
|
1328
|
+
"""
|
|
1329
|
+
absolute_base_directory = path.abspath(base_directory)
|
|
1330
|
+
absolute_candidate_path = path.abspath(
|
|
1331
|
+
path.join(absolute_base_directory, relative_path)
|
|
1332
|
+
)
|
|
1333
|
+
if not absolute_candidate_path.startswith(absolute_base_directory + path.sep):
|
|
1334
|
+
raise ValueError(error_message_on_escape)
|
|
1335
|
+
return absolute_candidate_path
|
mlrun/runtimes/__init__.py
CHANGED
|
@@ -221,6 +221,24 @@ class RuntimeKinds:
|
|
|
221
221
|
return True
|
|
222
222
|
return False
|
|
223
223
|
|
|
224
|
+
@staticmethod
|
|
225
|
+
def requires_k8s_name_validation(kind: str) -> bool:
|
|
226
|
+
"""
|
|
227
|
+
Returns True if the runtime kind creates Kubernetes resources that use the function name.
|
|
228
|
+
|
|
229
|
+
Function names for k8s-deployed runtimes must conform to DNS-1123 label requirements:
|
|
230
|
+
- Lowercase alphanumeric characters or '-'
|
|
231
|
+
- Start and end with an alphanumeric character
|
|
232
|
+
- Maximum 63 characters
|
|
233
|
+
|
|
234
|
+
Local runtimes (local, handler) run on the local machine and don't create k8s resources,
|
|
235
|
+
so they don't require k8s naming validation.
|
|
236
|
+
|
|
237
|
+
:param kind: Runtime kind string (job, spark, serving, local, etc.)
|
|
238
|
+
:return: True if function name needs k8s DNS-1123 validation, False otherwise
|
|
239
|
+
"""
|
|
240
|
+
return not RuntimeKinds.is_local_runtime(kind)
|
|
241
|
+
|
|
224
242
|
@staticmethod
|
|
225
243
|
def requires_absolute_artifacts_path(kind):
|
|
226
244
|
"""
|