mlrun 1.6.0rc6__py3-none-any.whl → 1.6.0rc8__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/__main__.py +32 -31
- mlrun/common/schemas/auth.py +2 -0
- mlrun/common/schemas/workflow.py +2 -0
- mlrun/config.py +3 -3
- mlrun/datastore/base.py +9 -3
- mlrun/datastore/datastore.py +10 -7
- mlrun/datastore/datastore_profile.py +19 -2
- mlrun/datastore/dbfs_store.py +6 -6
- mlrun/datastore/s3.py +6 -2
- mlrun/datastore/sources.py +12 -2
- mlrun/datastore/targets.py +43 -20
- mlrun/db/httpdb.py +22 -0
- mlrun/feature_store/feature_set.py +5 -2
- mlrun/feature_store/retrieval/spark_merger.py +7 -1
- mlrun/kfpops.py +1 -1
- mlrun/launcher/client.py +1 -6
- mlrun/launcher/remote.py +5 -3
- mlrun/model.py +2 -2
- mlrun/model_monitoring/batch_application.py +61 -94
- mlrun/package/packager.py +115 -89
- mlrun/package/packagers/default_packager.py +66 -65
- mlrun/package/packagers/numpy_packagers.py +109 -62
- mlrun/package/packagers/pandas_packagers.py +12 -23
- mlrun/package/packagers/python_standard_library_packagers.py +35 -57
- mlrun/package/packagers_manager.py +16 -13
- mlrun/package/utils/_pickler.py +8 -18
- mlrun/package/utils/_supported_format.py +1 -1
- mlrun/projects/pipelines.py +63 -4
- mlrun/projects/project.py +34 -11
- mlrun/runtimes/__init__.py +6 -0
- mlrun/runtimes/base.py +12 -1
- mlrun/runtimes/daskjob.py +73 -5
- mlrun/runtimes/databricks_job/databricks_runtime.py +2 -0
- mlrun/runtimes/function.py +53 -4
- mlrun/runtimes/kubejob.py +1 -1
- mlrun/runtimes/local.py +9 -9
- mlrun/runtimes/pod.py +1 -1
- mlrun/runtimes/remotesparkjob.py +1 -0
- mlrun/runtimes/serving.py +11 -1
- mlrun/runtimes/sparkjob/spark3job.py +4 -1
- mlrun/runtimes/utils.py +1 -46
- mlrun/utils/helpers.py +1 -17
- mlrun/utils/notifications/notification_pusher.py +27 -6
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.6.0rc6.dist-info → mlrun-1.6.0rc8.dist-info}/METADATA +7 -6
- {mlrun-1.6.0rc6.dist-info → mlrun-1.6.0rc8.dist-info}/RECORD +50 -50
- {mlrun-1.6.0rc6.dist-info → mlrun-1.6.0rc8.dist-info}/WHEEL +1 -1
- {mlrun-1.6.0rc6.dist-info → mlrun-1.6.0rc8.dist-info}/LICENSE +0 -0
- {mlrun-1.6.0rc6.dist-info → mlrun-1.6.0rc8.dist-info}/entry_points.txt +0 -0
- {mlrun-1.6.0rc6.dist-info → mlrun-1.6.0rc8.dist-info}/top_level.txt +0 -0
mlrun/projects/project.py
CHANGED
|
@@ -87,6 +87,7 @@ from .pipelines import (
|
|
|
87
87
|
FunctionsDict,
|
|
88
88
|
WorkflowSpec,
|
|
89
89
|
_PipelineRunStatus,
|
|
90
|
+
_RemoteRunner,
|
|
90
91
|
enrich_function_object,
|
|
91
92
|
get_db_function,
|
|
92
93
|
get_workflow_engine,
|
|
@@ -102,9 +103,9 @@ def init_repo(context, url, init_git):
|
|
|
102
103
|
repo = None
|
|
103
104
|
context_path = pathlib.Path(context)
|
|
104
105
|
if not context_path.exists():
|
|
105
|
-
context_path.mkdir(parents=True)
|
|
106
|
+
context_path.mkdir(parents=True, exist_ok=True)
|
|
106
107
|
elif not context_path.is_dir():
|
|
107
|
-
raise ValueError(f"
|
|
108
|
+
raise ValueError(f"Context {context} is not a dir path")
|
|
108
109
|
try:
|
|
109
110
|
repo = git.Repo(context)
|
|
110
111
|
url = get_repo_url(repo)
|
|
@@ -221,6 +222,7 @@ def new_project(
|
|
|
221
222
|
if remote and url != remote:
|
|
222
223
|
project.create_remote(remote)
|
|
223
224
|
elif url:
|
|
225
|
+
logger.info("Identified pre-initialized git repo, using it", url=url)
|
|
224
226
|
project.spec._source = url
|
|
225
227
|
project.spec.origin_url = url
|
|
226
228
|
if description:
|
|
@@ -366,7 +368,7 @@ def load_project(
|
|
|
366
368
|
project = _load_project_dir(context, name, subpath)
|
|
367
369
|
|
|
368
370
|
if not project.metadata.name:
|
|
369
|
-
raise ValueError("
|
|
371
|
+
raise ValueError("Project name must be specified")
|
|
370
372
|
|
|
371
373
|
if parameters:
|
|
372
374
|
# Enable setting project parameters at load time, can be used to customize the project_setup
|
|
@@ -1593,7 +1595,7 @@ class MlrunProject(ModelObj):
|
|
|
1593
1595
|
:param parameters: key/value dict of model parameters
|
|
1594
1596
|
:param inputs: ordered list of model input features (name, type, ..)
|
|
1595
1597
|
:param outputs: ordered list of model output/result elements (name, type, ..)
|
|
1596
|
-
:param upload: upload to datastore (
|
|
1598
|
+
:param upload: upload to datastore (if not specified, defaults to True (uploads artifact))
|
|
1597
1599
|
:param labels: a set of key/value labels to tag the artifact with
|
|
1598
1600
|
:param feature_vector: feature store feature vector uri (store://feature-vectors/<project>/<name>[:tag])
|
|
1599
1601
|
:param feature_weights: list of feature weights, one per input column
|
|
@@ -2499,6 +2501,7 @@ class MlrunProject(ModelObj):
|
|
|
2499
2501
|
timeout: int = None,
|
|
2500
2502
|
source: str = None,
|
|
2501
2503
|
cleanup_ttl: int = None,
|
|
2504
|
+
notifications: typing.List[mlrun.model.Notification] = None,
|
|
2502
2505
|
) -> _PipelineRunStatus:
|
|
2503
2506
|
"""run a workflow using kubeflow pipelines
|
|
2504
2507
|
|
|
@@ -2531,6 +2534,8 @@ class MlrunProject(ModelObj):
|
|
|
2531
2534
|
:param cleanup_ttl:
|
|
2532
2535
|
pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
|
|
2533
2536
|
workflow and all its resources are deleted)
|
|
2537
|
+
:param notifications:
|
|
2538
|
+
list of notifications to send for workflow completion
|
|
2534
2539
|
:returns: run id
|
|
2535
2540
|
"""
|
|
2536
2541
|
|
|
@@ -2598,6 +2603,7 @@ class MlrunProject(ModelObj):
|
|
|
2598
2603
|
artifact_path=artifact_path,
|
|
2599
2604
|
namespace=namespace,
|
|
2600
2605
|
source=source,
|
|
2606
|
+
notifications=notifications,
|
|
2601
2607
|
)
|
|
2602
2608
|
# run is None when scheduling
|
|
2603
2609
|
if run and run.state == mlrun.run.RunStatuses.failed:
|
|
@@ -2609,7 +2615,14 @@ class MlrunProject(ModelObj):
|
|
|
2609
2615
|
)
|
|
2610
2616
|
workflow_spec.clear_tmp()
|
|
2611
2617
|
if (timeout or watch) and not workflow_spec.schedule:
|
|
2612
|
-
run
|
|
2618
|
+
# run's engine gets replaced with inner engine if engine is remote,
|
|
2619
|
+
# so in that case we need to get the status from the remote engine manually
|
|
2620
|
+
if engine == "remote":
|
|
2621
|
+
status_engine = _RemoteRunner
|
|
2622
|
+
else:
|
|
2623
|
+
status_engine = run._engine
|
|
2624
|
+
|
|
2625
|
+
status_engine.get_run_status(project=self, run=run, timeout=timeout)
|
|
2613
2626
|
return run
|
|
2614
2627
|
|
|
2615
2628
|
def save_workflow(self, name, target, artifact_path=None, ttl=None):
|
|
@@ -2711,6 +2724,7 @@ class MlrunProject(ModelObj):
|
|
|
2711
2724
|
"""Set the credentials that will be used by the project's model monitoring
|
|
2712
2725
|
infrastructure functions.
|
|
2713
2726
|
|
|
2727
|
+
:param access_key: Model Monitoring access key for managing user permissions
|
|
2714
2728
|
:param access_key: Model Monitoring access key for managing user permissions
|
|
2715
2729
|
:param endpoint_store_connection: Endpoint store connection string
|
|
2716
2730
|
:param stream_path: Path to the model monitoring stream
|
|
@@ -2995,7 +3009,7 @@ class MlrunProject(ModelObj):
|
|
|
2995
3009
|
* True: The existing params are replaced by the new ones
|
|
2996
3010
|
:param extra_args: A string containing additional builder arguments in the format of command-line options,
|
|
2997
3011
|
e.g. extra_args="--skip-tls-verify --build-arg A=val"r
|
|
2998
|
-
:param force_build:
|
|
3012
|
+
:param force_build: set True for force building the image
|
|
2999
3013
|
"""
|
|
3000
3014
|
|
|
3001
3015
|
if skip_deployed:
|
|
@@ -3228,13 +3242,16 @@ class MlrunProject(ModelObj):
|
|
|
3228
3242
|
:param labels: Return functions that have specific labels assigned to them.
|
|
3229
3243
|
:returns: List of function objects.
|
|
3230
3244
|
"""
|
|
3231
|
-
|
|
3245
|
+
|
|
3246
|
+
model_monitoring_labels_list = [
|
|
3247
|
+
f"{mm_constants.ModelMonitoringAppLabel.KEY}={mm_constants.ModelMonitoringAppLabel.VAL}"
|
|
3248
|
+
]
|
|
3249
|
+
if labels:
|
|
3250
|
+
model_monitoring_labels_list += labels
|
|
3232
3251
|
return self.list_functions(
|
|
3233
3252
|
name=name,
|
|
3234
3253
|
tag=tag,
|
|
3235
|
-
labels=
|
|
3236
|
-
f"{mm_constants.ModelMonitoringAppLabel.KEY}={mm_constants.ModelMonitoringAppLabel.VAL}"
|
|
3237
|
-
].extend(labels),
|
|
3254
|
+
labels=model_monitoring_labels_list,
|
|
3238
3255
|
)
|
|
3239
3256
|
|
|
3240
3257
|
def list_runs(
|
|
@@ -3463,7 +3480,13 @@ def _init_function_from_dict(
|
|
|
3463
3480
|
)
|
|
3464
3481
|
|
|
3465
3482
|
elif url.endswith(".py"):
|
|
3466
|
-
|
|
3483
|
+
# when load_source_on_run is used we allow not providing image as code will be loaded pre-run. ML-4994
|
|
3484
|
+
if (
|
|
3485
|
+
not image
|
|
3486
|
+
and not project.default_image
|
|
3487
|
+
and kind != "local"
|
|
3488
|
+
and not project.spec.load_source_on_run
|
|
3489
|
+
):
|
|
3467
3490
|
raise ValueError(
|
|
3468
3491
|
"image must be provided with py code files which do not "
|
|
3469
3492
|
"run on 'local' engine kind"
|
mlrun/runtimes/__init__.py
CHANGED
|
@@ -199,6 +199,12 @@ class RuntimeKinds(object):
|
|
|
199
199
|
return True
|
|
200
200
|
return False
|
|
201
201
|
|
|
202
|
+
@staticmethod
|
|
203
|
+
def requires_image_name_for_execution(kind):
|
|
204
|
+
if RuntimeKinds.is_local_runtime(kind):
|
|
205
|
+
return False
|
|
206
|
+
return kind not in [RuntimeKinds.spark]
|
|
207
|
+
|
|
202
208
|
|
|
203
209
|
def get_runtime_class(kind: str):
|
|
204
210
|
if kind == RuntimeKinds.mpijob:
|
mlrun/runtimes/base.py
CHANGED
|
@@ -196,6 +196,9 @@ class BaseRuntime(ModelObj):
|
|
|
196
196
|
self.metadata.labels[key] = str(value)
|
|
197
197
|
return self
|
|
198
198
|
|
|
199
|
+
def set_categories(self, categories: List[str]):
|
|
200
|
+
self.metadata.categories = mlrun.utils.helpers.as_list(categories)
|
|
201
|
+
|
|
199
202
|
@property
|
|
200
203
|
def uri(self):
|
|
201
204
|
return self._function_uri()
|
|
@@ -356,7 +359,7 @@ class BaseRuntime(ModelObj):
|
|
|
356
359
|
type can be given there. The artifact key must appear in the dictionary as "key": "the_key".
|
|
357
360
|
:param state_thresholds: Dictionary of states to time thresholds. The state will be matched against the
|
|
358
361
|
pod's status. The threshold should be a time string that conforms to timelength python package
|
|
359
|
-
standards and is at least 1
|
|
362
|
+
standards and is at least 1 minute (-1 for infinite).
|
|
360
363
|
If the phase is active for longer than the threshold, the run will be aborted.
|
|
361
364
|
See mlconf.function.spec.state_thresholds for the state options and default values.
|
|
362
365
|
:return: Run context object (RunObject) with run metadata, results and status
|
|
@@ -797,6 +800,14 @@ class BaseRuntime(ModelObj):
|
|
|
797
800
|
self.spec.build = {}
|
|
798
801
|
return self
|
|
799
802
|
|
|
803
|
+
def requires_build(self) -> bool:
|
|
804
|
+
build = self.spec.build
|
|
805
|
+
return (
|
|
806
|
+
build.commands
|
|
807
|
+
or build.requirements
|
|
808
|
+
or (build.source and not build.load_source_on_run)
|
|
809
|
+
)
|
|
810
|
+
|
|
800
811
|
def prepare_image_for_deploy(self):
|
|
801
812
|
"""
|
|
802
813
|
if a function has a 'spec.image' it is considered to be deployed,
|
mlrun/runtimes/daskjob.py
CHANGED
|
@@ -16,6 +16,7 @@ import inspect
|
|
|
16
16
|
import socket
|
|
17
17
|
import time
|
|
18
18
|
from os import environ
|
|
19
|
+
from typing import Callable, Dict, List, Optional, Union
|
|
19
20
|
|
|
20
21
|
import mlrun.common.schemas
|
|
21
22
|
import mlrun.errors
|
|
@@ -230,7 +231,7 @@ class DaskCluster(KubejobRuntime):
|
|
|
230
231
|
if db_func and "status" in db_func:
|
|
231
232
|
self.status = db_func["status"]
|
|
232
233
|
if self.kfp:
|
|
233
|
-
logger.info(f"
|
|
234
|
+
logger.info(f"Dask status: {db_func['status']}")
|
|
234
235
|
return "scheduler_address" in db_func["status"]
|
|
235
236
|
|
|
236
237
|
return False
|
|
@@ -311,7 +312,7 @@ class DaskCluster(KubejobRuntime):
|
|
|
311
312
|
if self.spec.service_type == "NodePort":
|
|
312
313
|
dash = f"{config.remote_host}:{self.status.node_ports.get('dashboard')}"
|
|
313
314
|
else:
|
|
314
|
-
logger.info("
|
|
315
|
+
logger.info("To get a dashboard link, use NodePort service_type")
|
|
315
316
|
|
|
316
317
|
return addr, dash
|
|
317
318
|
|
|
@@ -325,12 +326,12 @@ class DaskCluster(KubejobRuntime):
|
|
|
325
326
|
|
|
326
327
|
if self.status.scheduler_address:
|
|
327
328
|
addr, dash = self._remote_addresses()
|
|
328
|
-
logger.info(f"
|
|
329
|
+
logger.info(f"Trying dask client at: {addr}")
|
|
329
330
|
try:
|
|
330
331
|
client = Client(addr)
|
|
331
332
|
except OSError as exc:
|
|
332
333
|
logger.warning(
|
|
333
|
-
f"
|
|
334
|
+
f"Remote scheduler at {addr} not ready, will try to restart {err_to_str(exc)}"
|
|
334
335
|
)
|
|
335
336
|
|
|
336
337
|
status = self.get_status()
|
|
@@ -340,7 +341,7 @@ class DaskCluster(KubejobRuntime):
|
|
|
340
341
|
client = Client(addr)
|
|
341
342
|
|
|
342
343
|
logger.info(
|
|
343
|
-
f"
|
|
344
|
+
f"Using remote dask scheduler ({self.status.cluster_name}) at: {addr}"
|
|
344
345
|
)
|
|
345
346
|
if dash:
|
|
346
347
|
ipython_display(
|
|
@@ -457,6 +458,73 @@ class DaskCluster(KubejobRuntime):
|
|
|
457
458
|
"""
|
|
458
459
|
self.spec._verify_and_set_requests("worker_resources", mem, cpu, patch=patch)
|
|
459
460
|
|
|
461
|
+
def set_state_thresholds(
|
|
462
|
+
self,
|
|
463
|
+
state_thresholds: Dict[str, str],
|
|
464
|
+
patch: bool = True,
|
|
465
|
+
):
|
|
466
|
+
raise NotImplementedError(
|
|
467
|
+
"State thresholds is not supported for Dask runtime yet, use spec.scheduler_timeout instead.",
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
def run(
|
|
471
|
+
self,
|
|
472
|
+
runspec: Optional[
|
|
473
|
+
Union["mlrun.run.RunTemplate", "mlrun.run.RunObject", dict]
|
|
474
|
+
] = None,
|
|
475
|
+
handler: Optional[Union[str, Callable]] = None,
|
|
476
|
+
name: Optional[str] = "",
|
|
477
|
+
project: Optional[str] = "",
|
|
478
|
+
params: Optional[dict] = None,
|
|
479
|
+
inputs: Optional[Dict[str, str]] = None,
|
|
480
|
+
out_path: Optional[str] = "",
|
|
481
|
+
workdir: Optional[str] = "",
|
|
482
|
+
artifact_path: Optional[str] = "",
|
|
483
|
+
watch: Optional[bool] = True,
|
|
484
|
+
schedule: Optional[Union[str, mlrun.common.schemas.ScheduleCronTrigger]] = None,
|
|
485
|
+
hyperparams: Optional[Dict[str, list]] = None,
|
|
486
|
+
hyper_param_options: Optional[mlrun.model.HyperParamOptions] = None,
|
|
487
|
+
verbose: Optional[bool] = None,
|
|
488
|
+
scrape_metrics: Optional[bool] = None,
|
|
489
|
+
local: Optional[bool] = False,
|
|
490
|
+
local_code_path: Optional[str] = None,
|
|
491
|
+
auto_build: Optional[bool] = None,
|
|
492
|
+
param_file_secrets: Optional[Dict[str, str]] = None,
|
|
493
|
+
notifications: Optional[List[mlrun.model.Notification]] = None,
|
|
494
|
+
returns: Optional[List[Union[str, Dict[str, str]]]] = None,
|
|
495
|
+
state_thresholds: Optional[Dict[str, int]] = None,
|
|
496
|
+
**launcher_kwargs,
|
|
497
|
+
) -> RunObject:
|
|
498
|
+
if state_thresholds:
|
|
499
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
500
|
+
"State thresholds is not supported for Dask runtime yet, use spec.scheduler_timeout instead."
|
|
501
|
+
)
|
|
502
|
+
return super().run(
|
|
503
|
+
runspec=runspec,
|
|
504
|
+
handler=handler,
|
|
505
|
+
name=name,
|
|
506
|
+
project=project,
|
|
507
|
+
params=params,
|
|
508
|
+
inputs=inputs,
|
|
509
|
+
out_path=out_path,
|
|
510
|
+
workdir=workdir,
|
|
511
|
+
artifact_path=artifact_path,
|
|
512
|
+
watch=watch,
|
|
513
|
+
schedule=schedule,
|
|
514
|
+
hyperparams=hyperparams,
|
|
515
|
+
hyper_param_options=hyper_param_options,
|
|
516
|
+
verbose=verbose,
|
|
517
|
+
scrape_metrics=scrape_metrics,
|
|
518
|
+
local=local,
|
|
519
|
+
local_code_path=local_code_path,
|
|
520
|
+
auto_build=auto_build,
|
|
521
|
+
param_file_secrets=param_file_secrets,
|
|
522
|
+
notifications=notifications,
|
|
523
|
+
returns=returns,
|
|
524
|
+
state_thresholds=state_thresholds,
|
|
525
|
+
**launcher_kwargs,
|
|
526
|
+
)
|
|
527
|
+
|
|
460
528
|
def _run(self, runobj: RunObject, execution):
|
|
461
529
|
|
|
462
530
|
handler = runobj.spec.handler
|
|
@@ -127,6 +127,7 @@ if result:
|
|
|
127
127
|
param_file_secrets: Optional[Dict[str, str]] = None,
|
|
128
128
|
notifications: Optional[List[mlrun.model.Notification]] = None,
|
|
129
129
|
returns: Optional[List[Union[str, Dict[str, str]]]] = None,
|
|
130
|
+
state_thresholds: Optional[Dict[str, int]] = None,
|
|
130
131
|
**launcher_kwargs,
|
|
131
132
|
) -> RunObject:
|
|
132
133
|
if local:
|
|
@@ -153,6 +154,7 @@ if result:
|
|
|
153
154
|
param_file_secrets=param_file_secrets,
|
|
154
155
|
notifications=notifications,
|
|
155
156
|
returns=returns,
|
|
157
|
+
state_thresholds=state_thresholds,
|
|
156
158
|
**launcher_kwargs,
|
|
157
159
|
)
|
|
158
160
|
|
mlrun/runtimes/function.py
CHANGED
|
@@ -120,6 +120,7 @@ class NuclioSpec(KubeResourceSpec):
|
|
|
120
120
|
"base_image_pull",
|
|
121
121
|
"service_type",
|
|
122
122
|
"add_templated_ingress_host_mode",
|
|
123
|
+
"disable_default_http_trigger",
|
|
123
124
|
]
|
|
124
125
|
|
|
125
126
|
def __init__(
|
|
@@ -163,6 +164,7 @@ class NuclioSpec(KubeResourceSpec):
|
|
|
163
164
|
add_templated_ingress_host_mode=None,
|
|
164
165
|
clone_target_dir=None,
|
|
165
166
|
state_thresholds=None,
|
|
167
|
+
disable_default_http_trigger=None,
|
|
166
168
|
):
|
|
167
169
|
|
|
168
170
|
super().__init__(
|
|
@@ -210,6 +212,8 @@ class NuclioSpec(KubeResourceSpec):
|
|
|
210
212
|
self.min_replicas = min_replicas or 1
|
|
211
213
|
self.max_replicas = max_replicas or 4
|
|
212
214
|
|
|
215
|
+
self.disable_default_http_trigger = disable_default_http_trigger
|
|
216
|
+
|
|
213
217
|
# When True it will set Nuclio spec.noBaseImagesPull to False (negative logic)
|
|
214
218
|
# indicate that the base image should be pulled from the container registry (not cached)
|
|
215
219
|
self.base_image_pull = False
|
|
@@ -413,6 +417,11 @@ class RemoteRuntime(KubeResource):
|
|
|
413
417
|
:param extra_attributes: key/value dict of extra nuclio trigger attributes
|
|
414
418
|
:return: function object (self)
|
|
415
419
|
"""
|
|
420
|
+
if self.disable_default_http_trigger:
|
|
421
|
+
logger.warning(
|
|
422
|
+
"Adding HTTP trigger despite the default HTTP trigger creation being disabled"
|
|
423
|
+
)
|
|
424
|
+
|
|
416
425
|
annotations = annotations or {}
|
|
417
426
|
if worker_timeout:
|
|
418
427
|
gateway_timeout = gateway_timeout or (worker_timeout + 60)
|
|
@@ -683,6 +692,24 @@ class RemoteRuntime(KubeResource):
|
|
|
683
692
|
"State thresholds do not apply for nuclio as it has its own function pods healthiness monitoring"
|
|
684
693
|
)
|
|
685
694
|
|
|
695
|
+
@min_nuclio_versions("1.12.8")
|
|
696
|
+
def disable_default_http_trigger(
|
|
697
|
+
self,
|
|
698
|
+
):
|
|
699
|
+
"""
|
|
700
|
+
Disables nuclio's default http trigger creation
|
|
701
|
+
"""
|
|
702
|
+
self.spec.disable_default_http_trigger = True
|
|
703
|
+
|
|
704
|
+
@min_nuclio_versions("1.12.8")
|
|
705
|
+
def enable_default_http_trigger(
|
|
706
|
+
self,
|
|
707
|
+
):
|
|
708
|
+
"""
|
|
709
|
+
Enables nuclio's default http trigger creation
|
|
710
|
+
"""
|
|
711
|
+
self.spec.disable_default_http_trigger = False
|
|
712
|
+
|
|
686
713
|
def _get_state(
|
|
687
714
|
self,
|
|
688
715
|
dashboard="",
|
|
@@ -876,11 +903,22 @@ class RemoteRuntime(KubeResource):
|
|
|
876
903
|
|
|
877
904
|
if "://" not in path:
|
|
878
905
|
if not self.status.address:
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
906
|
+
# here we check that if default http trigger is disabled, function contains a custom http trigger
|
|
907
|
+
# Otherwise, the function is not invokable, so we raise an error
|
|
908
|
+
if (
|
|
909
|
+
not self._trigger_of_kind_exists(kind="http")
|
|
910
|
+
and self.spec.disable_default_http_trigger
|
|
911
|
+
):
|
|
912
|
+
raise mlrun.errors.MLRunPreconditionFailedError(
|
|
913
|
+
"Default http trigger creation is disabled and there is no any other custom http trigger, "
|
|
914
|
+
"so function can not be invoked via http. Either enable default http trigger creation or create"
|
|
915
|
+
"custom http trigger"
|
|
883
916
|
)
|
|
917
|
+
state, _, _ = self._get_state(dashboard, auth_info=auth_info)
|
|
918
|
+
if state not in ["ready", "scaledToZero"]:
|
|
919
|
+
logger.warning(f"Function is in the {state} state")
|
|
920
|
+
if not self.status.address:
|
|
921
|
+
raise ValueError("no function address first run .deploy()")
|
|
884
922
|
|
|
885
923
|
path = self._resolve_invocation_url(path, force_external_address)
|
|
886
924
|
|
|
@@ -914,6 +952,17 @@ class RemoteRuntime(KubeResource):
|
|
|
914
952
|
data = json.loads(data)
|
|
915
953
|
return data
|
|
916
954
|
|
|
955
|
+
def _trigger_of_kind_exists(self, kind: str) -> bool:
|
|
956
|
+
if not self.spec.config:
|
|
957
|
+
return False
|
|
958
|
+
|
|
959
|
+
for name, spec in self.spec.config.items():
|
|
960
|
+
if isinstance(spec, dict):
|
|
961
|
+
if spec.get("kind") == kind:
|
|
962
|
+
return True
|
|
963
|
+
|
|
964
|
+
return False
|
|
965
|
+
|
|
917
966
|
def _pre_run_validations(self):
|
|
918
967
|
if self.spec.function_kind != "mlrun":
|
|
919
968
|
raise RunError(
|
mlrun/runtimes/kubejob.py
CHANGED
|
@@ -175,7 +175,7 @@ class KubejobRuntime(KubeResource):
|
|
|
175
175
|
:param show_on_failure: show logs only in case of build failure
|
|
176
176
|
:param force_build: set True for force building the image, even when no changes were made
|
|
177
177
|
|
|
178
|
-
:return True if the function is ready (deployed)
|
|
178
|
+
:return: True if the function is ready (deployed)
|
|
179
179
|
"""
|
|
180
180
|
|
|
181
181
|
build = self.spec.build
|
mlrun/runtimes/local.py
CHANGED
|
@@ -104,13 +104,13 @@ class ParallelRunner:
|
|
|
104
104
|
num_errors += 1
|
|
105
105
|
results.append(resp)
|
|
106
106
|
if num_errors > generator.max_errors:
|
|
107
|
-
logger.error("
|
|
107
|
+
logger.error("Max errors reached, stopping iterations!")
|
|
108
108
|
return True
|
|
109
109
|
run_results = resp["status"].get("results", {})
|
|
110
110
|
stop = generator.eval_stop_condition(run_results)
|
|
111
111
|
if stop:
|
|
112
112
|
logger.info(
|
|
113
|
-
f"
|
|
113
|
+
f"Reached early stop condition ({generator.options.stop_condition}), stopping iterations!"
|
|
114
114
|
)
|
|
115
115
|
return stop
|
|
116
116
|
|
|
@@ -140,7 +140,7 @@ class ParallelRunner:
|
|
|
140
140
|
|
|
141
141
|
client.close()
|
|
142
142
|
if function_name and generator.options.teardown_dask:
|
|
143
|
-
logger.info("
|
|
143
|
+
logger.info("Tearing down the dask cluster..")
|
|
144
144
|
mlrun.get_run_db().delete_runtime_resources(
|
|
145
145
|
kind="dask", object_id=function_name, force=True
|
|
146
146
|
)
|
|
@@ -278,7 +278,7 @@ class LocalRuntime(BaseRuntime, ParallelRunner):
|
|
|
278
278
|
|
|
279
279
|
handler = runobj.spec.handler
|
|
280
280
|
handler_str = handler or "main"
|
|
281
|
-
logger.debug(f"
|
|
281
|
+
logger.debug(f"Starting local run: {self.spec.command} # {handler_str}")
|
|
282
282
|
pythonpath = self.spec.pythonpath
|
|
283
283
|
|
|
284
284
|
if handler:
|
|
@@ -317,13 +317,13 @@ class LocalRuntime(BaseRuntime, ParallelRunner):
|
|
|
317
317
|
context.set_state(error=err_to_str(exc), commit=True)
|
|
318
318
|
logger.error(f"run error, {traceback.format_exc()}")
|
|
319
319
|
raise RunError(
|
|
320
|
-
"
|
|
320
|
+
"Failed on pre-loading / post-running of the function"
|
|
321
321
|
) from exc
|
|
322
322
|
|
|
323
323
|
else:
|
|
324
324
|
command = self.spec.command
|
|
325
325
|
command = command.format(**runobj.spec.parameters)
|
|
326
|
-
logger.info(f"
|
|
326
|
+
logger.info(f"Handler was not provided running main ({command})")
|
|
327
327
|
arg_list = command.split()
|
|
328
328
|
if self.spec.mode == "pass":
|
|
329
329
|
cmd = arg_list
|
|
@@ -360,9 +360,9 @@ class LocalRuntime(BaseRuntime, ParallelRunner):
|
|
|
360
360
|
if resp:
|
|
361
361
|
run_obj_dict = json.loads(resp)
|
|
362
362
|
else:
|
|
363
|
-
logger.
|
|
363
|
+
logger.debug("Empty context tmp file")
|
|
364
364
|
else:
|
|
365
|
-
logger.info("
|
|
365
|
+
logger.info("No context file found")
|
|
366
366
|
|
|
367
367
|
# If trackers where used, this is where we log all data collected to MLRun
|
|
368
368
|
run_obj_dict = trackers_manager.post_run(run_obj_dict)
|
|
@@ -396,7 +396,7 @@ def run_exec(cmd, args, env=None, cwd=None):
|
|
|
396
396
|
cmd += args
|
|
397
397
|
if env and "SYSTEMROOT" in os.environ:
|
|
398
398
|
env["SYSTEMROOT"] = os.environ["SYSTEMROOT"]
|
|
399
|
-
print("
|
|
399
|
+
print("Running:", cmd)
|
|
400
400
|
process = Popen(
|
|
401
401
|
cmd, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=cwd, universal_newlines=True
|
|
402
402
|
)
|
mlrun/runtimes/pod.py
CHANGED
|
@@ -1067,7 +1067,7 @@ class KubeResource(BaseRuntime):
|
|
|
1067
1067
|
Set the threshold for a specific state of the runtime.
|
|
1068
1068
|
The threshold is the amount of time that the runtime will wait before aborting the run if the job is in the
|
|
1069
1069
|
matching state.
|
|
1070
|
-
The threshold time string must conform to timelength python package standards and be at least 1
|
|
1070
|
+
The threshold time string must conform to timelength python package standards and be at least 1 minute
|
|
1071
1071
|
(e.g. 1000s, 1 hour 30m, 1h etc. or -1 for infinite).
|
|
1072
1072
|
If the threshold is not set for a state, the default threshold will be used.
|
|
1073
1073
|
|
mlrun/runtimes/remotesparkjob.py
CHANGED
mlrun/runtimes/serving.py
CHANGED
|
@@ -147,6 +147,7 @@ class ServingSpec(NuclioSpec):
|
|
|
147
147
|
add_templated_ingress_host_mode=None,
|
|
148
148
|
clone_target_dir=None,
|
|
149
149
|
state_thresholds=None,
|
|
150
|
+
disable_default_http_trigger=None,
|
|
150
151
|
):
|
|
151
152
|
super().__init__(
|
|
152
153
|
command=command,
|
|
@@ -187,6 +188,7 @@ class ServingSpec(NuclioSpec):
|
|
|
187
188
|
service_type=service_type,
|
|
188
189
|
add_templated_ingress_host_mode=add_templated_ingress_host_mode,
|
|
189
190
|
clone_target_dir=clone_target_dir,
|
|
191
|
+
disable_default_http_trigger=disable_default_http_trigger,
|
|
190
192
|
)
|
|
191
193
|
|
|
192
194
|
self.models = models or {}
|
|
@@ -584,6 +586,7 @@ class ServingRuntime(RemoteRuntime):
|
|
|
584
586
|
verbose=False,
|
|
585
587
|
auth_info: mlrun.common.schemas.AuthInfo = None,
|
|
586
588
|
builder_env: dict = None,
|
|
589
|
+
force_build: bool = False,
|
|
587
590
|
):
|
|
588
591
|
"""deploy model serving function to a local/remote cluster
|
|
589
592
|
|
|
@@ -594,6 +597,7 @@ class ServingRuntime(RemoteRuntime):
|
|
|
594
597
|
:param auth_info: The auth info to use to communicate with the Nuclio dashboard, required only when providing
|
|
595
598
|
dashboard
|
|
596
599
|
:param builder_env: env vars dict for source archive config/credentials e.g. builder_env={"GIT_TOKEN": token}
|
|
600
|
+
:param force_build: set True for force building the image
|
|
597
601
|
"""
|
|
598
602
|
load_mode = self.spec.load_mode
|
|
599
603
|
if load_mode and load_mode not in ["sync", "async"]:
|
|
@@ -633,7 +637,13 @@ class ServingRuntime(RemoteRuntime):
|
|
|
633
637
|
logger.info(f"deploy root function {self.metadata.name} ...")
|
|
634
638
|
|
|
635
639
|
return super().deploy(
|
|
636
|
-
dashboard,
|
|
640
|
+
dashboard,
|
|
641
|
+
project,
|
|
642
|
+
tag,
|
|
643
|
+
verbose,
|
|
644
|
+
auth_info,
|
|
645
|
+
builder_env=builder_env,
|
|
646
|
+
force_build=force_build,
|
|
637
647
|
)
|
|
638
648
|
|
|
639
649
|
def _get_runtime_env(self):
|
|
@@ -856,6 +856,7 @@ class Spark3Runtime(KubejobRuntime):
|
|
|
856
856
|
mlrun_version_specifier=None,
|
|
857
857
|
builder_env: dict = None,
|
|
858
858
|
show_on_failure: bool = False,
|
|
859
|
+
force_build: bool = False,
|
|
859
860
|
):
|
|
860
861
|
"""deploy function, build container with dependencies
|
|
861
862
|
|
|
@@ -867,8 +868,9 @@ class Spark3Runtime(KubejobRuntime):
|
|
|
867
868
|
:param builder_env: Kaniko builder pod env vars dict (for config/credentials)
|
|
868
869
|
e.g. builder_env={"GIT_TOKEN": token}
|
|
869
870
|
:param show_on_failure: show logs only in case of build failure
|
|
871
|
+
:param force_build: set True for force building the image, even when no changes were made
|
|
870
872
|
|
|
871
|
-
:return True if the function is ready (deployed)
|
|
873
|
+
:return: True if the function is ready (deployed)
|
|
872
874
|
"""
|
|
873
875
|
# connect will populate the config from the server config
|
|
874
876
|
mlrun.db.get_run_db()
|
|
@@ -882,6 +884,7 @@ class Spark3Runtime(KubejobRuntime):
|
|
|
882
884
|
mlrun_version_specifier=mlrun_version_specifier,
|
|
883
885
|
builder_env=builder_env,
|
|
884
886
|
show_on_failure=show_on_failure,
|
|
887
|
+
force_build=force_build,
|
|
885
888
|
)
|
|
886
889
|
|
|
887
890
|
@staticmethod
|