mlrun 1.7.2rc3__py3-none-any.whl → 1.8.0__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 +26 -22
- mlrun/__main__.py +15 -16
- mlrun/alerts/alert.py +150 -15
- mlrun/api/schemas/__init__.py +1 -9
- mlrun/artifacts/__init__.py +2 -3
- mlrun/artifacts/base.py +62 -19
- mlrun/artifacts/dataset.py +17 -17
- mlrun/artifacts/document.py +454 -0
- mlrun/artifacts/manager.py +28 -18
- mlrun/artifacts/model.py +91 -59
- mlrun/artifacts/plots.py +2 -2
- mlrun/common/constants.py +8 -0
- mlrun/common/formatters/__init__.py +1 -0
- mlrun/common/formatters/artifact.py +1 -1
- mlrun/common/formatters/feature_set.py +2 -0
- mlrun/common/formatters/function.py +1 -0
- mlrun/{model_monitoring/db/stores/v3io_kv/__init__.py → common/formatters/model_endpoint.py} +17 -0
- mlrun/common/formatters/pipeline.py +1 -2
- mlrun/common/formatters/project.py +9 -0
- mlrun/common/model_monitoring/__init__.py +0 -5
- mlrun/common/model_monitoring/helpers.py +12 -62
- mlrun/common/runtimes/constants.py +25 -4
- mlrun/common/schemas/__init__.py +9 -5
- mlrun/common/schemas/alert.py +114 -19
- mlrun/common/schemas/api_gateway.py +3 -3
- mlrun/common/schemas/artifact.py +22 -9
- mlrun/common/schemas/auth.py +8 -4
- mlrun/common/schemas/background_task.py +7 -7
- mlrun/common/schemas/client_spec.py +4 -4
- mlrun/common/schemas/clusterization_spec.py +2 -2
- mlrun/common/schemas/common.py +53 -3
- mlrun/common/schemas/constants.py +15 -0
- mlrun/common/schemas/datastore_profile.py +1 -1
- mlrun/common/schemas/feature_store.py +9 -9
- mlrun/common/schemas/frontend_spec.py +4 -4
- mlrun/common/schemas/function.py +10 -10
- mlrun/common/schemas/hub.py +1 -1
- mlrun/common/schemas/k8s.py +3 -3
- mlrun/common/schemas/memory_reports.py +3 -3
- mlrun/common/schemas/model_monitoring/__init__.py +4 -8
- mlrun/common/schemas/model_monitoring/constants.py +127 -46
- mlrun/common/schemas/model_monitoring/grafana.py +18 -12
- mlrun/common/schemas/model_monitoring/model_endpoints.py +154 -160
- mlrun/common/schemas/notification.py +24 -3
- mlrun/common/schemas/object.py +1 -1
- mlrun/common/schemas/pagination.py +4 -4
- mlrun/common/schemas/partition.py +142 -0
- mlrun/common/schemas/pipeline.py +3 -3
- mlrun/common/schemas/project.py +26 -18
- mlrun/common/schemas/runs.py +3 -3
- mlrun/common/schemas/runtime_resource.py +5 -5
- mlrun/common/schemas/schedule.py +1 -1
- mlrun/common/schemas/secret.py +1 -1
- mlrun/{model_monitoring/db/stores/sqldb/__init__.py → common/schemas/serving.py} +10 -1
- mlrun/common/schemas/tag.py +3 -3
- mlrun/common/schemas/workflow.py +6 -5
- mlrun/common/types.py +1 -0
- mlrun/config.py +157 -89
- mlrun/data_types/__init__.py +5 -3
- mlrun/data_types/infer.py +13 -3
- mlrun/data_types/spark.py +2 -1
- mlrun/datastore/__init__.py +59 -18
- mlrun/datastore/alibaba_oss.py +4 -1
- mlrun/datastore/azure_blob.py +4 -1
- mlrun/datastore/base.py +19 -24
- mlrun/datastore/datastore.py +10 -4
- mlrun/datastore/datastore_profile.py +178 -45
- mlrun/datastore/dbfs_store.py +4 -1
- mlrun/datastore/filestore.py +4 -1
- mlrun/datastore/google_cloud_storage.py +4 -1
- mlrun/datastore/hdfs.py +4 -1
- mlrun/datastore/inmem.py +4 -1
- mlrun/datastore/redis.py +4 -1
- mlrun/datastore/s3.py +14 -3
- mlrun/datastore/sources.py +89 -92
- mlrun/datastore/store_resources.py +7 -4
- mlrun/datastore/storeytargets.py +51 -16
- mlrun/datastore/targets.py +38 -31
- mlrun/datastore/utils.py +87 -4
- mlrun/datastore/v3io.py +4 -1
- mlrun/datastore/vectorstore.py +291 -0
- mlrun/datastore/wasbfs/fs.py +13 -12
- mlrun/db/base.py +286 -100
- mlrun/db/httpdb.py +1562 -490
- mlrun/db/nopdb.py +250 -83
- mlrun/errors.py +6 -2
- mlrun/execution.py +194 -50
- mlrun/feature_store/__init__.py +2 -10
- mlrun/feature_store/api.py +20 -458
- mlrun/feature_store/common.py +9 -9
- mlrun/feature_store/feature_set.py +20 -18
- mlrun/feature_store/feature_vector.py +105 -479
- mlrun/feature_store/feature_vector_utils.py +466 -0
- mlrun/feature_store/retrieval/base.py +15 -11
- mlrun/feature_store/retrieval/job.py +2 -1
- mlrun/feature_store/retrieval/storey_merger.py +1 -1
- mlrun/feature_store/steps.py +3 -3
- mlrun/features.py +30 -13
- mlrun/frameworks/__init__.py +1 -2
- mlrun/frameworks/_common/__init__.py +1 -2
- mlrun/frameworks/_common/artifacts_library.py +2 -2
- mlrun/frameworks/_common/mlrun_interface.py +10 -6
- mlrun/frameworks/_common/model_handler.py +31 -31
- mlrun/frameworks/_common/producer.py +3 -1
- mlrun/frameworks/_dl_common/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
- mlrun/frameworks/_ml_common/__init__.py +1 -2
- mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_ml_common/model_handler.py +21 -21
- mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/auto_mlrun/__init__.py +1 -2
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
- mlrun/frameworks/huggingface/__init__.py +1 -2
- mlrun/frameworks/huggingface/model_server.py +9 -9
- mlrun/frameworks/lgbm/__init__.py +47 -44
- mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
- mlrun/frameworks/lgbm/model_handler.py +15 -11
- mlrun/frameworks/lgbm/model_server.py +11 -7
- mlrun/frameworks/lgbm/utils.py +2 -2
- mlrun/frameworks/onnx/__init__.py +1 -2
- mlrun/frameworks/onnx/dataset.py +3 -3
- mlrun/frameworks/onnx/mlrun_interface.py +2 -2
- mlrun/frameworks/onnx/model_handler.py +7 -5
- mlrun/frameworks/onnx/model_server.py +8 -6
- mlrun/frameworks/parallel_coordinates.py +11 -11
- mlrun/frameworks/pytorch/__init__.py +22 -23
- mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
- mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
- mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
- mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
- mlrun/frameworks/pytorch/model_handler.py +21 -17
- mlrun/frameworks/pytorch/model_server.py +13 -9
- mlrun/frameworks/sklearn/__init__.py +19 -18
- mlrun/frameworks/sklearn/estimator.py +2 -2
- mlrun/frameworks/sklearn/metric.py +3 -3
- mlrun/frameworks/sklearn/metrics_library.py +8 -6
- mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
- mlrun/frameworks/sklearn/model_handler.py +4 -3
- mlrun/frameworks/tf_keras/__init__.py +11 -12
- mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
- mlrun/frameworks/tf_keras/model_handler.py +17 -13
- mlrun/frameworks/tf_keras/model_server.py +12 -8
- mlrun/frameworks/xgboost/__init__.py +19 -18
- mlrun/frameworks/xgboost/model_handler.py +13 -9
- mlrun/k8s_utils.py +2 -5
- mlrun/launcher/base.py +3 -4
- mlrun/launcher/client.py +2 -2
- mlrun/launcher/local.py +6 -2
- mlrun/launcher/remote.py +1 -1
- mlrun/lists.py +8 -4
- mlrun/model.py +132 -46
- mlrun/model_monitoring/__init__.py +3 -5
- mlrun/model_monitoring/api.py +113 -98
- mlrun/model_monitoring/applications/__init__.py +0 -5
- mlrun/model_monitoring/applications/_application_steps.py +81 -50
- mlrun/model_monitoring/applications/base.py +467 -14
- mlrun/model_monitoring/applications/context.py +212 -134
- mlrun/model_monitoring/{db/stores/base → applications/evidently}/__init__.py +6 -2
- mlrun/model_monitoring/applications/evidently/base.py +146 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +89 -56
- mlrun/model_monitoring/applications/results.py +67 -15
- mlrun/model_monitoring/controller.py +701 -315
- mlrun/model_monitoring/db/__init__.py +0 -2
- mlrun/model_monitoring/db/_schedules.py +242 -0
- mlrun/model_monitoring/db/_stats.py +189 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +33 -22
- mlrun/model_monitoring/db/tsdb/base.py +243 -49
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +76 -36
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +213 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +534 -88
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +436 -106
- mlrun/model_monitoring/helpers.py +356 -114
- mlrun/model_monitoring/stream_processing.py +190 -345
- mlrun/model_monitoring/tracking_policy.py +11 -4
- mlrun/model_monitoring/writer.py +49 -90
- mlrun/package/__init__.py +3 -6
- mlrun/package/context_handler.py +2 -2
- mlrun/package/packager.py +12 -9
- mlrun/package/packagers/__init__.py +0 -2
- mlrun/package/packagers/default_packager.py +14 -11
- mlrun/package/packagers/numpy_packagers.py +16 -7
- mlrun/package/packagers/pandas_packagers.py +18 -18
- mlrun/package/packagers/python_standard_library_packagers.py +25 -11
- mlrun/package/packagers_manager.py +35 -32
- mlrun/package/utils/__init__.py +0 -3
- mlrun/package/utils/_pickler.py +6 -6
- mlrun/platforms/__init__.py +47 -16
- mlrun/platforms/iguazio.py +4 -1
- mlrun/projects/operations.py +30 -30
- mlrun/projects/pipelines.py +116 -47
- mlrun/projects/project.py +1292 -329
- mlrun/render.py +5 -9
- mlrun/run.py +57 -14
- mlrun/runtimes/__init__.py +1 -3
- mlrun/runtimes/base.py +30 -22
- mlrun/runtimes/daskjob.py +9 -9
- mlrun/runtimes/databricks_job/databricks_runtime.py +6 -5
- mlrun/runtimes/function_reference.py +5 -2
- mlrun/runtimes/generators.py +3 -2
- mlrun/runtimes/kubejob.py +6 -7
- mlrun/runtimes/mounts.py +574 -0
- mlrun/runtimes/mpijob/__init__.py +0 -2
- mlrun/runtimes/mpijob/abstract.py +7 -6
- mlrun/runtimes/nuclio/api_gateway.py +7 -7
- mlrun/runtimes/nuclio/application/application.py +11 -13
- mlrun/runtimes/nuclio/application/reverse_proxy.go +66 -64
- mlrun/runtimes/nuclio/function.py +127 -70
- mlrun/runtimes/nuclio/serving.py +105 -37
- mlrun/runtimes/pod.py +159 -54
- mlrun/runtimes/remotesparkjob.py +3 -2
- mlrun/runtimes/sparkjob/__init__.py +0 -2
- mlrun/runtimes/sparkjob/spark3job.py +22 -12
- mlrun/runtimes/utils.py +7 -6
- mlrun/secrets.py +2 -2
- mlrun/serving/__init__.py +8 -0
- mlrun/serving/merger.py +7 -5
- mlrun/serving/remote.py +35 -22
- mlrun/serving/routers.py +186 -240
- mlrun/serving/server.py +41 -10
- mlrun/serving/states.py +432 -118
- mlrun/serving/utils.py +13 -2
- mlrun/serving/v1_serving.py +3 -2
- mlrun/serving/v2_serving.py +161 -203
- mlrun/track/__init__.py +1 -1
- mlrun/track/tracker.py +2 -2
- mlrun/track/trackers/mlflow_tracker.py +6 -5
- mlrun/utils/async_http.py +35 -22
- mlrun/utils/clones.py +7 -4
- mlrun/utils/helpers.py +511 -58
- mlrun/utils/logger.py +119 -13
- mlrun/utils/notifications/notification/__init__.py +22 -19
- mlrun/utils/notifications/notification/base.py +39 -15
- mlrun/utils/notifications/notification/console.py +6 -6
- mlrun/utils/notifications/notification/git.py +11 -11
- mlrun/utils/notifications/notification/ipython.py +10 -9
- mlrun/utils/notifications/notification/mail.py +176 -0
- mlrun/utils/notifications/notification/slack.py +16 -8
- mlrun/utils/notifications/notification/webhook.py +24 -8
- mlrun/utils/notifications/notification_pusher.py +191 -200
- mlrun/utils/regex.py +12 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/METADATA +81 -54
- mlrun-1.8.0.dist-info/RECORD +351 -0
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/WHEEL +1 -1
- mlrun/model_monitoring/applications/evidently_base.py +0 -137
- mlrun/model_monitoring/db/stores/__init__.py +0 -136
- mlrun/model_monitoring/db/stores/base/store.py +0 -213
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -71
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -190
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -103
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -40
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -659
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -726
- mlrun/model_monitoring/model_endpoint.py +0 -118
- mlrun-1.7.2rc3.dist-info/RECORD +0 -351
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info/licenses}/LICENSE +0 -0
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/top_level.txt +0 -0
|
@@ -275,7 +275,7 @@ class ApplicationRuntime(RemoteRuntime):
|
|
|
275
275
|
tag="",
|
|
276
276
|
verbose=False,
|
|
277
277
|
auth_info: schemas.AuthInfo = None,
|
|
278
|
-
builder_env: dict = None,
|
|
278
|
+
builder_env: typing.Optional[dict] = None,
|
|
279
279
|
force_build: bool = False,
|
|
280
280
|
with_mlrun=None,
|
|
281
281
|
skip_deployed=False,
|
|
@@ -367,7 +367,7 @@ class ApplicationRuntime(RemoteRuntime):
|
|
|
367
367
|
source,
|
|
368
368
|
workdir=None,
|
|
369
369
|
pull_at_runtime: bool = False,
|
|
370
|
-
target_dir: str = None,
|
|
370
|
+
target_dir: typing.Optional[str] = None,
|
|
371
371
|
):
|
|
372
372
|
"""load the code from git/tar/zip archive at build
|
|
373
373
|
|
|
@@ -426,12 +426,12 @@ class ApplicationRuntime(RemoteRuntime):
|
|
|
426
426
|
|
|
427
427
|
def create_api_gateway(
|
|
428
428
|
self,
|
|
429
|
-
name: str = None,
|
|
430
|
-
path: str = None,
|
|
429
|
+
name: typing.Optional[str] = None,
|
|
430
|
+
path: typing.Optional[str] = None,
|
|
431
431
|
direct_port_access: bool = False,
|
|
432
432
|
authentication_mode: schemas.APIGatewayAuthenticationMode = None,
|
|
433
|
-
authentication_creds: tuple[str, str] = None,
|
|
434
|
-
ssl_redirect: bool = None,
|
|
433
|
+
authentication_creds: typing.Optional[tuple[str, str]] = None,
|
|
434
|
+
ssl_redirect: typing.Optional[bool] = None,
|
|
435
435
|
set_as_default: bool = False,
|
|
436
436
|
gateway_timeout: typing.Optional[int] = None,
|
|
437
437
|
):
|
|
@@ -540,13 +540,12 @@ class ApplicationRuntime(RemoteRuntime):
|
|
|
540
540
|
self,
|
|
541
541
|
path: str = "",
|
|
542
542
|
body: typing.Optional[typing.Union[str, bytes, dict]] = None,
|
|
543
|
-
method: str = None,
|
|
544
|
-
headers: dict = None,
|
|
545
|
-
dashboard: str = "",
|
|
543
|
+
method: typing.Optional[str] = None,
|
|
544
|
+
headers: typing.Optional[dict] = None,
|
|
546
545
|
force_external_address: bool = False,
|
|
547
546
|
auth_info: schemas.AuthInfo = None,
|
|
548
|
-
mock: bool = None,
|
|
549
|
-
credentials: tuple[str, str] = None,
|
|
547
|
+
mock: typing.Optional[bool] = None,
|
|
548
|
+
credentials: typing.Optional[tuple[str, str]] = None,
|
|
550
549
|
**http_client_kwargs,
|
|
551
550
|
):
|
|
552
551
|
self._sync_api_gateway()
|
|
@@ -569,7 +568,6 @@ class ApplicationRuntime(RemoteRuntime):
|
|
|
569
568
|
body,
|
|
570
569
|
method,
|
|
571
570
|
headers,
|
|
572
|
-
dashboard,
|
|
573
571
|
force_external_address,
|
|
574
572
|
auth_info,
|
|
575
573
|
mock,
|
|
@@ -653,7 +651,7 @@ class ApplicationRuntime(RemoteRuntime):
|
|
|
653
651
|
|
|
654
652
|
def _build_application_image(
|
|
655
653
|
self,
|
|
656
|
-
builder_env: dict = None,
|
|
654
|
+
builder_env: typing.Optional[dict] = None,
|
|
657
655
|
force_build: bool = False,
|
|
658
656
|
watch=True,
|
|
659
657
|
with_mlrun=None,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// you may not use this file except in compliance with the License.
|
|
5
5
|
// You may obtain a copy of the License at
|
|
6
6
|
//
|
|
7
|
-
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
8
|
//
|
|
9
9
|
// Unless required by applicable law or agreed to in writing, software
|
|
10
10
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
@@ -14,82 +14,84 @@
|
|
|
14
14
|
package main
|
|
15
15
|
|
|
16
16
|
import (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
"bytes"
|
|
18
|
+
"fmt"
|
|
19
|
+
"net/http"
|
|
20
|
+
"net/http/httptest"
|
|
21
|
+
"net/http/httputil"
|
|
22
|
+
"net/url"
|
|
23
|
+
"os"
|
|
24
|
+
"strings"
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
nuclio "github.com/nuclio/nuclio-sdk-go"
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
func Handler(context *nuclio.Context, event nuclio.Event) (interface{}, error) {
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
reverseProxy := context.UserData.(map[string]interface{})["reverseProxy"].(*httputil.ReverseProxy)
|
|
31
|
+
sidecarUrl := context.UserData.(map[string]interface{})["server"].(string)
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
// populate reverse proxy http request
|
|
34
|
+
httpRequest, err := http.NewRequest(event.GetMethod(), event.GetPath(), bytes.NewReader(event.GetBody()))
|
|
35
|
+
if err != nil {
|
|
36
|
+
context.Logger.ErrorWith("Failed to create a reverse proxy request")
|
|
37
|
+
return nil, err
|
|
38
|
+
}
|
|
39
|
+
for k, v := range event.GetHeaders() {
|
|
40
|
+
httpRequest.Header[k] = []string{v.(string)}
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
// populate query params
|
|
44
|
+
query := httpRequest.URL.Query()
|
|
45
|
+
for k, v := range event.GetFields() {
|
|
46
|
+
query.Set(k, v.(string))
|
|
47
|
+
}
|
|
48
|
+
httpRequest.URL.RawQuery = query.Encode()
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
recorder := httptest.NewRecorder()
|
|
51
|
+
reverseProxy.ServeHTTP(recorder, httpRequest)
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
// send request to sidecar
|
|
54
|
+
context.Logger.DebugWith("Forwarding request to sidecar",
|
|
55
|
+
"sidecarUrl", sidecarUrl,
|
|
56
|
+
"method", event.GetMethod())
|
|
57
|
+
response := recorder.Result()
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
headers := make(map[string]interface{})
|
|
60
|
+
for key, value := range response.Header {
|
|
61
|
+
headers[key] = value[0]
|
|
62
|
+
}
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
// let the processor calculate the content length
|
|
65
|
+
delete(headers, "Content-Length")
|
|
66
|
+
return nuclio.Response{
|
|
67
|
+
StatusCode: response.StatusCode,
|
|
68
|
+
Body: recorder.Body.Bytes(),
|
|
69
|
+
ContentType: response.Header.Get("Content-Type"),
|
|
70
|
+
Headers: headers,
|
|
71
|
+
}, nil
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
func InitContext(context *nuclio.Context) error {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
sidecarHost := os.Getenv("SIDECAR_HOST")
|
|
76
|
+
sidecarPort := os.Getenv("SIDECAR_PORT")
|
|
77
|
+
if sidecarHost == "" {
|
|
78
|
+
sidecarHost = "http://localhost"
|
|
79
|
+
} else if !strings.Contains(sidecarHost, "://") {
|
|
80
|
+
sidecarHost = fmt.Sprintf("http://%s", sidecarHost)
|
|
81
|
+
}
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
// url for request forwarding
|
|
84
|
+
sidecarUrl := fmt.Sprintf("%s:%s", sidecarHost, sidecarPort)
|
|
85
|
+
parsedURL, err := url.Parse(sidecarUrl)
|
|
86
|
+
if err != nil {
|
|
87
|
+
context.Logger.ErrorWith("Failed to parse sidecar url", "sidecarUrl", sidecarUrl)
|
|
88
|
+
return err
|
|
89
|
+
}
|
|
90
|
+
reverseProxy := httputil.NewSingleHostReverseProxy(parsedURL)
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
context.UserData = map[string]interface{}{
|
|
93
|
+
"server": sidecarUrl,
|
|
94
|
+
"reverseProxy": reverseProxy,
|
|
95
|
+
}
|
|
96
|
+
return nil
|
|
95
97
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import asyncio
|
|
16
|
+
import copy
|
|
16
17
|
import json
|
|
17
18
|
import typing
|
|
18
19
|
import warnings
|
|
@@ -26,9 +27,6 @@ import requests
|
|
|
26
27
|
import semver
|
|
27
28
|
from aiohttp.client import ClientSession
|
|
28
29
|
from kubernetes import client
|
|
29
|
-
from mlrun_pipelines.common.mounts import VolumeMount
|
|
30
|
-
from mlrun_pipelines.common.ops import deploy_op
|
|
31
|
-
from mlrun_pipelines.mounts import mount_v3io, v3io_cred
|
|
32
30
|
from nuclio.deploy import find_dashboard_url, get_deploy_status
|
|
33
31
|
from nuclio.triggers import V3IOStreamTrigger
|
|
34
32
|
|
|
@@ -47,9 +45,24 @@ from mlrun.platforms.iguazio import (
|
|
|
47
45
|
split_path,
|
|
48
46
|
)
|
|
49
47
|
from mlrun.runtimes.base import FunctionStatus, RunError
|
|
48
|
+
from mlrun.runtimes.mounts import VolumeMount, mount_v3io, v3io_cred
|
|
50
49
|
from mlrun.runtimes.pod import KubeResource, KubeResourceSpec
|
|
51
50
|
from mlrun.runtimes.utils import get_item_name, log_std
|
|
52
51
|
from mlrun.utils import get_in, logger, update_in
|
|
52
|
+
from mlrun_pipelines.common.ops import deploy_op
|
|
53
|
+
|
|
54
|
+
SENSITIVE_PATHS_IN_TRIGGER_CONFIG = {
|
|
55
|
+
"password",
|
|
56
|
+
"secret",
|
|
57
|
+
"attributes/password",
|
|
58
|
+
"attributes/accesskeyid",
|
|
59
|
+
"attributes/secretaccesskey",
|
|
60
|
+
"attributes/cacert",
|
|
61
|
+
"attributes/accesskey",
|
|
62
|
+
"attributes/accesscertificate",
|
|
63
|
+
"attributes/sasl/password",
|
|
64
|
+
"attributes/sasl/oauth/clientsecret",
|
|
65
|
+
}
|
|
53
66
|
|
|
54
67
|
|
|
55
68
|
def validate_nuclio_version_compatibility(*min_versions):
|
|
@@ -275,6 +288,37 @@ class RemoteRuntime(KubeResource):
|
|
|
275
288
|
if self.metadata.tag:
|
|
276
289
|
mlrun.utils.validate_tag_name(self.metadata.tag, "function.metadata.tag")
|
|
277
290
|
|
|
291
|
+
def mask_sensitive_data_in_config(self):
|
|
292
|
+
if not self.spec.config:
|
|
293
|
+
return {}
|
|
294
|
+
|
|
295
|
+
raw_config = copy.deepcopy(self.spec.config)
|
|
296
|
+
|
|
297
|
+
for key, value in self.spec.config.items():
|
|
298
|
+
if key.startswith("spec.triggers"):
|
|
299
|
+
trigger_name = key.split(".")[-1]
|
|
300
|
+
|
|
301
|
+
for path in SENSITIVE_PATHS_IN_TRIGGER_CONFIG:
|
|
302
|
+
# Handle nested keys
|
|
303
|
+
nested_keys = path.split("/")
|
|
304
|
+
target = value
|
|
305
|
+
for sub_key in nested_keys[:-1]:
|
|
306
|
+
target = target.get(sub_key, {})
|
|
307
|
+
|
|
308
|
+
last_key = nested_keys[-1]
|
|
309
|
+
if last_key in target:
|
|
310
|
+
sensitive_field = target[last_key]
|
|
311
|
+
if sensitive_field.startswith(
|
|
312
|
+
mlrun.model.Credentials.secret_reference_prefix
|
|
313
|
+
):
|
|
314
|
+
# already masked
|
|
315
|
+
continue
|
|
316
|
+
target[last_key] = (
|
|
317
|
+
f"{mlrun.model.Credentials.secret_reference_prefix}/spec/triggers/{trigger_name}/{path}"
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
return raw_config
|
|
321
|
+
|
|
278
322
|
def set_config(self, key, value):
|
|
279
323
|
self.spec.config[key] = value
|
|
280
324
|
return self
|
|
@@ -307,9 +351,12 @@ class RemoteRuntime(KubeResource):
|
|
|
307
351
|
def _validate_triggers(self, spec):
|
|
308
352
|
# ML-7763 / NUC-233
|
|
309
353
|
min_nuclio_version = "1.13.12"
|
|
310
|
-
if
|
|
354
|
+
if (
|
|
311
355
|
mlconf.nuclio_version
|
|
312
|
-
|
|
356
|
+
and mlconf.nuclio_version != "unstable"
|
|
357
|
+
and semver.VersionInfo.parse(mlconf.nuclio_version)
|
|
358
|
+
< semver.VersionInfo.parse(min_nuclio_version)
|
|
359
|
+
):
|
|
313
360
|
explicit_ack_enabled = False
|
|
314
361
|
num_triggers = 0
|
|
315
362
|
trigger_name = spec.get("name", "UNKNOWN")
|
|
@@ -370,8 +417,9 @@ class RemoteRuntime(KubeResource):
|
|
|
370
417
|
)
|
|
371
418
|
"""
|
|
372
419
|
self.spec.build.source = source
|
|
373
|
-
# update handler in function_handler
|
|
374
|
-
|
|
420
|
+
# update handler in function_handler if needed
|
|
421
|
+
if handler:
|
|
422
|
+
self.spec.function_handler = handler
|
|
375
423
|
if workdir:
|
|
376
424
|
self.spec.workdir = workdir
|
|
377
425
|
if runtime:
|
|
@@ -527,6 +575,13 @@ class RemoteRuntime(KubeResource):
|
|
|
527
575
|
access_key = kwargs.pop("access_key", None)
|
|
528
576
|
if not access_key:
|
|
529
577
|
access_key = self._resolve_v3io_access_key()
|
|
578
|
+
engine = "sync"
|
|
579
|
+
explicit_ack_mode = kwargs.pop("explicit_ack_mode", None)
|
|
580
|
+
if self.spec and hasattr(self.spec, "graph"):
|
|
581
|
+
engine = getattr(self.spec.graph, "engine", None) or engine
|
|
582
|
+
|
|
583
|
+
if mlrun.mlconf.is_explicit_ack_enabled() and engine == "async":
|
|
584
|
+
explicit_ack_mode = explicit_ack_mode or "explicitOnly"
|
|
530
585
|
|
|
531
586
|
self.add_trigger(
|
|
532
587
|
name,
|
|
@@ -540,6 +595,7 @@ class RemoteRuntime(KubeResource):
|
|
|
540
595
|
extra_attributes=extra_attributes,
|
|
541
596
|
read_batch_size=256,
|
|
542
597
|
access_key=access_key,
|
|
598
|
+
explicit_ack_mode=explicit_ack_mode,
|
|
543
599
|
**kwargs,
|
|
544
600
|
),
|
|
545
601
|
)
|
|
@@ -554,7 +610,7 @@ class RemoteRuntime(KubeResource):
|
|
|
554
610
|
tag="",
|
|
555
611
|
verbose=False,
|
|
556
612
|
auth_info: AuthInfo = None,
|
|
557
|
-
builder_env: dict = None,
|
|
613
|
+
builder_env: typing.Optional[dict] = None,
|
|
558
614
|
force_build: bool = False,
|
|
559
615
|
):
|
|
560
616
|
"""Deploy the nuclio function to the cluster
|
|
@@ -567,9 +623,9 @@ class RemoteRuntime(KubeResource):
|
|
|
567
623
|
:param force_build: set True for force building the image
|
|
568
624
|
"""
|
|
569
625
|
if auth_info:
|
|
570
|
-
# TODO: remove in 1.
|
|
626
|
+
# TODO: remove in 1.10.0
|
|
571
627
|
warnings.warn(
|
|
572
|
-
"'auth_info' is deprecated for nuclio runtimes in 1.7.0 and will be removed in 1.
|
|
628
|
+
"'auth_info' is deprecated for nuclio runtimes in 1.7.0 and will be removed in 1.10.0",
|
|
573
629
|
FutureWarning,
|
|
574
630
|
)
|
|
575
631
|
|
|
@@ -600,6 +656,18 @@ class RemoteRuntime(KubeResource):
|
|
|
600
656
|
# when a function is deployed, we wait for it to be ready by default
|
|
601
657
|
# this also means that the function object will be updated with the function status
|
|
602
658
|
self._wait_for_function_deployment(db, verbose=verbose)
|
|
659
|
+
# check if there are any background tasks related to creating model endpoints
|
|
660
|
+
model_endpoints_creation_background_tasks = (
|
|
661
|
+
mlrun.common.schemas.BackgroundTaskList(
|
|
662
|
+
**data.pop("background_tasks", {"background_tasks": []})
|
|
663
|
+
).background_tasks
|
|
664
|
+
)
|
|
665
|
+
if model_endpoints_creation_background_tasks:
|
|
666
|
+
self._check_model_endpoint_task_state(
|
|
667
|
+
db=db,
|
|
668
|
+
background_task=model_endpoints_creation_background_tasks[0],
|
|
669
|
+
wait_for_completion=False,
|
|
670
|
+
)
|
|
603
671
|
|
|
604
672
|
return self._enrich_command_from_status()
|
|
605
673
|
|
|
@@ -693,7 +761,9 @@ class RemoteRuntime(KubeResource):
|
|
|
693
761
|
super().with_priority_class(name)
|
|
694
762
|
|
|
695
763
|
def with_service_type(
|
|
696
|
-
self,
|
|
764
|
+
self,
|
|
765
|
+
service_type: str,
|
|
766
|
+
add_templated_ingress_host_mode: typing.Optional[str] = None,
|
|
697
767
|
):
|
|
698
768
|
"""
|
|
699
769
|
Enables to control the service type of the pod and the addition of templated ingress host
|
|
@@ -741,45 +811,10 @@ class RemoteRuntime(KubeResource):
|
|
|
741
811
|
|
|
742
812
|
def _get_state(
|
|
743
813
|
self,
|
|
744
|
-
dashboard="",
|
|
745
814
|
last_log_timestamp=0,
|
|
746
815
|
verbose=False,
|
|
747
816
|
raise_on_exception=True,
|
|
748
|
-
resolve_address=True,
|
|
749
|
-
auth_info: AuthInfo = None,
|
|
750
817
|
) -> tuple[str, str, typing.Optional[float]]:
|
|
751
|
-
if dashboard:
|
|
752
|
-
(
|
|
753
|
-
state,
|
|
754
|
-
address,
|
|
755
|
-
name,
|
|
756
|
-
last_log_timestamp,
|
|
757
|
-
text,
|
|
758
|
-
function_status,
|
|
759
|
-
) = get_nuclio_deploy_status(
|
|
760
|
-
self.metadata.name,
|
|
761
|
-
self.metadata.project,
|
|
762
|
-
self.metadata.tag,
|
|
763
|
-
dashboard,
|
|
764
|
-
last_log_timestamp=last_log_timestamp,
|
|
765
|
-
verbose=verbose,
|
|
766
|
-
resolve_address=resolve_address,
|
|
767
|
-
auth_info=auth_info,
|
|
768
|
-
)
|
|
769
|
-
self.status.internal_invocation_urls = function_status.get(
|
|
770
|
-
"internalInvocationUrls", []
|
|
771
|
-
)
|
|
772
|
-
self.status.external_invocation_urls = function_status.get(
|
|
773
|
-
"externalInvocationUrls", []
|
|
774
|
-
)
|
|
775
|
-
self.status.state = state
|
|
776
|
-
self.status.nuclio_name = name
|
|
777
|
-
self.status.container_image = function_status.get("containerImage", "")
|
|
778
|
-
if address:
|
|
779
|
-
self.status.address = address
|
|
780
|
-
self.spec.command = f"http://{address}"
|
|
781
|
-
return state, text, last_log_timestamp
|
|
782
|
-
|
|
783
818
|
try:
|
|
784
819
|
text, last_log_timestamp = self._get_db().get_nuclio_deploy_status(
|
|
785
820
|
self, last_log_timestamp=last_log_timestamp, verbose=verbose
|
|
@@ -887,13 +922,12 @@ class RemoteRuntime(KubeResource):
|
|
|
887
922
|
def invoke(
|
|
888
923
|
self,
|
|
889
924
|
path: str,
|
|
890
|
-
body: typing.Union[str, bytes, dict] = None,
|
|
891
|
-
method: str = None,
|
|
892
|
-
headers: dict = None,
|
|
893
|
-
dashboard: str = "",
|
|
925
|
+
body: typing.Optional[typing.Union[str, bytes, dict]] = None,
|
|
926
|
+
method: typing.Optional[str] = None,
|
|
927
|
+
headers: typing.Optional[dict] = None,
|
|
894
928
|
force_external_address: bool = False,
|
|
895
929
|
auth_info: AuthInfo = None,
|
|
896
|
-
mock: bool = None,
|
|
930
|
+
mock: typing.Optional[bool] = None,
|
|
897
931
|
**http_client_kwargs,
|
|
898
932
|
):
|
|
899
933
|
"""Invoke the remote (live) function and return the results
|
|
@@ -906,7 +940,6 @@ class RemoteRuntime(KubeResource):
|
|
|
906
940
|
:param body: request body (str, bytes or a dict for json requests)
|
|
907
941
|
:param method: HTTP method (GET, PUT, ..)
|
|
908
942
|
:param headers: key/value dict with http headers
|
|
909
|
-
:param dashboard: nuclio dashboard address (deprecated)
|
|
910
943
|
:param force_external_address: use the external ingress URL
|
|
911
944
|
:param auth_info: service AuthInfo
|
|
912
945
|
:param mock: use mock server vs a real Nuclio function (for local simulations)
|
|
@@ -914,14 +947,6 @@ class RemoteRuntime(KubeResource):
|
|
|
914
947
|
see this link for more information:
|
|
915
948
|
https://requests.readthedocs.io/en/latest/api/#requests.request
|
|
916
949
|
"""
|
|
917
|
-
if dashboard:
|
|
918
|
-
# TODO: remove in 1.8.0
|
|
919
|
-
warnings.warn(
|
|
920
|
-
"'dashboard' parameter is no longer supported on client side, "
|
|
921
|
-
"it is being configured through the MLRun API. It will be removed in 1.8.0.",
|
|
922
|
-
FutureWarning,
|
|
923
|
-
)
|
|
924
|
-
|
|
925
950
|
if not method:
|
|
926
951
|
method = "POST" if body else "GET"
|
|
927
952
|
|
|
@@ -951,7 +976,7 @@ class RemoteRuntime(KubeResource):
|
|
|
951
976
|
"so function can not be invoked via http. Either enable default http trigger creation or "
|
|
952
977
|
"create custom http trigger"
|
|
953
978
|
)
|
|
954
|
-
state, _, _ = self._get_state(
|
|
979
|
+
state, _, _ = self._get_state()
|
|
955
980
|
if state not in ["ready", "scaledToZero"]:
|
|
956
981
|
logger.warning(f"Function is in the {state} state")
|
|
957
982
|
if not self.status.address:
|
|
@@ -975,7 +1000,7 @@ class RemoteRuntime(KubeResource):
|
|
|
975
1000
|
else:
|
|
976
1001
|
http_client_kwargs["json"] = body
|
|
977
1002
|
try:
|
|
978
|
-
logger.
|
|
1003
|
+
logger.debug("Invoking function", method=method, path=path)
|
|
979
1004
|
if not getattr(self, "_http_session", None):
|
|
980
1005
|
self._http_session = requests.Session()
|
|
981
1006
|
resp = self._http_session.request(
|
|
@@ -995,14 +1020,15 @@ class RemoteRuntime(KubeResource):
|
|
|
995
1020
|
|
|
996
1021
|
def with_sidecar(
|
|
997
1022
|
self,
|
|
998
|
-
name: str = None,
|
|
999
|
-
image: str = None,
|
|
1023
|
+
name: typing.Optional[str] = None,
|
|
1024
|
+
image: typing.Optional[str] = None,
|
|
1000
1025
|
ports: typing.Optional[typing.Union[int, list[int]]] = None,
|
|
1001
1026
|
command: typing.Optional[str] = None,
|
|
1002
1027
|
args: typing.Optional[list[str]] = None,
|
|
1003
1028
|
):
|
|
1004
1029
|
"""
|
|
1005
1030
|
Add a sidecar container to the function pod
|
|
1031
|
+
|
|
1006
1032
|
:param name: Sidecar container name.
|
|
1007
1033
|
:param image: Sidecar container image.
|
|
1008
1034
|
:param ports: Sidecar container ports to expose. Can be a single port or a list of ports.
|
|
@@ -1192,9 +1218,6 @@ class RemoteRuntime(KubeResource):
|
|
|
1192
1218
|
return results
|
|
1193
1219
|
|
|
1194
1220
|
def _resolve_invocation_url(self, path, force_external_address):
|
|
1195
|
-
if not path.startswith("/") and path != "":
|
|
1196
|
-
path = f"/{path}"
|
|
1197
|
-
|
|
1198
1221
|
# internal / external invocation urls is a nuclio >= 1.6.x feature
|
|
1199
1222
|
# try to infer the invocation url from the internal and if not exists, use external.
|
|
1200
1223
|
# $$$$ we do not want to use the external invocation url (e.g.: ingress, nodePort, etc.)
|
|
@@ -1203,12 +1226,16 @@ class RemoteRuntime(KubeResource):
|
|
|
1203
1226
|
and self.status.internal_invocation_urls
|
|
1204
1227
|
and mlrun.k8s_utils.is_running_inside_kubernetes_cluster()
|
|
1205
1228
|
):
|
|
1206
|
-
return
|
|
1229
|
+
return mlrun.utils.helpers.join_urls(
|
|
1230
|
+
f"http://{self.status.internal_invocation_urls[0]}", path
|
|
1231
|
+
)
|
|
1207
1232
|
|
|
1208
1233
|
if self.status.external_invocation_urls:
|
|
1209
|
-
return
|
|
1234
|
+
return mlrun.utils.helpers.join_urls(
|
|
1235
|
+
f"http://{self.status.external_invocation_urls[0]}", path
|
|
1236
|
+
)
|
|
1210
1237
|
else:
|
|
1211
|
-
return f"http://{self.status.address}
|
|
1238
|
+
return mlrun.utils.helpers.join_urls(f"http://{self.status.address}", path)
|
|
1212
1239
|
|
|
1213
1240
|
def _update_credentials_from_remote_build(self, remote_data):
|
|
1214
1241
|
self.metadata.credentials = remote_data.get("metadata", {}).get(
|
|
@@ -1244,6 +1271,9 @@ class RemoteRuntime(KubeResource):
|
|
|
1244
1271
|
if remote_env.get("name") in credentials_env_var_names:
|
|
1245
1272
|
new_env.append(remote_env)
|
|
1246
1273
|
|
|
1274
|
+
# update nuclio-specific credentials
|
|
1275
|
+
self.mask_sensitive_data_in_config()
|
|
1276
|
+
|
|
1247
1277
|
self.spec.env = new_env
|
|
1248
1278
|
|
|
1249
1279
|
def _set_as_mock(self, enable):
|
|
@@ -1283,6 +1313,33 @@ class RemoteRuntime(KubeResource):
|
|
|
1283
1313
|
return mlrun.model.Credentials.generate_access_key
|
|
1284
1314
|
return None
|
|
1285
1315
|
|
|
1316
|
+
def _check_model_endpoint_task_state(
|
|
1317
|
+
self,
|
|
1318
|
+
db: mlrun.db.RunDBInterface,
|
|
1319
|
+
background_task: mlrun.common.schemas.BackgroundTask,
|
|
1320
|
+
wait_for_completion: bool,
|
|
1321
|
+
):
|
|
1322
|
+
if wait_for_completion:
|
|
1323
|
+
background_task = db._wait_for_background_task_to_reach_terminal_state(
|
|
1324
|
+
name=background_task.metadata.name, project=self.metadata.project
|
|
1325
|
+
)
|
|
1326
|
+
else:
|
|
1327
|
+
background_task = db.get_project_background_task(
|
|
1328
|
+
project=self.metadata.project, name=background_task.metadata.name
|
|
1329
|
+
)
|
|
1330
|
+
if (
|
|
1331
|
+
background_task.status.state
|
|
1332
|
+
in mlrun.common.schemas.BackgroundTaskState.terminal_states()
|
|
1333
|
+
):
|
|
1334
|
+
logger.info(
|
|
1335
|
+
f"Model endpoint creation task completed with state {background_task.status.state}"
|
|
1336
|
+
)
|
|
1337
|
+
else:
|
|
1338
|
+
logger.warning(
|
|
1339
|
+
f"Model endpoint creation task is still running with state {background_task.status.state}"
|
|
1340
|
+
f"You can use the serving function, but it won't be monitored for the next few minutes"
|
|
1341
|
+
)
|
|
1342
|
+
|
|
1286
1343
|
|
|
1287
1344
|
def parse_logs(logs):
|
|
1288
1345
|
logs = json.loads(logs)
|