mlrun 1.10.0rc16__py3-none-any.whl → 1.10.1rc4__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 +34 -21
- mlrun/datastore/__init__.py +11 -3
- mlrun/datastore/azure_blob.py +162 -47
- mlrun/datastore/base.py +265 -7
- mlrun/datastore/datastore.py +10 -5
- mlrun/datastore/datastore_profile.py +61 -5
- mlrun/datastore/model_provider/huggingface_provider.py +367 -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/store_resources.py +4 -4
- 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 +388 -138
- 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 +16 -11
- mlrun/projects/pipelines.py +2 -2
- mlrun/projects/project.py +157 -69
- mlrun/run.py +97 -20
- 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 +72 -27
- mlrun/runtimes/nuclio/serving.py +102 -20
- 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 +230 -40
- mlrun/serving/states.py +605 -232
- mlrun/serving/steps.py +62 -0
- mlrun/serving/system_steps.py +136 -81
- mlrun/serving/v2_serving.py +9 -10
- mlrun/utils/helpers.py +215 -83
- 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/mail.py +38 -15
- 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.1rc4.dist-info}/METADATA +51 -50
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.1rc4.dist-info}/RECORD +100 -95
- mlrun/api/schemas/__init__.py +0 -259
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.1rc4.dist-info}/WHEEL +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.1rc4.dist-info}/entry_points.txt +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.1rc4.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.1rc4.dist-info}/top_level.txt +0 -0
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:
|
|
@@ -316,7 +345,7 @@ def get_or_create_ctx(
|
|
|
316
345
|
def import_function(url="", secrets=None, db="", project=None, new_name=None):
|
|
317
346
|
"""Create function object from DB or local/remote YAML file
|
|
318
347
|
|
|
319
|
-
Functions can be imported from function repositories (
|
|
348
|
+
Functions can be imported from function repositories (MLRun Hub) or local db),
|
|
320
349
|
or be read from a remote URL (http(s), s3, git, v3io, ..) containing the function YAML
|
|
321
350
|
|
|
322
351
|
special URLs::
|
|
@@ -332,7 +361,7 @@ def import_function(url="", secrets=None, db="", project=None, new_name=None):
|
|
|
332
361
|
"https://raw.githubusercontent.com/org/repo/func.yaml"
|
|
333
362
|
)
|
|
334
363
|
|
|
335
|
-
:param url: path/url to
|
|
364
|
+
:param url: path/url to MLRun Hub, db or function YAML file
|
|
336
365
|
:param secrets: optional, credentials dict for DB or URL (s3, v3io, ...)
|
|
337
366
|
:param db: optional, mlrun api/db path
|
|
338
367
|
:param project: optional, target project for the function
|
|
@@ -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,
|
|
@@ -638,7 +692,7 @@ def code_to_function(
|
|
|
638
692
|
:param description: short function description, defaults to ''
|
|
639
693
|
:param requirements: a list of python packages
|
|
640
694
|
:param requirements_file: path to a python requirements file
|
|
641
|
-
:param categories: list of categories for
|
|
695
|
+
:param categories: list of categories for MLRun Hub, defaults to None
|
|
642
696
|
:param labels: name/value pairs dict to tag the function with useful metadata, defaults to None
|
|
643
697
|
:param with_doc: indicates whether to document the function parameters, defaults to True
|
|
644
698
|
:param ignored_tags: notebook cells to ignore when converting notebooks to py code (separated by ';')
|
|
@@ -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
|
"""
|
mlrun/runtimes/base.py
CHANGED
|
@@ -142,9 +142,6 @@ class FunctionSpec(ModelObj):
|
|
|
142
142
|
def build(self, build):
|
|
143
143
|
self._build = self._verify_dict(build, "build", ImageBuilder)
|
|
144
144
|
|
|
145
|
-
def enrich_function_preemption_spec(self):
|
|
146
|
-
pass
|
|
147
|
-
|
|
148
145
|
def validate_service_account(self, allowed_service_accounts):
|
|
149
146
|
pass
|
|
150
147
|
|
|
@@ -379,7 +376,12 @@ class BaseRuntime(ModelObj):
|
|
|
379
376
|
This ensures latest code changes are executed. This argument must be used in
|
|
380
377
|
conjunction with the local=True argument.
|
|
381
378
|
:param output_path: Default artifact output path.
|
|
382
|
-
:param retry: Retry configuration for the run, can be a dict or an instance of
|
|
379
|
+
:param retry: Retry configuration for the run, can be a dict or an instance of
|
|
380
|
+
:py:class:`~mlrun.model.Retry`.
|
|
381
|
+
The `count` field in the `Retry` object specifies the number of retry attempts.
|
|
382
|
+
If `count=0`, the run will not be retried.
|
|
383
|
+
The `backoff` field specifies the retry backoff strategy between retry attempts.
|
|
384
|
+
If not provided, the default backoff delay is 30 seconds.
|
|
383
385
|
:return: Run context object (RunObject) with run metadata, results and status
|
|
384
386
|
"""
|
|
385
387
|
if artifact_path or out_path:
|
|
@@ -391,6 +393,7 @@ class BaseRuntime(ModelObj):
|
|
|
391
393
|
FutureWarning,
|
|
392
394
|
)
|
|
393
395
|
output_path = output_path or out_path or artifact_path
|
|
396
|
+
|
|
394
397
|
launcher = mlrun.launcher.factory.LauncherFactory().create_launcher(
|
|
395
398
|
self._is_remote, local=local, **launcher_kwargs
|
|
396
399
|
)
|
|
@@ -446,15 +449,20 @@ class BaseRuntime(ModelObj):
|
|
|
446
449
|
:param runobj: Run context object (RunObject) with run metadata and status
|
|
447
450
|
:return: Dictionary with all the variables that could be parsed
|
|
448
451
|
"""
|
|
452
|
+
active_project = self.metadata.project or config.active_project
|
|
449
453
|
runtime_env = {
|
|
450
|
-
|
|
454
|
+
mlrun_constants.MLRUN_ACTIVE_PROJECT: active_project,
|
|
455
|
+
# TODO: Remove this in 1.12.0 as MLRUN_DEFAULT_PROJECT is deprecated and should not be injected anymore
|
|
456
|
+
"MLRUN_DEFAULT_PROJECT": active_project,
|
|
451
457
|
}
|
|
452
458
|
if runobj:
|
|
453
459
|
runtime_env["MLRUN_EXEC_CONFIG"] = runobj.to_json(
|
|
454
460
|
exclude_notifications_params=True
|
|
455
461
|
)
|
|
456
462
|
if runobj.metadata.project:
|
|
457
|
-
runtime_env[
|
|
463
|
+
runtime_env[mlrun_constants.MLRUN_ACTIVE_PROJECT] = (
|
|
464
|
+
runobj.metadata.project
|
|
465
|
+
)
|
|
458
466
|
if runobj.spec.verbose:
|
|
459
467
|
runtime_env["MLRUN_LOG_LEVEL"] = "DEBUG"
|
|
460
468
|
if config.httpdb.api_url:
|
mlrun/runtimes/daskjob.py
CHANGED
mlrun/runtimes/local.py
CHANGED
|
@@ -29,12 +29,12 @@ from os import environ, remove
|
|
|
29
29
|
from pathlib import Path
|
|
30
30
|
from subprocess import PIPE, Popen
|
|
31
31
|
from sys import executable
|
|
32
|
+
from typing import Optional
|
|
32
33
|
|
|
33
34
|
from nuclio import Event
|
|
34
35
|
|
|
35
36
|
import mlrun
|
|
36
37
|
import mlrun.common.constants as mlrun_constants
|
|
37
|
-
import mlrun.common.runtimes.constants
|
|
38
38
|
from mlrun.lists import RunList
|
|
39
39
|
|
|
40
40
|
from ..errors import err_to_str
|
|
@@ -201,9 +201,12 @@ class LocalRuntime(BaseRuntime, ParallelRunner):
|
|
|
201
201
|
kind = "local"
|
|
202
202
|
_is_remote = False
|
|
203
203
|
|
|
204
|
-
def to_job(self, image=""):
|
|
204
|
+
def to_job(self, image="", func_name: Optional[str] = None):
|
|
205
205
|
struct = self.to_dict()
|
|
206
206
|
obj = KubejobRuntime.from_dict(struct)
|
|
207
|
+
obj.kind = "job" # Ensure kind is set to 'job' for KubejobRuntime
|
|
208
|
+
if func_name:
|
|
209
|
+
obj.metadata.name = func_name
|
|
207
210
|
if image:
|
|
208
211
|
obj.spec.image = image
|
|
209
212
|
return obj
|
mlrun/runtimes/mounts.py
CHANGED
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
16
|
import typing
|
|
17
|
+
import warnings
|
|
17
18
|
from collections import namedtuple
|
|
18
19
|
|
|
20
|
+
import mlrun.common.secrets
|
|
21
|
+
import mlrun.errors
|
|
19
22
|
from mlrun.config import config
|
|
20
23
|
from mlrun.config import config as mlconf
|
|
21
24
|
from mlrun.errors import MLRunInvalidArgumentError
|
|
@@ -247,10 +250,22 @@ def mount_s3(
|
|
|
247
250
|
def _use_s3_cred(runtime: "KubeResource"):
|
|
248
251
|
_access_key = aws_access_key or os.environ.get(prefix + "AWS_ACCESS_KEY_ID")
|
|
249
252
|
_secret_key = aws_secret_key or os.environ.get(prefix + "AWS_SECRET_ACCESS_KEY")
|
|
250
|
-
|
|
253
|
+
|
|
254
|
+
# Check for endpoint URL with backward compatibility
|
|
255
|
+
_endpoint_url = endpoint_url or os.environ.get(prefix + "AWS_ENDPOINT_URL_S3")
|
|
256
|
+
if not _endpoint_url:
|
|
257
|
+
# Check for deprecated environment variable
|
|
258
|
+
_endpoint_url = os.environ.get(prefix + "S3_ENDPOINT_URL")
|
|
259
|
+
if _endpoint_url:
|
|
260
|
+
warnings.warn(
|
|
261
|
+
"S3_ENDPOINT_URL is deprecated in 1.10.0 and will be removed in 1.12.0, "
|
|
262
|
+
"use AWS_ENDPOINT_URL_S3 instead.",
|
|
263
|
+
# TODO: Remove this in 1.12.0
|
|
264
|
+
FutureWarning,
|
|
265
|
+
)
|
|
251
266
|
|
|
252
267
|
if _endpoint_url:
|
|
253
|
-
runtime.set_env(prefix + "
|
|
268
|
+
runtime.set_env(prefix + "AWS_ENDPOINT_URL_S3", _endpoint_url)
|
|
254
269
|
if aws_region:
|
|
255
270
|
runtime.set_env(prefix + "AWS_REGION", aws_region)
|
|
256
271
|
if non_anonymous:
|
|
@@ -399,6 +414,9 @@ def mount_secret(
|
|
|
399
414
|
the specified paths, and unlisted keys will not be
|
|
400
415
|
present."""
|
|
401
416
|
|
|
417
|
+
if secret_name:
|
|
418
|
+
mlrun.common.secrets.validate_not_forbidden_secret(secret_name.strip())
|
|
419
|
+
|
|
402
420
|
def _mount_secret(runtime: "KubeResource"):
|
|
403
421
|
# Define the secret volume source
|
|
404
422
|
secret_volume_source = {
|
|
@@ -16,6 +16,7 @@ from .serving import ServingRuntime, new_v2_model_server # noqa
|
|
|
16
16
|
from .nuclio import nuclio_init_hook # noqa
|
|
17
17
|
from .function import (
|
|
18
18
|
min_nuclio_versions,
|
|
19
|
+
multiple_port_sidecar_is_supported,
|
|
19
20
|
RemoteRuntime,
|
|
20
21
|
) # noqa
|
|
21
22
|
from .api_gateway import APIGateway
|