mlrun 1.10.0rc40__py3-none-any.whl → 1.11.0rc16__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 +3 -2
- mlrun/__main__.py +0 -4
- mlrun/artifacts/dataset.py +2 -2
- mlrun/artifacts/plots.py +1 -1
- mlrun/{model_monitoring/db/tsdb/tdengine → auth}/__init__.py +2 -3
- mlrun/auth/nuclio.py +89 -0
- mlrun/auth/providers.py +429 -0
- mlrun/auth/utils.py +415 -0
- mlrun/common/constants.py +7 -0
- mlrun/common/model_monitoring/helpers.py +41 -4
- mlrun/common/runtimes/constants.py +28 -0
- mlrun/common/schemas/__init__.py +13 -3
- mlrun/common/schemas/alert.py +2 -2
- mlrun/common/schemas/api_gateway.py +3 -0
- mlrun/common/schemas/auth.py +10 -10
- mlrun/common/schemas/client_spec.py +4 -0
- mlrun/common/schemas/constants.py +25 -0
- mlrun/common/schemas/frontend_spec.py +1 -8
- mlrun/common/schemas/function.py +24 -0
- mlrun/common/schemas/hub.py +3 -2
- mlrun/common/schemas/model_monitoring/__init__.py +1 -1
- mlrun/common/schemas/model_monitoring/constants.py +2 -2
- mlrun/common/schemas/secret.py +17 -2
- mlrun/common/secrets.py +95 -1
- mlrun/common/types.py +10 -10
- mlrun/config.py +53 -15
- mlrun/data_types/infer.py +2 -2
- mlrun/datastore/__init__.py +2 -3
- mlrun/datastore/base.py +274 -10
- mlrun/datastore/datastore.py +1 -1
- mlrun/datastore/datastore_profile.py +49 -17
- mlrun/datastore/model_provider/huggingface_provider.py +6 -2
- mlrun/datastore/model_provider/model_provider.py +2 -2
- mlrun/datastore/model_provider/openai_provider.py +2 -2
- mlrun/datastore/s3.py +15 -16
- mlrun/datastore/sources.py +1 -1
- mlrun/datastore/store_resources.py +4 -4
- mlrun/datastore/storeytargets.py +16 -10
- mlrun/datastore/targets.py +1 -1
- mlrun/datastore/utils.py +16 -3
- mlrun/datastore/v3io.py +1 -1
- mlrun/db/base.py +36 -12
- mlrun/db/httpdb.py +316 -101
- mlrun/db/nopdb.py +29 -11
- mlrun/errors.py +4 -2
- mlrun/execution.py +11 -12
- mlrun/feature_store/api.py +1 -1
- mlrun/feature_store/common.py +1 -1
- mlrun/feature_store/feature_vector_utils.py +1 -1
- mlrun/feature_store/steps.py +8 -6
- mlrun/frameworks/_common/utils.py +3 -3
- mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +2 -1
- mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
- mlrun/frameworks/_ml_common/utils.py +2 -1
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +4 -3
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +2 -1
- mlrun/frameworks/onnx/dataset.py +2 -1
- mlrun/frameworks/onnx/mlrun_interface.py +2 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +5 -4
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +2 -1
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +2 -1
- mlrun/frameworks/pytorch/utils.py +2 -1
- mlrun/frameworks/sklearn/metric.py +2 -1
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +5 -4
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +2 -1
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +2 -1
- mlrun/hub/__init__.py +37 -0
- mlrun/hub/base.py +142 -0
- mlrun/hub/module.py +67 -76
- mlrun/hub/step.py +113 -0
- mlrun/launcher/base.py +2 -1
- mlrun/launcher/local.py +2 -1
- mlrun/model.py +12 -2
- mlrun/model_monitoring/__init__.py +0 -1
- mlrun/model_monitoring/api.py +2 -2
- mlrun/model_monitoring/applications/base.py +20 -6
- mlrun/model_monitoring/applications/context.py +1 -0
- mlrun/model_monitoring/controller.py +7 -17
- mlrun/model_monitoring/db/_schedules.py +2 -16
- mlrun/model_monitoring/db/_stats.py +2 -13
- mlrun/model_monitoring/db/tsdb/__init__.py +9 -7
- mlrun/model_monitoring/db/tsdb/base.py +2 -4
- mlrun/model_monitoring/db/tsdb/preaggregate.py +234 -0
- mlrun/model_monitoring/db/tsdb/stream_graph_steps.py +63 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_metrics_queries.py +414 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_predictions_queries.py +376 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_results_queries.py +590 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connection.py +434 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connector.py +541 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_operations.py +808 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_schema.py +502 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream.py +163 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream_graph_steps.py +60 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_dataframe_processor.py +141 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_query_builder.py +585 -0
- mlrun/model_monitoring/db/tsdb/timescaledb/writer_graph_steps.py +73 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +4 -6
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +147 -79
- mlrun/model_monitoring/features_drift_table.py +2 -1
- mlrun/model_monitoring/helpers.py +2 -1
- mlrun/model_monitoring/stream_processing.py +18 -16
- mlrun/model_monitoring/writer.py +4 -3
- mlrun/package/__init__.py +2 -1
- mlrun/platforms/__init__.py +0 -44
- mlrun/platforms/iguazio.py +1 -1
- mlrun/projects/operations.py +11 -10
- mlrun/projects/project.py +81 -82
- mlrun/run.py +4 -7
- mlrun/runtimes/__init__.py +2 -204
- mlrun/runtimes/base.py +89 -21
- mlrun/runtimes/constants.py +225 -0
- mlrun/runtimes/daskjob.py +4 -2
- mlrun/runtimes/databricks_job/databricks_runtime.py +2 -1
- mlrun/runtimes/mounts.py +5 -0
- mlrun/runtimes/nuclio/__init__.py +12 -8
- mlrun/runtimes/nuclio/api_gateway.py +36 -6
- mlrun/runtimes/nuclio/application/application.py +200 -32
- mlrun/runtimes/nuclio/function.py +154 -49
- mlrun/runtimes/nuclio/serving.py +55 -42
- mlrun/runtimes/pod.py +59 -10
- mlrun/secrets.py +46 -2
- mlrun/serving/__init__.py +2 -0
- mlrun/serving/remote.py +5 -5
- mlrun/serving/routers.py +3 -3
- mlrun/serving/server.py +46 -43
- mlrun/serving/serving_wrapper.py +6 -2
- mlrun/serving/states.py +554 -207
- mlrun/serving/steps.py +1 -1
- mlrun/serving/system_steps.py +42 -33
- mlrun/track/trackers/mlflow_tracker.py +29 -31
- mlrun/utils/helpers.py +89 -16
- mlrun/utils/http.py +9 -2
- mlrun/utils/notifications/notification/git.py +1 -1
- mlrun/utils/notifications/notification/mail.py +39 -16
- mlrun/utils/notifications/notification_pusher.py +2 -2
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +3 -4
- {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/METADATA +39 -49
- {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/RECORD +144 -130
- mlrun/db/auth_utils.py +0 -152
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +0 -343
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +0 -75
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +0 -281
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +0 -1368
- mlrun/model_monitoring/db/tsdb/tdengine/writer_graph_steps.py +0 -51
- {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/WHEEL +0 -0
- {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/entry_points.txt +0 -0
- {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/top_level.txt +0 -0
mlrun/runtimes/base.py
CHANGED
|
@@ -16,8 +16,9 @@ import http
|
|
|
16
16
|
import re
|
|
17
17
|
import typing
|
|
18
18
|
import warnings
|
|
19
|
+
from collections.abc import Callable
|
|
19
20
|
from os import environ
|
|
20
|
-
from typing import
|
|
21
|
+
from typing import Optional, Union
|
|
21
22
|
|
|
22
23
|
import requests.exceptions
|
|
23
24
|
from nuclio.build import mlrun_footer
|
|
@@ -30,6 +31,7 @@ import mlrun.common.schemas
|
|
|
30
31
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
31
32
|
import mlrun.errors
|
|
32
33
|
import mlrun.launcher.factory
|
|
34
|
+
import mlrun.runtimes
|
|
33
35
|
import mlrun.utils.helpers
|
|
34
36
|
import mlrun.utils.notifications
|
|
35
37
|
import mlrun.utils.regex
|
|
@@ -277,18 +279,6 @@ class BaseRuntime(ModelObj):
|
|
|
277
279
|
mlrun.model.Credentials.generate_access_key
|
|
278
280
|
)
|
|
279
281
|
|
|
280
|
-
def generate_runtime_k8s_env(self, runobj: RunObject = None) -> list[dict]:
|
|
281
|
-
"""
|
|
282
|
-
Prepares a runtime environment as it's expected by kubernetes.models.V1Container
|
|
283
|
-
|
|
284
|
-
:param runobj: Run context object (RunObject) with run metadata and status
|
|
285
|
-
:return: List of dicts with the structure {"name": "var_name", "value": "var_value"}
|
|
286
|
-
"""
|
|
287
|
-
return [
|
|
288
|
-
{"name": k, "value": v}
|
|
289
|
-
for k, v in self._generate_runtime_env(runobj).items()
|
|
290
|
-
]
|
|
291
|
-
|
|
292
282
|
def run(
|
|
293
283
|
self,
|
|
294
284
|
runspec: Optional[
|
|
@@ -394,8 +384,6 @@ class BaseRuntime(ModelObj):
|
|
|
394
384
|
)
|
|
395
385
|
output_path = output_path or out_path or artifact_path
|
|
396
386
|
|
|
397
|
-
mlrun.utils.helpers.validate_function_name(self.metadata.name)
|
|
398
|
-
|
|
399
387
|
launcher = mlrun.launcher.factory.LauncherFactory().create_launcher(
|
|
400
388
|
self._is_remote, local=local, **launcher_kwargs
|
|
401
389
|
)
|
|
@@ -443,13 +431,14 @@ class BaseRuntime(ModelObj):
|
|
|
443
431
|
if task:
|
|
444
432
|
return task.to_dict()
|
|
445
433
|
|
|
446
|
-
def _generate_runtime_env(self, runobj: RunObject = None)
|
|
434
|
+
def _generate_runtime_env(self, runobj: RunObject = None):
|
|
447
435
|
"""
|
|
448
|
-
Prepares all available environment variables for usage on a runtime
|
|
449
|
-
Data will be extracted from several sources and most of them are not guaranteed to be available
|
|
436
|
+
Prepares all available environment variables for usage on a runtime.
|
|
450
437
|
|
|
451
|
-
:param runobj:
|
|
452
|
-
:return:
|
|
438
|
+
:param runobj: Optional run context object (RunObject) with run metadata and status
|
|
439
|
+
:return: Tuple of (runtime_env, external_source_env) where:
|
|
440
|
+
- runtime_env: Dict of {env_name: value} for standard env vars
|
|
441
|
+
- external_source_env: Dict of {env_name: value_from} for env vars with external sources
|
|
453
442
|
"""
|
|
454
443
|
active_project = self.metadata.project or config.active_project
|
|
455
444
|
runtime_env = {
|
|
@@ -457,6 +446,16 @@ class BaseRuntime(ModelObj):
|
|
|
457
446
|
# TODO: Remove this in 1.12.0 as MLRUN_DEFAULT_PROJECT is deprecated and should not be injected anymore
|
|
458
447
|
"MLRUN_DEFAULT_PROJECT": active_project,
|
|
459
448
|
}
|
|
449
|
+
|
|
450
|
+
# Set auth session only for nuclio runtimes that have an access key
|
|
451
|
+
if (
|
|
452
|
+
self.kind in mlrun.runtimes.RuntimeKinds.nuclio_runtimes()
|
|
453
|
+
and self.metadata.credentials.access_key
|
|
454
|
+
):
|
|
455
|
+
runtime_env[
|
|
456
|
+
mlrun.common.runtimes.constants.FunctionEnvironmentVariables.auth_session
|
|
457
|
+
] = self.metadata.credentials.access_key
|
|
458
|
+
|
|
460
459
|
if runobj:
|
|
461
460
|
runtime_env["MLRUN_EXEC_CONFIG"] = runobj.to_json(
|
|
462
461
|
exclude_notifications_params=True
|
|
@@ -471,7 +470,47 @@ class BaseRuntime(ModelObj):
|
|
|
471
470
|
runtime_env["MLRUN_DBPATH"] = config.httpdb.api_url
|
|
472
471
|
if self.metadata.namespace or config.namespace:
|
|
473
472
|
runtime_env["MLRUN_NAMESPACE"] = self.metadata.namespace or config.namespace
|
|
474
|
-
|
|
473
|
+
|
|
474
|
+
external_source_env = self._generate_external_source_runtime_envs()
|
|
475
|
+
|
|
476
|
+
return runtime_env, external_source_env
|
|
477
|
+
|
|
478
|
+
def _generate_external_source_runtime_envs(self):
|
|
479
|
+
"""
|
|
480
|
+
Returns non-static env vars to be added to the runtime pod/container.
|
|
481
|
+
|
|
482
|
+
:return: Dict of {env_name: value_from} for env vars with external sources (e.g., fieldRef)
|
|
483
|
+
"""
|
|
484
|
+
return {
|
|
485
|
+
"MLRUN_RUNTIME_KIND": {
|
|
486
|
+
"fieldRef": {
|
|
487
|
+
"apiVersion": "v1",
|
|
488
|
+
"fieldPath": f"metadata.labels['{mlrun_constants.MLRunInternalLabels.mlrun_class}']",
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
def _generate_k8s_runtime_env(self, runobj: RunObject = None):
|
|
494
|
+
"""
|
|
495
|
+
Generates runtime environment variables in Kubernetes format.
|
|
496
|
+
|
|
497
|
+
:param runobj: Optional run context object (RunObject) with run metadata and status
|
|
498
|
+
:return: List of env var dicts in K8s format:
|
|
499
|
+
- Standard envs: [{"name": key, "value": value}, ...]
|
|
500
|
+
- External source envs: [{"name": key, "valueFrom": value_from}, ...]
|
|
501
|
+
"""
|
|
502
|
+
runtime_env, external_source_env = self._generate_runtime_env(runobj)
|
|
503
|
+
|
|
504
|
+
# Convert standard env vars to K8s format
|
|
505
|
+
k8s_env = [{"name": k, "value": v} for k, v in runtime_env.items()]
|
|
506
|
+
|
|
507
|
+
# Convert external source env vars to K8s format
|
|
508
|
+
k8s_external_env = [
|
|
509
|
+
{"name": k, "valueFrom": v} for k, v in external_source_env.items()
|
|
510
|
+
]
|
|
511
|
+
|
|
512
|
+
k8s_env.extend(k8s_external_env)
|
|
513
|
+
return k8s_env
|
|
475
514
|
|
|
476
515
|
@staticmethod
|
|
477
516
|
def _handle_submit_job_http_error(error: requests.HTTPError):
|
|
@@ -949,5 +988,34 @@ class BaseRuntime(ModelObj):
|
|
|
949
988
|
line += f", default={p['default']}"
|
|
950
989
|
print(" " + line)
|
|
951
990
|
|
|
991
|
+
def remove_auth_secret_volumes(self):
|
|
992
|
+
secret_name_prefix = (
|
|
993
|
+
mlrun.mlconf.secret_stores.kubernetes.auth_secret_name.format(
|
|
994
|
+
hashed_access_key=""
|
|
995
|
+
)
|
|
996
|
+
)
|
|
997
|
+
volumes = self.spec.volumes or []
|
|
998
|
+
mounts = self.spec.volume_mounts or []
|
|
999
|
+
|
|
1000
|
+
volumes_to_remove = set()
|
|
1001
|
+
|
|
1002
|
+
# Identify volumes to remove
|
|
1003
|
+
for vol in volumes:
|
|
1004
|
+
secret_name = mlrun.utils.get_in(vol, "secret.secretName", "")
|
|
1005
|
+
|
|
1006
|
+
# Pattern of auth secret volumes
|
|
1007
|
+
if secret_name.startswith(secret_name_prefix):
|
|
1008
|
+
volumes_to_remove.add(vol["name"])
|
|
1009
|
+
|
|
1010
|
+
# Filter out only the matched volumes
|
|
1011
|
+
self.spec.volumes = [
|
|
1012
|
+
volume for volume in volumes if volume["name"] not in volumes_to_remove
|
|
1013
|
+
]
|
|
1014
|
+
|
|
1015
|
+
# Filter out matching mounts
|
|
1016
|
+
self.spec.volume_mounts = [
|
|
1017
|
+
mount for mount in mounts if mount["name"] not in volumes_to_remove
|
|
1018
|
+
]
|
|
1019
|
+
|
|
952
1020
|
def skip_image_enrichment(self):
|
|
953
1021
|
return False
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Copyright 2023 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import typing
|
|
16
|
+
|
|
17
|
+
import mlrun.runtimes.nuclio as nuclio_runtime
|
|
18
|
+
import mlrun.runtimes.nuclio.application as nuclio_application
|
|
19
|
+
import mlrun.runtimes.nuclio.serving as nuclio_serving
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class RuntimeKinds:
|
|
23
|
+
remote = "remote"
|
|
24
|
+
nuclio = "nuclio"
|
|
25
|
+
dask = "dask"
|
|
26
|
+
job = "job"
|
|
27
|
+
spark = "spark"
|
|
28
|
+
remotespark = "remote-spark"
|
|
29
|
+
mpijob = "mpijob"
|
|
30
|
+
serving = "serving"
|
|
31
|
+
local = "local"
|
|
32
|
+
handler = "handler"
|
|
33
|
+
databricks = "databricks"
|
|
34
|
+
application = "application"
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def all():
|
|
38
|
+
return [
|
|
39
|
+
RuntimeKinds.remote,
|
|
40
|
+
RuntimeKinds.nuclio,
|
|
41
|
+
RuntimeKinds.serving,
|
|
42
|
+
RuntimeKinds.dask,
|
|
43
|
+
RuntimeKinds.job,
|
|
44
|
+
RuntimeKinds.spark,
|
|
45
|
+
RuntimeKinds.remotespark,
|
|
46
|
+
RuntimeKinds.mpijob,
|
|
47
|
+
RuntimeKinds.local,
|
|
48
|
+
RuntimeKinds.databricks,
|
|
49
|
+
RuntimeKinds.application,
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def runtime_with_handlers():
|
|
54
|
+
return [
|
|
55
|
+
RuntimeKinds.dask,
|
|
56
|
+
RuntimeKinds.job,
|
|
57
|
+
RuntimeKinds.spark,
|
|
58
|
+
RuntimeKinds.remotespark,
|
|
59
|
+
RuntimeKinds.mpijob,
|
|
60
|
+
RuntimeKinds.databricks,
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def abortable_runtimes():
|
|
65
|
+
return [
|
|
66
|
+
RuntimeKinds.job,
|
|
67
|
+
RuntimeKinds.spark,
|
|
68
|
+
RuntimeKinds.remotespark,
|
|
69
|
+
RuntimeKinds.mpijob,
|
|
70
|
+
RuntimeKinds.databricks,
|
|
71
|
+
RuntimeKinds.local,
|
|
72
|
+
RuntimeKinds.handler,
|
|
73
|
+
"",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def retriable_runtimes():
|
|
78
|
+
return [
|
|
79
|
+
RuntimeKinds.job,
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def nuclio_runtimes():
|
|
84
|
+
return [
|
|
85
|
+
RuntimeKinds.remote,
|
|
86
|
+
RuntimeKinds.nuclio,
|
|
87
|
+
RuntimeKinds.serving,
|
|
88
|
+
RuntimeKinds.application,
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def pure_nuclio_deployed_runtimes():
|
|
93
|
+
return [
|
|
94
|
+
RuntimeKinds.remote,
|
|
95
|
+
RuntimeKinds.nuclio,
|
|
96
|
+
RuntimeKinds.serving,
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def handlerless_runtimes():
|
|
101
|
+
return [
|
|
102
|
+
RuntimeKinds.serving,
|
|
103
|
+
# Application runtime handler is internal reverse proxy
|
|
104
|
+
RuntimeKinds.application,
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
def local_runtimes():
|
|
109
|
+
return [
|
|
110
|
+
RuntimeKinds.local,
|
|
111
|
+
RuntimeKinds.handler,
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def is_log_collectable_runtime(kind: typing.Optional[str]):
|
|
116
|
+
"""
|
|
117
|
+
whether log collector can collect logs for that runtime
|
|
118
|
+
:param kind: kind name
|
|
119
|
+
:return: whether log collector can collect logs for that runtime
|
|
120
|
+
"""
|
|
121
|
+
# if local run, the log collector doesn't support it as it is only supports k8s resources
|
|
122
|
+
# when runtime is local the client is responsible for logging the stdout of the run by using `log_std`
|
|
123
|
+
if RuntimeKinds.is_local_runtime(kind):
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
if (
|
|
127
|
+
kind
|
|
128
|
+
not in [
|
|
129
|
+
# dask implementation is different from other runtimes, because few runs can be run against the same
|
|
130
|
+
# runtime resource, so collecting logs on that runtime resource won't be correct, the way we collect
|
|
131
|
+
# logs for dask is by using `log_std` on client side after we execute the code against the cluster,
|
|
132
|
+
# as submitting the run with the dask client will return the run stdout.
|
|
133
|
+
# For more information head to `DaskCluster._run`.
|
|
134
|
+
RuntimeKinds.dask
|
|
135
|
+
]
|
|
136
|
+
+ RuntimeKinds.nuclio_runtimes()
|
|
137
|
+
):
|
|
138
|
+
return True
|
|
139
|
+
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def is_local_runtime(kind):
|
|
144
|
+
# "" or None counted as local
|
|
145
|
+
if not kind or kind in RuntimeKinds.local_runtimes():
|
|
146
|
+
return True
|
|
147
|
+
return False
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def requires_k8s_name_validation(kind: str) -> bool:
|
|
151
|
+
"""
|
|
152
|
+
Returns True if the runtime kind creates Kubernetes resources that use the function name.
|
|
153
|
+
|
|
154
|
+
Function names for k8s-deployed runtimes must conform to DNS-1123 label requirements:
|
|
155
|
+
- Lowercase alphanumeric characters or '-'
|
|
156
|
+
- Start and end with an alphanumeric character
|
|
157
|
+
- Maximum 63 characters
|
|
158
|
+
|
|
159
|
+
Local runtimes (local, handler) run on the local machine and don't create k8s resources,
|
|
160
|
+
so they don't require k8s naming validation.
|
|
161
|
+
|
|
162
|
+
:param kind: Runtime kind string (job, spark, serving, local, etc.)
|
|
163
|
+
:return: True if function name needs k8s DNS-1123 validation, False otherwise
|
|
164
|
+
"""
|
|
165
|
+
return not RuntimeKinds.is_local_runtime(kind)
|
|
166
|
+
|
|
167
|
+
@staticmethod
|
|
168
|
+
def requires_absolute_artifacts_path(kind):
|
|
169
|
+
"""
|
|
170
|
+
Returns True if the runtime kind requires absolute artifacts' path (i.e. is local), False otherwise.
|
|
171
|
+
"""
|
|
172
|
+
if RuntimeKinds.is_local_runtime(kind):
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
if kind not in [
|
|
176
|
+
# logging artifacts is done externally to the dask cluster by a client that can either run locally (in which
|
|
177
|
+
# case the path can be relative) or remotely (in which case the path must be absolute and will be passed
|
|
178
|
+
# to another run)
|
|
179
|
+
RuntimeKinds.dask
|
|
180
|
+
]:
|
|
181
|
+
return True
|
|
182
|
+
return False
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def requires_image_name_for_execution(kind):
|
|
186
|
+
if RuntimeKinds.is_local_runtime(kind):
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
# both spark and remote spark uses different mechanism for assigning images
|
|
190
|
+
return kind not in [RuntimeKinds.spark, RuntimeKinds.remotespark]
|
|
191
|
+
|
|
192
|
+
@staticmethod
|
|
193
|
+
def supports_from_notebook(kind):
|
|
194
|
+
return kind not in [RuntimeKinds.application]
|
|
195
|
+
|
|
196
|
+
@staticmethod
|
|
197
|
+
def resolve_nuclio_runtime(kind: str, sub_kind: str):
|
|
198
|
+
kind = kind.split(":")[0]
|
|
199
|
+
if kind not in RuntimeKinds.nuclio_runtimes():
|
|
200
|
+
raise ValueError(
|
|
201
|
+
f"Kind {kind} is not a nuclio runtime, "
|
|
202
|
+
f"available runtimes are {RuntimeKinds.nuclio_runtimes()}"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# These names are imported at module level below; referenced at call-time (no imports here).
|
|
206
|
+
if sub_kind == nuclio_serving.serving_subkind:
|
|
207
|
+
return nuclio_runtime.ServingRuntime()
|
|
208
|
+
|
|
209
|
+
if kind == RuntimeKinds.application:
|
|
210
|
+
return nuclio_application.ApplicationRuntime()
|
|
211
|
+
|
|
212
|
+
runtime = nuclio_runtime.RemoteRuntime()
|
|
213
|
+
runtime.spec.function_kind = sub_kind
|
|
214
|
+
return runtime
|
|
215
|
+
|
|
216
|
+
@staticmethod
|
|
217
|
+
def resolve_nuclio_sub_kind(kind: str):
|
|
218
|
+
is_nuclio = kind.startswith("nuclio")
|
|
219
|
+
sub_kind = kind[kind.find(":") + 1 :] if is_nuclio and ":" in kind else None
|
|
220
|
+
if kind == RuntimeKinds.serving:
|
|
221
|
+
is_nuclio = True
|
|
222
|
+
sub_kind = nuclio_serving.serving_subkind
|
|
223
|
+
elif kind == RuntimeKinds.application:
|
|
224
|
+
is_nuclio = True
|
|
225
|
+
return is_nuclio, sub_kind
|
mlrun/runtimes/daskjob.py
CHANGED
|
@@ -15,8 +15,9 @@ import datetime
|
|
|
15
15
|
import inspect
|
|
16
16
|
import socket
|
|
17
17
|
import time
|
|
18
|
+
from collections.abc import Callable
|
|
18
19
|
from os import environ
|
|
19
|
-
from typing import
|
|
20
|
+
from typing import Optional, Union
|
|
20
21
|
|
|
21
22
|
import mlrun.common.schemas
|
|
22
23
|
import mlrun.errors
|
|
@@ -551,7 +552,8 @@ class DaskCluster(KubejobRuntime):
|
|
|
551
552
|
|
|
552
553
|
# TODO: investigate if the following instructions could overwrite the environment on any MLRun API Pod
|
|
553
554
|
# Such action could result on race conditions against other runtimes and MLRun itself
|
|
554
|
-
extra_env = self._generate_runtime_env(runobj)
|
|
555
|
+
extra_env, _ = self._generate_runtime_env(runobj)
|
|
556
|
+
# Since it runs locally, we don't need the external sources env vars
|
|
555
557
|
environ.update(extra_env)
|
|
556
558
|
|
|
557
559
|
context = MLClientCtx.from_dict(
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
import typing
|
|
15
15
|
from ast import FunctionDef, parse, unparse
|
|
16
16
|
from base64 import b64decode
|
|
17
|
-
from
|
|
17
|
+
from collections.abc import Callable
|
|
18
|
+
from typing import Optional, Union
|
|
18
19
|
|
|
19
20
|
import mlrun
|
|
20
21
|
import mlrun.runtimes.kubejob as kubejob
|
mlrun/runtimes/mounts.py
CHANGED
|
@@ -17,6 +17,8 @@ import typing
|
|
|
17
17
|
import warnings
|
|
18
18
|
from collections import namedtuple
|
|
19
19
|
|
|
20
|
+
import mlrun.common.secrets
|
|
21
|
+
import mlrun.errors
|
|
20
22
|
from mlrun.config import config
|
|
21
23
|
from mlrun.config import config as mlconf
|
|
22
24
|
from mlrun.errors import MLRunInvalidArgumentError
|
|
@@ -412,6 +414,9 @@ def mount_secret(
|
|
|
412
414
|
the specified paths, and unlisted keys will not be
|
|
413
415
|
present."""
|
|
414
416
|
|
|
417
|
+
if secret_name:
|
|
418
|
+
mlrun.common.secrets.validate_not_forbidden_secret(secret_name.strip())
|
|
419
|
+
|
|
415
420
|
def _mount_secret(runtime: "KubeResource"):
|
|
416
421
|
# Define the secret volume source
|
|
417
422
|
secret_volume_source = {
|
|
@@ -12,11 +12,15 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
import mlrun.runtimes.nuclio.serving as nuclio_serving # noqa
|
|
16
|
+
import mlrun.runtimes.nuclio.nuclio as nuclio_nuclio # noqa
|
|
17
|
+
import mlrun.runtimes.nuclio.function as nuclio_function # noqa
|
|
18
|
+
import mlrun.runtimes.nuclio.api_gateway as nuclio_api_gateway # noqa
|
|
19
|
+
|
|
20
|
+
ServingRuntime = nuclio_serving.ServingRuntime
|
|
21
|
+
new_v2_model_server = nuclio_serving.new_v2_model_server
|
|
22
|
+
nuclio_init_hook = nuclio_nuclio.nuclio_init_hook
|
|
23
|
+
min_nuclio_versions = nuclio_function.min_nuclio_versions
|
|
24
|
+
multiple_port_sidecar_is_supported = nuclio_function.multiple_port_sidecar_is_supported
|
|
25
|
+
RemoteRuntime = nuclio_function.RemoteRuntime
|
|
26
|
+
APIGateway = nuclio_api_gateway.APIGateway
|
|
@@ -17,13 +17,14 @@ from typing import Optional, Union
|
|
|
17
17
|
from urllib.parse import urljoin
|
|
18
18
|
|
|
19
19
|
import requests
|
|
20
|
-
from nuclio.auth import AuthInfo as NuclioAuthInfo
|
|
21
20
|
from nuclio.auth import AuthKinds as NuclioAuthKinds
|
|
22
21
|
|
|
23
22
|
import mlrun
|
|
23
|
+
import mlrun.auth.nuclio
|
|
24
24
|
import mlrun.common.constants as mlrun_constants
|
|
25
25
|
import mlrun.common.helpers
|
|
26
26
|
import mlrun.common.schemas as schemas
|
|
27
|
+
import mlrun.common.schemas.auth
|
|
27
28
|
import mlrun.common.types
|
|
28
29
|
from mlrun.model import ModelObj
|
|
29
30
|
from mlrun.platforms.iguazio import min_iguazio_versions
|
|
@@ -55,6 +56,11 @@ class Authenticator(typing.Protocol):
|
|
|
55
56
|
== schemas.APIGatewayAuthenticationMode.access_key.value
|
|
56
57
|
):
|
|
57
58
|
return AccessKeyAuth()
|
|
59
|
+
elif (
|
|
60
|
+
api_gateway_spec.authenticationMode
|
|
61
|
+
== schemas.APIGatewayAuthenticationMode.iguazio.value
|
|
62
|
+
):
|
|
63
|
+
return IguazioAuth()
|
|
58
64
|
else:
|
|
59
65
|
return NoneAuth()
|
|
60
66
|
|
|
@@ -112,6 +118,16 @@ class AccessKeyAuth(APIGatewayAuthenticator):
|
|
|
112
118
|
return schemas.APIGatewayAuthenticationMode.access_key.value
|
|
113
119
|
|
|
114
120
|
|
|
121
|
+
class IguazioAuth(APIGatewayAuthenticator):
|
|
122
|
+
"""
|
|
123
|
+
An API gateway authenticator with Iguazio authentication.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def authentication_mode(self) -> str:
|
|
128
|
+
return schemas.APIGatewayAuthenticationMode.iguazio.value
|
|
129
|
+
|
|
130
|
+
|
|
115
131
|
class APIGatewayMetadata(ModelObj):
|
|
116
132
|
_dict_fields = ["name", "namespace", "labels", "annotations", "creation_timestamp"]
|
|
117
133
|
|
|
@@ -430,7 +446,7 @@ class APIGateway(ModelObj):
|
|
|
430
446
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
431
447
|
"API Gateway invocation requires authentication. Please pass credentials"
|
|
432
448
|
)
|
|
433
|
-
auth = NuclioAuthInfo(
|
|
449
|
+
auth = mlrun.auth.nuclio.NuclioAuthInfo(
|
|
434
450
|
username=credentials[0], password=credentials[1]
|
|
435
451
|
).to_requests_auth()
|
|
436
452
|
|
|
@@ -440,23 +456,30 @@ class APIGateway(ModelObj):
|
|
|
440
456
|
):
|
|
441
457
|
# inject access key from env
|
|
442
458
|
if credentials:
|
|
443
|
-
auth = NuclioAuthInfo(
|
|
459
|
+
auth = mlrun.auth.nuclio.NuclioAuthInfo(
|
|
444
460
|
username=credentials[0],
|
|
445
461
|
password=credentials[1],
|
|
446
462
|
mode=NuclioAuthKinds.iguazio,
|
|
447
463
|
).to_requests_auth()
|
|
448
464
|
else:
|
|
449
|
-
auth =
|
|
465
|
+
auth = (
|
|
466
|
+
mlrun.auth.nuclio.NuclioAuthInfo().from_envvar().to_requests_auth()
|
|
467
|
+
)
|
|
450
468
|
if not auth:
|
|
451
469
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
452
470
|
"API Gateway invocation requires authentication. Please set V3IO_ACCESS_KEY env var"
|
|
453
471
|
)
|
|
472
|
+
if (
|
|
473
|
+
self.spec.authentication.authentication_mode
|
|
474
|
+
== schemas.APIGatewayAuthenticationMode.iguazio.value
|
|
475
|
+
):
|
|
476
|
+
auth = mlrun.auth.nuclio.NuclioAuthInfo.from_envvar().to_requests_auth()
|
|
454
477
|
url = urljoin(self.invoke_url, path or "")
|
|
455
478
|
|
|
456
479
|
# Determine the correct keyword argument for the body
|
|
457
480
|
if isinstance(body, dict):
|
|
458
481
|
kwargs["json"] = body
|
|
459
|
-
elif isinstance(body,
|
|
482
|
+
elif isinstance(body, str | bytes):
|
|
460
483
|
kwargs["data"] = body
|
|
461
484
|
|
|
462
485
|
return requests.request(
|
|
@@ -527,6 +550,13 @@ class APIGateway(ModelObj):
|
|
|
527
550
|
"""
|
|
528
551
|
self.spec.authentication = AccessKeyAuth()
|
|
529
552
|
|
|
553
|
+
@min_nuclio_versions("1.15.10")
|
|
554
|
+
def with_iguazio_auth(self):
|
|
555
|
+
"""
|
|
556
|
+
Set iguazio authentication for the API gateway.
|
|
557
|
+
"""
|
|
558
|
+
self.spec.authentication = IguazioAuth()
|
|
559
|
+
|
|
530
560
|
def with_canary(
|
|
531
561
|
self,
|
|
532
562
|
functions: Union[
|
|
@@ -692,7 +722,7 @@ class APIGateway(ModelObj):
|
|
|
692
722
|
@staticmethod
|
|
693
723
|
def _generate_basic_auth(username: str, password: str):
|
|
694
724
|
token = base64.b64encode(f"{username}:{password}".encode()).decode()
|
|
695
|
-
return f"
|
|
725
|
+
return f"{mlrun.common.schemas.AuthorizationHeaderPrefixes.basic}{token}"
|
|
696
726
|
|
|
697
727
|
@staticmethod
|
|
698
728
|
def _resolve_canary(
|