mlrun 1.10.0rc18__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 +24 -3
- mlrun/__main__.py +0 -4
- mlrun/artifacts/dataset.py +2 -2
- mlrun/artifacts/document.py +6 -1
- mlrun/artifacts/llm_prompt.py +21 -15
- mlrun/artifacts/model.py +3 -3
- 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 +14 -0
- mlrun/common/model_monitoring/helpers.py +123 -0
- mlrun/common/runtimes/constants.py +28 -0
- mlrun/common/schemas/__init__.py +14 -3
- mlrun/common/schemas/alert.py +2 -2
- mlrun/common/schemas/api_gateway.py +3 -0
- mlrun/common/schemas/auth.py +12 -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 +34 -0
- mlrun/common/schemas/hub.py +33 -20
- mlrun/common/schemas/model_monitoring/__init__.py +2 -1
- mlrun/common/schemas/model_monitoring/constants.py +12 -15
- 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/secret.py +17 -2
- mlrun/common/secrets.py +95 -1
- mlrun/common/types.py +10 -10
- mlrun/config.py +69 -19
- mlrun/data_types/infer.py +2 -2
- mlrun/datastore/__init__.py +12 -5
- mlrun/datastore/azure_blob.py +162 -47
- mlrun/datastore/base.py +274 -10
- mlrun/datastore/datastore.py +7 -2
- mlrun/datastore/datastore_profile.py +84 -22
- mlrun/datastore/model_provider/huggingface_provider.py +225 -41
- mlrun/datastore/model_provider/mock_model_provider.py +87 -0
- mlrun/datastore/model_provider/model_provider.py +206 -74
- mlrun/datastore/model_provider/openai_provider.py +226 -66
- mlrun/datastore/s3.py +39 -18
- mlrun/datastore/sources.py +1 -1
- mlrun/datastore/store_resources.py +4 -4
- mlrun/datastore/storeytargets.py +17 -12
- mlrun/datastore/targets.py +1 -1
- mlrun/datastore/utils.py +25 -6
- mlrun/datastore/v3io.py +1 -1
- mlrun/db/base.py +63 -32
- mlrun/db/httpdb.py +373 -153
- mlrun/db/nopdb.py +54 -21
- mlrun/errors.py +4 -2
- mlrun/execution.py +66 -25
- 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 +52 -0
- mlrun/hub/base.py +142 -0
- mlrun/hub/module.py +172 -0
- mlrun/hub/step.py +113 -0
- mlrun/k8s_utils.py +105 -16
- mlrun/launcher/base.py +15 -7
- mlrun/launcher/local.py +4 -1
- mlrun/model.py +14 -4
- mlrun/model_monitoring/__init__.py +0 -1
- mlrun/model_monitoring/api.py +65 -28
- mlrun/model_monitoring/applications/__init__.py +1 -1
- mlrun/model_monitoring/applications/base.py +299 -128
- mlrun/model_monitoring/applications/context.py +2 -4
- mlrun/model_monitoring/controller.py +132 -58
- mlrun/model_monitoring/db/_schedules.py +38 -29
- mlrun/model_monitoring/db/_stats.py +6 -16
- mlrun/model_monitoring/db/tsdb/__init__.py +9 -7
- mlrun/model_monitoring/db/tsdb/base.py +29 -9
- 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 +20 -9
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +235 -51
- mlrun/model_monitoring/features_drift_table.py +2 -1
- mlrun/model_monitoring/helpers.py +30 -6
- mlrun/model_monitoring/stream_processing.py +34 -28
- mlrun/model_monitoring/writer.py +224 -4
- mlrun/package/__init__.py +2 -1
- mlrun/platforms/__init__.py +0 -43
- mlrun/platforms/iguazio.py +8 -4
- mlrun/projects/operations.py +17 -11
- mlrun/projects/pipelines.py +2 -2
- mlrun/projects/project.py +187 -123
- mlrun/run.py +95 -21
- mlrun/runtimes/__init__.py +2 -186
- mlrun/runtimes/base.py +103 -25
- mlrun/runtimes/constants.py +225 -0
- mlrun/runtimes/daskjob.py +5 -2
- mlrun/runtimes/databricks_job/databricks_runtime.py +2 -1
- mlrun/runtimes/local.py +5 -2
- mlrun/runtimes/mounts.py +20 -2
- mlrun/runtimes/nuclio/__init__.py +12 -7
- mlrun/runtimes/nuclio/api_gateway.py +36 -6
- mlrun/runtimes/nuclio/application/application.py +339 -40
- mlrun/runtimes/nuclio/function.py +222 -72
- mlrun/runtimes/nuclio/serving.py +132 -42
- mlrun/runtimes/pod.py +213 -21
- mlrun/runtimes/utils.py +49 -9
- mlrun/secrets.py +99 -14
- mlrun/serving/__init__.py +2 -0
- mlrun/serving/remote.py +84 -11
- mlrun/serving/routers.py +26 -44
- mlrun/serving/server.py +138 -51
- mlrun/serving/serving_wrapper.py +6 -2
- mlrun/serving/states.py +997 -283
- mlrun/serving/steps.py +62 -0
- mlrun/serving/system_steps.py +149 -95
- mlrun/serving/v2_serving.py +9 -10
- mlrun/track/trackers/mlflow_tracker.py +29 -31
- mlrun/utils/helpers.py +292 -94
- mlrun/utils/http.py +9 -2
- mlrun/utils/notifications/notification/base.py +18 -0
- mlrun/utils/notifications/notification/git.py +3 -5
- mlrun/utils/notifications/notification/mail.py +39 -16
- mlrun/utils/notifications/notification/slack.py +2 -4
- mlrun/utils/notifications/notification/webhook.py +2 -5
- mlrun/utils/notifications/notification_pusher.py +3 -3
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +3 -4
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/METADATA +63 -74
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/RECORD +161 -143
- mlrun/api/schemas/__init__.py +0 -259
- mlrun/db/auth_utils.py +0 -152
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +0 -344
- 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 -1266
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/WHEEL +0 -0
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/entry_points.txt +0 -0
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/top_level.txt +0 -0
mlrun/__init__.py
CHANGED
|
@@ -24,6 +24,7 @@ __all__ = [
|
|
|
24
24
|
"v3io_cred",
|
|
25
25
|
"auto_mount",
|
|
26
26
|
"VolumeMount",
|
|
27
|
+
"sync_secret_tokens",
|
|
27
28
|
]
|
|
28
29
|
|
|
29
30
|
from os import environ, path
|
|
@@ -31,11 +32,13 @@ from typing import Optional
|
|
|
31
32
|
|
|
32
33
|
import dotenv
|
|
33
34
|
|
|
35
|
+
from .common.constants import MLRUN_ACTIVE_PROJECT
|
|
34
36
|
from .config import config as mlconf
|
|
35
37
|
from .datastore import DataItem, ModelProvider, store_manager
|
|
36
38
|
from .db import get_run_db
|
|
37
39
|
from .errors import MLRunInvalidArgumentError, MLRunNotFoundError
|
|
38
40
|
from .execution import MLClientCtx
|
|
41
|
+
from .hub import get_hub_item, get_hub_module, get_hub_step, import_module
|
|
39
42
|
from .model import RunObject, RunTemplate, new_task
|
|
40
43
|
from .package import ArtifactType, DefaultPackager, Packager, handler
|
|
41
44
|
from .projects import (
|
|
@@ -66,7 +69,7 @@ from .run import (
|
|
|
66
69
|
wait_for_pipeline_completion,
|
|
67
70
|
)
|
|
68
71
|
from .runtimes import mounts, new_model_server
|
|
69
|
-
from .secrets import get_secret_or_env
|
|
72
|
+
from .secrets import get_secret_or_env, sync_secret_tokens
|
|
70
73
|
from .utils.version import Version
|
|
71
74
|
|
|
72
75
|
__version__ = Version().get()["version"]
|
|
@@ -167,11 +170,29 @@ def set_environment(
|
|
|
167
170
|
|
|
168
171
|
|
|
169
172
|
def get_current_project(silent: bool = False) -> Optional[MlrunProject]:
|
|
170
|
-
if
|
|
173
|
+
if pipeline_context.project:
|
|
174
|
+
return pipeline_context.project
|
|
175
|
+
|
|
176
|
+
project_name = environ.get(MLRUN_ACTIVE_PROJECT, None)
|
|
177
|
+
if not project_name:
|
|
178
|
+
if not silent:
|
|
179
|
+
raise MLRunInvalidArgumentError(
|
|
180
|
+
"No current project is initialized. Use new, get or load project functions first."
|
|
181
|
+
)
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
project = load_project(
|
|
185
|
+
name=project_name,
|
|
186
|
+
url=project_name,
|
|
187
|
+
save=False,
|
|
188
|
+
sync_functions=False,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if not project and not silent:
|
|
171
192
|
raise MLRunInvalidArgumentError(
|
|
172
193
|
"No current project is initialized. Use new, get or load project functions first."
|
|
173
194
|
)
|
|
174
|
-
return
|
|
195
|
+
return project
|
|
175
196
|
|
|
176
197
|
|
|
177
198
|
def get_sample_path(subpath=""):
|
mlrun/__main__.py
CHANGED
|
@@ -203,7 +203,6 @@ def main():
|
|
|
203
203
|
@click.option(
|
|
204
204
|
"--allow-cross-project",
|
|
205
205
|
is_flag=True,
|
|
206
|
-
default=True, # TODO: remove this default in 1.11
|
|
207
206
|
help="Override the loaded project name. This flag ensures awareness of loading an existing project yaml "
|
|
208
207
|
"as a baseline for a new project with a different name",
|
|
209
208
|
)
|
|
@@ -513,7 +512,6 @@ def run(
|
|
|
513
512
|
@click.option(
|
|
514
513
|
"--allow-cross-project",
|
|
515
514
|
is_flag=True,
|
|
516
|
-
default=True, # TODO: remove this default in 1.11
|
|
517
515
|
help="Override the loaded project name. This flag ensures awareness of loading an existing project yaml "
|
|
518
516
|
"as a baseline for a new project with a different name",
|
|
519
517
|
)
|
|
@@ -672,7 +670,6 @@ def build(
|
|
|
672
670
|
@click.option(
|
|
673
671
|
"--allow-cross-project",
|
|
674
672
|
is_flag=True,
|
|
675
|
-
default=True, # TODO: remove this default in 1.11
|
|
676
673
|
help="Override the loaded project name. This flag ensures awareness of loading an existing project yaml "
|
|
677
674
|
"as a baseline for a new project with a different name",
|
|
678
675
|
)
|
|
@@ -1008,7 +1005,6 @@ def logs(uid, project, offset, db):
|
|
|
1008
1005
|
@click.option(
|
|
1009
1006
|
"--allow-cross-project",
|
|
1010
1007
|
is_flag=True,
|
|
1011
|
-
default=True, # TODO: remove this default in 1.11
|
|
1012
1008
|
help="Override the loaded project name. This flag ensures awareness of loading an existing project yaml "
|
|
1013
1009
|
"as a baseline for a new project with a different name",
|
|
1014
1010
|
)
|
mlrun/artifacts/dataset.py
CHANGED
|
@@ -366,9 +366,9 @@ def get_df_stats(df):
|
|
|
366
366
|
for col, values in df.describe(include="all").items():
|
|
367
367
|
stats_dict = {}
|
|
368
368
|
for stat, val in values.dropna().items():
|
|
369
|
-
if isinstance(val,
|
|
369
|
+
if isinstance(val, float | np.floating | np.float64):
|
|
370
370
|
stats_dict[stat] = float(val)
|
|
371
|
-
elif isinstance(val,
|
|
371
|
+
elif isinstance(val, int | np.integer | np.int64):
|
|
372
372
|
stats_dict[stat] = int(val)
|
|
373
373
|
else:
|
|
374
374
|
stats_dict[stat] = str(val)
|
mlrun/artifacts/document.py
CHANGED
|
@@ -359,7 +359,12 @@ class DocumentArtifact(Artifact):
|
|
|
359
359
|
self,
|
|
360
360
|
splitter: Optional["TextSplitter"] = None, # noqa: F821
|
|
361
361
|
) -> list["Document"]: # noqa: F821
|
|
362
|
-
|
|
362
|
+
# Try new langchain 1.0+ import path first
|
|
363
|
+
try:
|
|
364
|
+
from langchain_core.documents import Document
|
|
365
|
+
except ImportError:
|
|
366
|
+
# Fall back to old langchain <1.0 import path
|
|
367
|
+
from langchain.schema import Document
|
|
363
368
|
|
|
364
369
|
"""
|
|
365
370
|
Create LC documents from the artifact
|
mlrun/artifacts/llm_prompt.py
CHANGED
|
@@ -29,7 +29,7 @@ class LLMPromptArtifactSpec(ArtifactSpec):
|
|
|
29
29
|
_dict_fields = ArtifactSpec._dict_fields + [
|
|
30
30
|
"prompt_template",
|
|
31
31
|
"prompt_legend",
|
|
32
|
-
"
|
|
32
|
+
"invocation_config",
|
|
33
33
|
"description",
|
|
34
34
|
]
|
|
35
35
|
PROMPT_TEMPLATE_KEYS = ("content", "role")
|
|
@@ -41,7 +41,7 @@ class LLMPromptArtifactSpec(ArtifactSpec):
|
|
|
41
41
|
prompt_template: Optional[list[dict]] = None,
|
|
42
42
|
prompt_path: Optional[str] = None,
|
|
43
43
|
prompt_legend: Optional[dict] = None,
|
|
44
|
-
|
|
44
|
+
invocation_config: Optional[dict] = None,
|
|
45
45
|
description: Optional[str] = None,
|
|
46
46
|
target_path: Optional[str] = None,
|
|
47
47
|
**kwargs,
|
|
@@ -62,12 +62,17 @@ class LLMPromptArtifactSpec(ArtifactSpec):
|
|
|
62
62
|
parent_uri=model_artifact.uri
|
|
63
63
|
if isinstance(model_artifact, model_art.ModelArtifact)
|
|
64
64
|
else model_artifact,
|
|
65
|
+
format=kwargs.pop("format", "") or "json",
|
|
65
66
|
**kwargs,
|
|
66
67
|
)
|
|
67
68
|
|
|
68
69
|
self.prompt_template = prompt_template
|
|
69
70
|
self.prompt_legend = prompt_legend
|
|
70
|
-
|
|
71
|
+
if invocation_config is not None and not isinstance(invocation_config, dict):
|
|
72
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
73
|
+
"LLMPromptArtifact invocation_config must be a dictionary or None"
|
|
74
|
+
)
|
|
75
|
+
self.invocation_config = invocation_config or {}
|
|
71
76
|
self.description = description
|
|
72
77
|
self._model_artifact = (
|
|
73
78
|
model_artifact
|
|
@@ -83,19 +88,20 @@ class LLMPromptArtifactSpec(ArtifactSpec):
|
|
|
83
88
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
84
89
|
"Expected prompt_template to be a list of dicts"
|
|
85
90
|
)
|
|
86
|
-
keys_to_pop = []
|
|
87
91
|
for message in prompt_template:
|
|
92
|
+
if set(key.lower() for key in message.keys()) != set(
|
|
93
|
+
self.PROMPT_TEMPLATE_KEYS
|
|
94
|
+
):
|
|
95
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
96
|
+
f"Expected prompt_template to contain dicts with keys "
|
|
97
|
+
f"{self.PROMPT_TEMPLATE_KEYS}, got {message.keys()}"
|
|
98
|
+
)
|
|
99
|
+
keys_to_pop = []
|
|
88
100
|
for key in message.keys():
|
|
89
101
|
if isinstance(key, str):
|
|
90
|
-
if key.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
f"only has keys from {self.PROMPT_TEMPLATE_KEYS}"
|
|
94
|
-
)
|
|
95
|
-
else:
|
|
96
|
-
if not key.islower():
|
|
97
|
-
message[key.lower()] = message[key]
|
|
98
|
-
keys_to_pop.append(key)
|
|
102
|
+
if not key.islower():
|
|
103
|
+
message[key.lower()] = message[key]
|
|
104
|
+
keys_to_pop.append(key)
|
|
99
105
|
else:
|
|
100
106
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
101
107
|
f"Expected prompt_template to contain dict that only"
|
|
@@ -169,7 +175,7 @@ class LLMPromptArtifact(Artifact):
|
|
|
169
175
|
prompt_template: Optional[list[dict]] = None,
|
|
170
176
|
prompt_path: Optional[str] = None,
|
|
171
177
|
prompt_legend: Optional[dict] = None,
|
|
172
|
-
|
|
178
|
+
invocation_config: Optional[dict] = None,
|
|
173
179
|
description: Optional[str] = None,
|
|
174
180
|
target_path=None,
|
|
175
181
|
**kwargs,
|
|
@@ -179,7 +185,7 @@ class LLMPromptArtifact(Artifact):
|
|
|
179
185
|
prompt_path=prompt_path,
|
|
180
186
|
prompt_legend=prompt_legend,
|
|
181
187
|
model_artifact=model_artifact,
|
|
182
|
-
|
|
188
|
+
invocation_config=invocation_config,
|
|
183
189
|
target_path=target_path,
|
|
184
190
|
description=description,
|
|
185
191
|
)
|
mlrun/artifacts/model.py
CHANGED
|
@@ -190,10 +190,10 @@ class ModelArtifact(Artifact):
|
|
|
190
190
|
"""
|
|
191
191
|
super().__init__(key, body, format=format, target_path=target_path, **kwargs)
|
|
192
192
|
model_file = str(model_file or "")
|
|
193
|
-
if model_file and model_url:
|
|
193
|
+
if (model_file or model_dir or body) and model_url:
|
|
194
194
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
195
|
-
"Arguments 'model_file' and '
|
|
196
|
-
" used together with '
|
|
195
|
+
"Arguments 'model_file' and 'model_url' cannot be"
|
|
196
|
+
" used together with 'model_file', 'model_dir' or 'body'."
|
|
197
197
|
)
|
|
198
198
|
if model_file and "/" in model_file:
|
|
199
199
|
if model_dir:
|
mlrun/artifacts/plots.py
CHANGED
|
@@ -42,7 +42,7 @@ class PlotArtifact(Artifact):
|
|
|
42
42
|
import matplotlib
|
|
43
43
|
|
|
44
44
|
if not self.spec.get_body() or not isinstance(
|
|
45
|
-
self.spec.get_body(),
|
|
45
|
+
self.spec.get_body(), bytes | matplotlib.figure.Figure
|
|
46
46
|
):
|
|
47
47
|
raise ValueError(
|
|
48
48
|
"matplotlib fig or png bytes must be provided as artifact body"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 Iguazio
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -11,5 +11,4 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from .tdengine_connector import TDEngineConnector
|
|
14
|
+
from .providers import IGTokenProvider, OAuthClientIDTokenProvider, StaticTokenProvider
|
mlrun/auth/nuclio.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
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 base64
|
|
16
|
+
|
|
17
|
+
import requests.auth
|
|
18
|
+
from nuclio.auth import AuthInfo as _NuclioAuthInfo
|
|
19
|
+
from nuclio.auth import AuthKinds as NuclioAuthKinds
|
|
20
|
+
|
|
21
|
+
import mlrun.auth.providers
|
|
22
|
+
import mlrun.common.schemas.auth
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class NuclioAuthInfo(_NuclioAuthInfo):
|
|
26
|
+
def __init__(self, token=None, **kwargs):
|
|
27
|
+
super().__init__(**kwargs)
|
|
28
|
+
self._token = token
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def from_auth_info(cls, auth_info: "mlrun.common.schemas.auth.AuthInfo"):
|
|
32
|
+
if not auth_info:
|
|
33
|
+
return None
|
|
34
|
+
if mlrun.mlconf.is_iguazio_v4_mode():
|
|
35
|
+
return cls.from_request_headers(auth_info.request_headers)
|
|
36
|
+
if auth_info.session != "":
|
|
37
|
+
return NuclioAuthInfo(
|
|
38
|
+
password=auth_info.session, mode=NuclioAuthKinds.iguazio
|
|
39
|
+
)
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def from_request_headers(cls, headers: dict[str, str]):
|
|
44
|
+
if not headers:
|
|
45
|
+
return cls()
|
|
46
|
+
for key, value in headers.items():
|
|
47
|
+
if key.lower() == "authorization":
|
|
48
|
+
if value.lower().startswith("bearer "):
|
|
49
|
+
return cls(
|
|
50
|
+
token=value[len("bearer ") :],
|
|
51
|
+
mode=NuclioAuthKinds.iguazio,
|
|
52
|
+
)
|
|
53
|
+
if value.lower().startswith("basic "):
|
|
54
|
+
token = value[len("basic ") :]
|
|
55
|
+
decoded_token = base64.b64decode(token).decode("utf-8")
|
|
56
|
+
username, password = decoded_token.split(":", 1)
|
|
57
|
+
return cls(
|
|
58
|
+
username=username,
|
|
59
|
+
password=password,
|
|
60
|
+
mode=NuclioAuthKinds.iguazio,
|
|
61
|
+
)
|
|
62
|
+
return cls()
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def from_envvar(cls):
|
|
66
|
+
if mlrun.mlconf.is_iguazio_v4_mode():
|
|
67
|
+
token_provider = mlrun.auth.providers.IGTokenProvider(
|
|
68
|
+
token_endpoint=mlrun.mlconf.auth_token_endpoint,
|
|
69
|
+
)
|
|
70
|
+
return cls(
|
|
71
|
+
token=token_provider.get_token(),
|
|
72
|
+
mode=NuclioAuthKinds.iguazio,
|
|
73
|
+
)
|
|
74
|
+
return super().from_envvar()
|
|
75
|
+
|
|
76
|
+
def to_requests_auth(self) -> "requests.auth":
|
|
77
|
+
if self._token:
|
|
78
|
+
# in iguazio v4 mode we use bearer token auth
|
|
79
|
+
return _RequestAuthBearerToken(self._token)
|
|
80
|
+
return super().to_requests_auth()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class _RequestAuthBearerToken(requests.auth.AuthBase):
|
|
84
|
+
def __init__(self, token: str):
|
|
85
|
+
self._token = token
|
|
86
|
+
|
|
87
|
+
def __call__(self, r):
|
|
88
|
+
r.headers["Authorization"] = f"Bearer {self._token}"
|
|
89
|
+
return r
|