mlrun 1.7.0rc5__py3-none-any.whl → 1.7.2__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 +11 -1
- mlrun/__main__.py +39 -121
- mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
- mlrun/alerts/alert.py +248 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +39 -254
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +73 -46
- mlrun/artifacts/model.py +30 -158
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +73 -2
- mlrun/common/db/sql_session.py +3 -2
- mlrun/common/formatters/__init__.py +21 -0
- mlrun/common/formatters/artifact.py +46 -0
- mlrun/common/formatters/base.py +113 -0
- mlrun/common/formatters/feature_set.py +44 -0
- mlrun/common/formatters/function.py +46 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/common/formatters/run.py +29 -0
- mlrun/common/helpers.py +11 -1
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +21 -4
- mlrun/common/schemas/alert.py +202 -0
- mlrun/common/schemas/api_gateway.py +113 -2
- mlrun/common/schemas/artifact.py +28 -1
- mlrun/common/schemas/auth.py +11 -0
- mlrun/common/schemas/client_spec.py +2 -1
- mlrun/common/schemas/common.py +7 -4
- mlrun/common/schemas/constants.py +3 -0
- mlrun/common/schemas/feature_store.py +58 -28
- mlrun/common/schemas/frontend_spec.py +8 -0
- mlrun/common/schemas/function.py +11 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/__init__.py +21 -4
- mlrun/common/schemas/model_monitoring/constants.py +136 -42
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +89 -41
- mlrun/common/schemas/notification.py +69 -12
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +7 -0
- mlrun/common/schemas/project.py +67 -16
- mlrun/common/schemas/runs.py +17 -0
- mlrun/common/schemas/schedule.py +1 -1
- mlrun/common/schemas/workflow.py +10 -2
- mlrun/common/types.py +14 -1
- mlrun/config.py +224 -58
- mlrun/data_types/data_types.py +11 -1
- mlrun/data_types/spark.py +5 -4
- mlrun/data_types/to_pandas.py +75 -34
- mlrun/datastore/__init__.py +8 -10
- mlrun/datastore/alibaba_oss.py +131 -0
- mlrun/datastore/azure_blob.py +131 -43
- mlrun/datastore/base.py +107 -47
- mlrun/datastore/datastore.py +17 -7
- mlrun/datastore/datastore_profile.py +91 -7
- mlrun/datastore/dbfs_store.py +3 -7
- mlrun/datastore/filestore.py +1 -3
- mlrun/datastore/google_cloud_storage.py +92 -32
- mlrun/datastore/hdfs.py +5 -0
- mlrun/datastore/inmem.py +6 -3
- mlrun/datastore/redis.py +3 -2
- mlrun/datastore/s3.py +30 -12
- mlrun/datastore/snowflake_utils.py +45 -0
- mlrun/datastore/sources.py +274 -59
- mlrun/datastore/spark_utils.py +30 -0
- mlrun/datastore/store_resources.py +9 -7
- mlrun/datastore/storeytargets.py +151 -0
- mlrun/datastore/targets.py +374 -102
- mlrun/datastore/utils.py +68 -5
- mlrun/datastore/v3io.py +28 -50
- mlrun/db/auth_utils.py +152 -0
- mlrun/db/base.py +231 -22
- mlrun/db/factory.py +1 -4
- mlrun/db/httpdb.py +864 -228
- mlrun/db/nopdb.py +268 -16
- mlrun/errors.py +35 -5
- mlrun/execution.py +111 -38
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +46 -53
- mlrun/feature_store/common.py +6 -11
- mlrun/feature_store/feature_set.py +48 -23
- mlrun/feature_store/feature_vector.py +13 -2
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +13 -4
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +24 -32
- mlrun/feature_store/steps.py +38 -19
- mlrun/features.py +6 -14
- mlrun/frameworks/_common/plan.py +3 -3
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- mlrun/frameworks/_ml_common/plan.py +1 -1
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
- mlrun/frameworks/lgbm/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/model_handler.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +4 -4
- mlrun/frameworks/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/sklearn/mlrun_interface.py +13 -3
- mlrun/frameworks/tf_keras/__init__.py +5 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
- mlrun/frameworks/xgboost/__init__.py +1 -1
- mlrun/k8s_utils.py +57 -12
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +6 -5
- mlrun/launcher/client.py +13 -11
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +15 -5
- mlrun/launcher/remote.py +10 -3
- mlrun/lists.py +6 -2
- mlrun/model.py +297 -48
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +152 -357
- mlrun/model_monitoring/applications/__init__.py +10 -0
- mlrun/model_monitoring/applications/_application_steps.py +190 -0
- mlrun/model_monitoring/applications/base.py +108 -0
- mlrun/model_monitoring/applications/context.py +341 -0
- mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
- mlrun/model_monitoring/applications/histogram_data_drift.py +227 -91
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +130 -303
- mlrun/model_monitoring/{stores/models/sqlite.py → db/__init__.py} +5 -10
- mlrun/model_monitoring/db/stores/__init__.py +136 -0
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/db/stores/base/store.py +213 -0
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
- mlrun/model_monitoring/db/tsdb/base.py +448 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +298 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +522 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
- mlrun/model_monitoring/features_drift_table.py +34 -22
- mlrun/model_monitoring/helpers.py +177 -39
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +165 -398
- mlrun/model_monitoring/tracking_policy.py +7 -1
- mlrun/model_monitoring/writer.py +161 -125
- mlrun/package/packagers/default_packager.py +2 -2
- mlrun/package/packagers_manager.py +1 -0
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +67 -228
- mlrun/projects/__init__.py +6 -1
- mlrun/projects/operations.py +47 -20
- mlrun/projects/pipelines.py +396 -249
- mlrun/projects/project.py +1125 -414
- mlrun/render.py +28 -22
- mlrun/run.py +207 -180
- mlrun/runtimes/__init__.py +76 -11
- mlrun/runtimes/base.py +40 -14
- mlrun/runtimes/daskjob.py +9 -2
- mlrun/runtimes/databricks_job/databricks_runtime.py +1 -0
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +1 -29
- mlrun/runtimes/kubejob.py +34 -128
- mlrun/runtimes/local.py +39 -10
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +8 -8
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/runtimes/nuclio/api_gateway.py +646 -177
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +758 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/nuclio/function.py +188 -68
- mlrun/runtimes/nuclio/serving.py +57 -60
- mlrun/runtimes/pod.py +191 -58
- mlrun/runtimes/remotesparkjob.py +11 -8
- mlrun/runtimes/sparkjob/spark3job.py +17 -18
- mlrun/runtimes/utils.py +40 -73
- mlrun/secrets.py +6 -2
- mlrun/serving/__init__.py +8 -1
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +89 -64
- mlrun/serving/server.py +54 -26
- mlrun/serving/states.py +187 -56
- mlrun/serving/utils.py +19 -11
- mlrun/serving/v2_serving.py +136 -63
- mlrun/track/tracker.py +2 -1
- mlrun/track/trackers/mlflow_tracker.py +5 -0
- mlrun/utils/async_http.py +26 -6
- mlrun/utils/db.py +18 -0
- mlrun/utils/helpers.py +375 -105
- mlrun/utils/http.py +2 -2
- mlrun/utils/logger.py +75 -9
- mlrun/utils/notifications/notification/__init__.py +14 -10
- mlrun/utils/notifications/notification/base.py +48 -0
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +24 -1
- mlrun/utils/notifications/notification/ipython.py +2 -0
- mlrun/utils/notifications/notification/slack.py +96 -21
- mlrun/utils/notifications/notification/webhook.py +63 -2
- mlrun/utils/notifications/notification_pusher.py +146 -16
- mlrun/utils/regex.py +9 -0
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/v3io_clients.py +2 -3
- mlrun/utils/version/version.json +2 -2
- mlrun-1.7.2.dist-info/METADATA +390 -0
- mlrun-1.7.2.dist-info/RECORD +351 -0
- {mlrun-1.7.0rc5.dist-info → mlrun-1.7.2.dist-info}/WHEEL +1 -1
- mlrun/feature_store/retrieval/conversion.py +0 -271
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/application.py +0 -310
- mlrun/model_monitoring/batch.py +0 -974
- mlrun/model_monitoring/controller_handler.py +0 -37
- mlrun/model_monitoring/prometheus.py +0 -216
- mlrun/model_monitoring/stores/__init__.py +0 -111
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -574
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -145
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/models/base.py +0 -84
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
- mlrun/platforms/other.py +0 -305
- mlrun-1.7.0rc5.dist-info/METADATA +0 -269
- mlrun-1.7.0rc5.dist-info/RECORD +0 -323
- {mlrun-1.7.0rc5.dist-info → mlrun-1.7.2.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc5.dist-info → mlrun-1.7.2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc5.dist-info → mlrun-1.7.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Copyright 2024 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
|
+
package main
|
|
15
|
+
|
|
16
|
+
import (
|
|
17
|
+
"bytes"
|
|
18
|
+
"fmt"
|
|
19
|
+
"net/http"
|
|
20
|
+
"net/http/httptest"
|
|
21
|
+
"net/http/httputil"
|
|
22
|
+
"net/url"
|
|
23
|
+
"os"
|
|
24
|
+
"strings"
|
|
25
|
+
|
|
26
|
+
nuclio "github.com/nuclio/nuclio-sdk-go"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
func Handler(context *nuclio.Context, event nuclio.Event) (interface{}, error) {
|
|
30
|
+
reverseProxy := context.UserData.(map[string]interface{})["reverseProxy"].(*httputil.ReverseProxy)
|
|
31
|
+
sidecarUrl := context.UserData.(map[string]interface{})["server"].(string)
|
|
32
|
+
|
|
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
|
+
|
|
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
|
+
|
|
50
|
+
recorder := httptest.NewRecorder()
|
|
51
|
+
reverseProxy.ServeHTTP(recorder, httpRequest)
|
|
52
|
+
|
|
53
|
+
// send request to sidecar
|
|
54
|
+
context.Logger.DebugWith("Forwarding request to sidecar", "sidecarUrl", sidecarUrl, "query", httpRequest.URL.Query())
|
|
55
|
+
response := recorder.Result()
|
|
56
|
+
|
|
57
|
+
headers := make(map[string]interface{})
|
|
58
|
+
for key, value := range response.Header {
|
|
59
|
+
headers[key] = value[0]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// let the processor calculate the content length
|
|
63
|
+
delete(headers, "Content-Length")
|
|
64
|
+
return nuclio.Response{
|
|
65
|
+
StatusCode: response.StatusCode,
|
|
66
|
+
Body: recorder.Body.Bytes(),
|
|
67
|
+
ContentType: response.Header.Get("Content-Type"),
|
|
68
|
+
Headers: headers,
|
|
69
|
+
}, nil
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func InitContext(context *nuclio.Context) error {
|
|
73
|
+
sidecarHost := os.Getenv("SIDECAR_HOST")
|
|
74
|
+
sidecarPort := os.Getenv("SIDECAR_PORT")
|
|
75
|
+
if sidecarHost == "" {
|
|
76
|
+
sidecarHost = "http://localhost"
|
|
77
|
+
} else if !strings.Contains(sidecarHost, "://") {
|
|
78
|
+
sidecarHost = fmt.Sprintf("http://%s", sidecarHost)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// url for request forwarding
|
|
82
|
+
sidecarUrl := fmt.Sprintf("%s:%s", sidecarHost, sidecarPort)
|
|
83
|
+
parsedURL, err := url.Parse(sidecarUrl)
|
|
84
|
+
if err != nil {
|
|
85
|
+
context.Logger.ErrorWith("Failed to parse sidecar url", "sidecarUrl", sidecarUrl)
|
|
86
|
+
return err
|
|
87
|
+
}
|
|
88
|
+
reverseProxy := httputil.NewSingleHostReverseProxy(parsedURL)
|
|
89
|
+
|
|
90
|
+
context.UserData = map[string]interface{}{
|
|
91
|
+
"server": sidecarUrl,
|
|
92
|
+
"reverseProxy": reverseProxy,
|
|
93
|
+
}
|
|
94
|
+
return nil
|
|
95
|
+
}
|
|
@@ -19,12 +19,16 @@ import warnings
|
|
|
19
19
|
from datetime import datetime
|
|
20
20
|
from time import sleep
|
|
21
21
|
|
|
22
|
+
import inflection
|
|
22
23
|
import nuclio
|
|
23
24
|
import nuclio.utils
|
|
24
25
|
import requests
|
|
25
26
|
import semver
|
|
26
27
|
from aiohttp.client import ClientSession
|
|
27
28
|
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
|
|
28
32
|
from nuclio.deploy import find_dashboard_url, get_deploy_status
|
|
29
33
|
from nuclio.triggers import V3IOStreamTrigger
|
|
30
34
|
|
|
@@ -36,15 +40,11 @@ import mlrun.utils.helpers
|
|
|
36
40
|
from mlrun.common.schemas import AuthInfo
|
|
37
41
|
from mlrun.config import config as mlconf
|
|
38
42
|
from mlrun.errors import err_to_str
|
|
39
|
-
from mlrun.kfpops import deploy_op
|
|
40
43
|
from mlrun.lists import RunList
|
|
41
44
|
from mlrun.model import RunObject
|
|
42
45
|
from mlrun.platforms.iguazio import (
|
|
43
|
-
VolumeMount,
|
|
44
|
-
mount_v3io,
|
|
45
46
|
parse_path,
|
|
46
47
|
split_path,
|
|
47
|
-
v3io_cred,
|
|
48
48
|
)
|
|
49
49
|
from mlrun.runtimes.base import FunctionStatus, RunError
|
|
50
50
|
from mlrun.runtimes.pod import KubeResource, KubeResourceSpec
|
|
@@ -56,33 +56,9 @@ def validate_nuclio_version_compatibility(*min_versions):
|
|
|
56
56
|
"""
|
|
57
57
|
:param min_versions: Valid minimum version(s) required, assuming no 2 versions has equal major and minor.
|
|
58
58
|
"""
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
try:
|
|
63
|
-
parsed_current_version = semver.VersionInfo.parse(mlconf.nuclio_version)
|
|
64
|
-
except ValueError:
|
|
65
|
-
# only log when version is set but invalid
|
|
66
|
-
if mlconf.nuclio_version:
|
|
67
|
-
logger.warning(
|
|
68
|
-
"Unable to parse nuclio version, assuming compatibility",
|
|
69
|
-
nuclio_version=mlconf.nuclio_version,
|
|
70
|
-
min_versions=min_versions,
|
|
71
|
-
)
|
|
72
|
-
return True
|
|
73
|
-
|
|
74
|
-
parsed_min_versions.sort(reverse=True)
|
|
75
|
-
for parsed_min_version in parsed_min_versions:
|
|
76
|
-
if (
|
|
77
|
-
parsed_current_version.major == parsed_min_version.major
|
|
78
|
-
and parsed_current_version.minor == parsed_min_version.minor
|
|
79
|
-
and parsed_current_version.patch < parsed_min_version.patch
|
|
80
|
-
):
|
|
81
|
-
return False
|
|
82
|
-
|
|
83
|
-
if parsed_current_version >= parsed_min_version:
|
|
84
|
-
return True
|
|
85
|
-
return False
|
|
59
|
+
return mlrun.utils.helpers.validate_component_version_compatibility(
|
|
60
|
+
"nuclio", *min_versions
|
|
61
|
+
)
|
|
86
62
|
|
|
87
63
|
|
|
88
64
|
def min_nuclio_versions(*versions):
|
|
@@ -91,9 +67,13 @@ def min_nuclio_versions(*versions):
|
|
|
91
67
|
if validate_nuclio_version_compatibility(*versions):
|
|
92
68
|
return function(*args, **kwargs)
|
|
93
69
|
|
|
70
|
+
if function.__name__ == "__init__":
|
|
71
|
+
name = inflection.titleize(function.__qualname__.split(".")[0])
|
|
72
|
+
else:
|
|
73
|
+
name = function.__qualname__
|
|
74
|
+
|
|
94
75
|
message = (
|
|
95
|
-
f"{
|
|
96
|
-
f"nuclio {mlconf.nuclio_version}, please upgrade."
|
|
76
|
+
f"'{name}' function requires Nuclio v{' or v'.join(versions)} or higher"
|
|
97
77
|
)
|
|
98
78
|
raise mlrun.errors.MLRunIncompatibleVersionError(message)
|
|
99
79
|
|
|
@@ -291,6 +271,10 @@ class RemoteRuntime(KubeResource):
|
|
|
291
271
|
def status(self, status):
|
|
292
272
|
self._status = self._verify_dict(status, "status", NuclioStatus)
|
|
293
273
|
|
|
274
|
+
def pre_deploy_validation(self):
|
|
275
|
+
if self.metadata.tag:
|
|
276
|
+
mlrun.utils.validate_tag_name(self.metadata.tag, "function.metadata.tag")
|
|
277
|
+
|
|
294
278
|
def set_config(self, key, value):
|
|
295
279
|
self.spec.config[key] = value
|
|
296
280
|
return self
|
|
@@ -313,10 +297,37 @@ class RemoteRuntime(KubeResource):
|
|
|
313
297
|
"""
|
|
314
298
|
if hasattr(spec, "to_dict"):
|
|
315
299
|
spec = spec.to_dict()
|
|
300
|
+
|
|
301
|
+
self._validate_triggers(spec)
|
|
302
|
+
|
|
316
303
|
spec["name"] = name
|
|
317
304
|
self.spec.config[f"spec.triggers.{name}"] = spec
|
|
318
305
|
return self
|
|
319
306
|
|
|
307
|
+
def _validate_triggers(self, spec):
|
|
308
|
+
# ML-7763 / NUC-233
|
|
309
|
+
min_nuclio_version = "1.13.12"
|
|
310
|
+
if mlconf.nuclio_version and semver.VersionInfo.parse(
|
|
311
|
+
mlconf.nuclio_version
|
|
312
|
+
) < semver.VersionInfo.parse(min_nuclio_version):
|
|
313
|
+
explicit_ack_enabled = False
|
|
314
|
+
num_triggers = 0
|
|
315
|
+
trigger_name = spec.get("name", "UNKNOWN")
|
|
316
|
+
for key, config in [(f"spec.triggers.{trigger_name}", spec)] + list(
|
|
317
|
+
self.spec.config.items()
|
|
318
|
+
):
|
|
319
|
+
if key.startswith("spec.triggers."):
|
|
320
|
+
num_triggers += 1
|
|
321
|
+
explicit_ack_enabled = (
|
|
322
|
+
config.get("explicitAckMode", "disable") != "disable"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
if num_triggers > 1 and explicit_ack_enabled:
|
|
326
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
327
|
+
"Multiple triggers cannot be used in conjunction with explicit ack. "
|
|
328
|
+
f"Please upgrade to nuclio {min_nuclio_version} or newer."
|
|
329
|
+
)
|
|
330
|
+
|
|
320
331
|
def with_source_archive(
|
|
321
332
|
self,
|
|
322
333
|
source,
|
|
@@ -342,17 +353,21 @@ class RemoteRuntime(KubeResource):
|
|
|
342
353
|
|
|
343
354
|
git::
|
|
344
355
|
|
|
345
|
-
fn.with_source_archive(
|
|
346
|
-
|
|
347
|
-
|
|
356
|
+
fn.with_source_archive(
|
|
357
|
+
"git://github.com/org/repo#my-branch",
|
|
358
|
+
handler="main:handler",
|
|
359
|
+
workdir="path/inside/repo",
|
|
360
|
+
)
|
|
348
361
|
|
|
349
362
|
s3::
|
|
350
363
|
|
|
351
364
|
fn.spec.nuclio_runtime = "golang"
|
|
352
|
-
fn.with_source_archive(
|
|
365
|
+
fn.with_source_archive(
|
|
366
|
+
"s3://my-bucket/path/in/bucket/my-functions-archive",
|
|
353
367
|
handler="my_func:Handler",
|
|
354
368
|
workdir="path/inside/functions/archive",
|
|
355
|
-
runtime="golang"
|
|
369
|
+
runtime="golang",
|
|
370
|
+
)
|
|
356
371
|
"""
|
|
357
372
|
self.spec.build.source = source
|
|
358
373
|
# update handler in function_handler
|
|
@@ -431,14 +446,8 @@ class RemoteRuntime(KubeResource):
|
|
|
431
446
|
raise ValueError(
|
|
432
447
|
"gateway timeout must be greater than the worker timeout"
|
|
433
448
|
)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
)
|
|
437
|
-
annotations["nginx.ingress.kubernetes.io/proxy-read-timeout"] = (
|
|
438
|
-
f"{gateway_timeout}"
|
|
439
|
-
)
|
|
440
|
-
annotations["nginx.ingress.kubernetes.io/proxy-send-timeout"] = (
|
|
441
|
-
f"{gateway_timeout}"
|
|
449
|
+
mlrun.runtimes.utils.enrich_gateway_timeout_annotations(
|
|
450
|
+
annotations, gateway_timeout
|
|
442
451
|
)
|
|
443
452
|
|
|
444
453
|
trigger = nuclio.HttpTrigger(
|
|
@@ -459,6 +468,11 @@ class RemoteRuntime(KubeResource):
|
|
|
459
468
|
return self
|
|
460
469
|
|
|
461
470
|
def from_image(self, image):
|
|
471
|
+
"""
|
|
472
|
+
Deploy the function with an existing nuclio processor image.
|
|
473
|
+
|
|
474
|
+
:param image: image name
|
|
475
|
+
"""
|
|
462
476
|
config = nuclio.config.new_config()
|
|
463
477
|
update_in(
|
|
464
478
|
config,
|
|
@@ -509,6 +523,11 @@ class RemoteRuntime(KubeResource):
|
|
|
509
523
|
extra_attributes = extra_attributes or {}
|
|
510
524
|
if ack_window_size:
|
|
511
525
|
extra_attributes["ackWindowSize"] = ack_window_size
|
|
526
|
+
|
|
527
|
+
access_key = kwargs.pop("access_key", None)
|
|
528
|
+
if not access_key:
|
|
529
|
+
access_key = self._resolve_v3io_access_key()
|
|
530
|
+
|
|
512
531
|
self.add_trigger(
|
|
513
532
|
name,
|
|
514
533
|
V3IOStreamTrigger(
|
|
@@ -520,11 +539,14 @@ class RemoteRuntime(KubeResource):
|
|
|
520
539
|
webapi=endpoint or "http://v3io-webapi:8081",
|
|
521
540
|
extra_attributes=extra_attributes,
|
|
522
541
|
read_batch_size=256,
|
|
542
|
+
access_key=access_key,
|
|
523
543
|
**kwargs,
|
|
524
544
|
),
|
|
525
545
|
)
|
|
526
|
-
self.spec.min_replicas
|
|
527
|
-
|
|
546
|
+
if self.spec.min_replicas != shards or self.spec.max_replicas != shards:
|
|
547
|
+
logger.warning(f"Setting function replicas to {shards}")
|
|
548
|
+
self.spec.min_replicas = shards
|
|
549
|
+
self.spec.max_replicas = shards
|
|
528
550
|
|
|
529
551
|
def deploy(
|
|
530
552
|
self,
|
|
@@ -540,11 +562,16 @@ class RemoteRuntime(KubeResource):
|
|
|
540
562
|
:param project: project name
|
|
541
563
|
:param tag: function tag
|
|
542
564
|
:param verbose: set True for verbose logging
|
|
543
|
-
:param auth_info: service AuthInfo
|
|
565
|
+
:param auth_info: service AuthInfo (deprecated and ignored)
|
|
544
566
|
:param builder_env: env vars dict for source archive config/credentials e.g. builder_env={"GIT_TOKEN": token}
|
|
545
567
|
:param force_build: set True for force building the image
|
|
546
568
|
"""
|
|
547
|
-
|
|
569
|
+
if auth_info:
|
|
570
|
+
# TODO: remove in 1.9.0
|
|
571
|
+
warnings.warn(
|
|
572
|
+
"'auth_info' is deprecated for nuclio runtimes in 1.7.0 and will be removed in 1.9.0",
|
|
573
|
+
FutureWarning,
|
|
574
|
+
)
|
|
548
575
|
|
|
549
576
|
old_http_session = getattr(self, "_http_session", None)
|
|
550
577
|
if old_http_session:
|
|
@@ -561,15 +588,12 @@ class RemoteRuntime(KubeResource):
|
|
|
561
588
|
if tag:
|
|
562
589
|
self.metadata.tag = tag
|
|
563
590
|
|
|
564
|
-
save_record = False
|
|
565
591
|
# Attempt auto-mounting, before sending to remote build
|
|
566
592
|
self.try_auto_mount_based_on_config()
|
|
567
593
|
self._fill_credentials()
|
|
568
594
|
db = self._get_db()
|
|
569
595
|
logger.info("Starting remote function deploy")
|
|
570
|
-
data = db.
|
|
571
|
-
self, False, builder_env=builder_env, force_build=force_build
|
|
572
|
-
)
|
|
596
|
+
data = db.deploy_nuclio_function(func=self, builder_env=builder_env)
|
|
573
597
|
self.status = data["data"].get("status")
|
|
574
598
|
self._update_credentials_from_remote_build(data["data"])
|
|
575
599
|
|
|
@@ -577,19 +601,25 @@ class RemoteRuntime(KubeResource):
|
|
|
577
601
|
# this also means that the function object will be updated with the function status
|
|
578
602
|
self._wait_for_function_deployment(db, verbose=verbose)
|
|
579
603
|
|
|
604
|
+
return self._enrich_command_from_status()
|
|
605
|
+
|
|
606
|
+
def _enrich_command_from_status(self):
|
|
580
607
|
# NOTE: on older mlrun versions & nuclio versions, function are exposed via NodePort
|
|
581
608
|
# now, functions can be not exposed (using service type ClusterIP) and hence
|
|
582
609
|
# for BC we first try to populate the external invocation url, and then
|
|
583
610
|
# if not exists, take the internal invocation url
|
|
584
|
-
if
|
|
611
|
+
if (
|
|
612
|
+
self.status.external_invocation_urls
|
|
613
|
+
and self.status.external_invocation_urls[0] != ""
|
|
614
|
+
):
|
|
585
615
|
self.spec.command = f"http://{self.status.external_invocation_urls[0]}"
|
|
586
|
-
|
|
587
|
-
|
|
616
|
+
elif (
|
|
617
|
+
self.status.internal_invocation_urls
|
|
618
|
+
and self.status.internal_invocation_urls[0] != ""
|
|
619
|
+
):
|
|
588
620
|
self.spec.command = f"http://{self.status.internal_invocation_urls[0]}"
|
|
589
|
-
|
|
590
|
-
elif self.status.address:
|
|
621
|
+
elif self.status.address and self.status.address != "":
|
|
591
622
|
self.spec.command = f"http://{self.status.address}"
|
|
592
|
-
save_record = True
|
|
593
623
|
|
|
594
624
|
logger.info(
|
|
595
625
|
"Successfully deployed function",
|
|
@@ -597,13 +627,11 @@ class RemoteRuntime(KubeResource):
|
|
|
597
627
|
external_invocation_urls=self.status.external_invocation_urls,
|
|
598
628
|
)
|
|
599
629
|
|
|
600
|
-
|
|
601
|
-
self.save(versioned=False)
|
|
630
|
+
self.save(versioned=False)
|
|
602
631
|
|
|
603
632
|
return self.spec.command
|
|
604
633
|
|
|
605
634
|
def _wait_for_function_deployment(self, db, verbose=False):
|
|
606
|
-
text = ""
|
|
607
635
|
state = ""
|
|
608
636
|
last_log_timestamp = 1
|
|
609
637
|
while state not in ["ready", "error", "unhealthy"]:
|
|
@@ -611,7 +639,7 @@ class RemoteRuntime(KubeResource):
|
|
|
611
639
|
int(mlrun.mlconf.httpdb.logs.nuclio.pull_deploy_status_default_interval)
|
|
612
640
|
)
|
|
613
641
|
try:
|
|
614
|
-
text, last_log_timestamp = db.
|
|
642
|
+
text, last_log_timestamp = db.get_nuclio_deploy_status(
|
|
615
643
|
self, last_log_timestamp=last_log_timestamp, verbose=verbose
|
|
616
644
|
)
|
|
617
645
|
except mlrun.db.RunDBError:
|
|
@@ -689,7 +717,7 @@ class RemoteRuntime(KubeResource):
|
|
|
689
717
|
"State thresholds do not apply for nuclio as it has its own function pods healthiness monitoring"
|
|
690
718
|
)
|
|
691
719
|
|
|
692
|
-
@min_nuclio_versions("1.
|
|
720
|
+
@min_nuclio_versions("1.13.1")
|
|
693
721
|
def disable_default_http_trigger(
|
|
694
722
|
self,
|
|
695
723
|
):
|
|
@@ -698,7 +726,7 @@ class RemoteRuntime(KubeResource):
|
|
|
698
726
|
"""
|
|
699
727
|
self.spec.disable_default_http_trigger = True
|
|
700
728
|
|
|
701
|
-
@min_nuclio_versions("1.
|
|
729
|
+
@min_nuclio_versions("1.13.1")
|
|
702
730
|
def enable_default_http_trigger(
|
|
703
731
|
self,
|
|
704
732
|
):
|
|
@@ -707,6 +735,10 @@ class RemoteRuntime(KubeResource):
|
|
|
707
735
|
"""
|
|
708
736
|
self.spec.disable_default_http_trigger = False
|
|
709
737
|
|
|
738
|
+
def skip_image_enrichment(self):
|
|
739
|
+
# make sure the API does not enrich the base image if the function is not a python function
|
|
740
|
+
return self.spec.nuclio_runtime and "python" not in self.spec.nuclio_runtime
|
|
741
|
+
|
|
710
742
|
def _get_state(
|
|
711
743
|
self,
|
|
712
744
|
dashboard="",
|
|
@@ -749,7 +781,7 @@ class RemoteRuntime(KubeResource):
|
|
|
749
781
|
return state, text, last_log_timestamp
|
|
750
782
|
|
|
751
783
|
try:
|
|
752
|
-
text, last_log_timestamp = self._get_db().
|
|
784
|
+
text, last_log_timestamp = self._get_db().get_nuclio_deploy_status(
|
|
753
785
|
self, last_log_timestamp=last_log_timestamp, verbose=verbose
|
|
754
786
|
)
|
|
755
787
|
except mlrun.db.RunDBError:
|
|
@@ -769,10 +801,13 @@ class RemoteRuntime(KubeResource):
|
|
|
769
801
|
runtime_env["MLRUN_NAMESPACE"] = mlconf.namespace
|
|
770
802
|
if self.metadata.credentials.access_key:
|
|
771
803
|
runtime_env[
|
|
772
|
-
mlrun.runtimes.constants.FunctionEnvironmentVariables.auth_session
|
|
804
|
+
mlrun.common.runtimes.constants.FunctionEnvironmentVariables.auth_session
|
|
773
805
|
] = self.metadata.credentials.access_key
|
|
774
806
|
return runtime_env
|
|
775
807
|
|
|
808
|
+
def _get_serving_spec(self):
|
|
809
|
+
return None
|
|
810
|
+
|
|
776
811
|
def _get_nuclio_config_spec_env(self):
|
|
777
812
|
env_dict = {}
|
|
778
813
|
external_source_env_dict = {}
|
|
@@ -958,6 +993,64 @@ class RemoteRuntime(KubeResource):
|
|
|
958
993
|
data = json.loads(data)
|
|
959
994
|
return data
|
|
960
995
|
|
|
996
|
+
def with_sidecar(
|
|
997
|
+
self,
|
|
998
|
+
name: str = None,
|
|
999
|
+
image: str = None,
|
|
1000
|
+
ports: typing.Optional[typing.Union[int, list[int]]] = None,
|
|
1001
|
+
command: typing.Optional[str] = None,
|
|
1002
|
+
args: typing.Optional[list[str]] = None,
|
|
1003
|
+
):
|
|
1004
|
+
"""
|
|
1005
|
+
Add a sidecar container to the function pod
|
|
1006
|
+
|
|
1007
|
+
:param name: Sidecar container name.
|
|
1008
|
+
:param image: Sidecar container image.
|
|
1009
|
+
:param ports: Sidecar container ports to expose. Can be a single port or a list of ports.
|
|
1010
|
+
:param command: Sidecar container command instead of the image entrypoint.
|
|
1011
|
+
:param args: Sidecar container command args (requires command to be set).
|
|
1012
|
+
"""
|
|
1013
|
+
name = name or f"{self.metadata.name}-sidecar"
|
|
1014
|
+
sidecar = self._set_sidecar(name)
|
|
1015
|
+
if image:
|
|
1016
|
+
sidecar["image"] = image
|
|
1017
|
+
|
|
1018
|
+
ports = mlrun.utils.helpers.as_list(ports)
|
|
1019
|
+
# according to RFC-6335, port name should be less than 15 characters,
|
|
1020
|
+
# so we truncate it if needed and leave room for the index
|
|
1021
|
+
port_name = name[:13].rstrip("-_") if len(name) > 13 else name
|
|
1022
|
+
sidecar["ports"] = [
|
|
1023
|
+
{
|
|
1024
|
+
"name": f"{port_name}-{i}",
|
|
1025
|
+
"containerPort": port,
|
|
1026
|
+
"protocol": "TCP",
|
|
1027
|
+
}
|
|
1028
|
+
for i, port in enumerate(ports)
|
|
1029
|
+
]
|
|
1030
|
+
|
|
1031
|
+
# if it is a redeploy, 'command' might be set with the previous invocation url.
|
|
1032
|
+
# in this case, we don't want to use it as the sidecar command
|
|
1033
|
+
if command and not command.startswith("http"):
|
|
1034
|
+
sidecar["command"] = mlrun.utils.helpers.as_list(command)
|
|
1035
|
+
|
|
1036
|
+
if args and sidecar.get("command"):
|
|
1037
|
+
sidecar["args"] = mlrun.utils.helpers.as_list(args)
|
|
1038
|
+
|
|
1039
|
+
# put the configured resources on the sidecar container instead of the reverse proxy container
|
|
1040
|
+
if self.spec.resources:
|
|
1041
|
+
sidecar["resources"] = self.spec.resources
|
|
1042
|
+
self.spec.resources = None
|
|
1043
|
+
|
|
1044
|
+
def _set_sidecar(self, name: str) -> dict:
|
|
1045
|
+
self.spec.config.setdefault("spec.sidecars", [])
|
|
1046
|
+
sidecars = self.spec.config["spec.sidecars"]
|
|
1047
|
+
for sidecar in sidecars:
|
|
1048
|
+
if sidecar["name"] == name:
|
|
1049
|
+
return sidecar
|
|
1050
|
+
|
|
1051
|
+
sidecars.append({"name": name})
|
|
1052
|
+
return sidecars[-1]
|
|
1053
|
+
|
|
961
1054
|
def _trigger_of_kind_exists(self, kind: str) -> bool:
|
|
962
1055
|
if not self.spec.config:
|
|
963
1056
|
return False
|
|
@@ -1184,6 +1277,13 @@ class RemoteRuntime(KubeResource):
|
|
|
1184
1277
|
|
|
1185
1278
|
return self._resolve_invocation_url("", force_external_address)
|
|
1186
1279
|
|
|
1280
|
+
@staticmethod
|
|
1281
|
+
def _resolve_v3io_access_key():
|
|
1282
|
+
# Nuclio supports generating access key for v3io stream trigger only from version 1.13.11
|
|
1283
|
+
if validate_nuclio_version_compatibility("1.13.11"):
|
|
1284
|
+
return mlrun.model.Credentials.generate_access_key
|
|
1285
|
+
return None
|
|
1286
|
+
|
|
1187
1287
|
|
|
1188
1288
|
def parse_logs(logs):
|
|
1189
1289
|
logs = json.loads(logs)
|
|
@@ -1278,3 +1378,23 @@ def get_nuclio_deploy_status(
|
|
|
1278
1378
|
else:
|
|
1279
1379
|
text = "\n".join(outputs) if outputs else ""
|
|
1280
1380
|
return state, address, name, last_log_timestamp, text, function_status
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
def enrich_nuclio_function_from_headers(
|
|
1384
|
+
func: RemoteRuntime,
|
|
1385
|
+
headers: dict,
|
|
1386
|
+
):
|
|
1387
|
+
func.status.state = headers.get("x-mlrun-function-status", "")
|
|
1388
|
+
func.status.address = headers.get("x-mlrun-address", "")
|
|
1389
|
+
func.status.nuclio_name = headers.get("x-mlrun-name", "")
|
|
1390
|
+
func.status.internal_invocation_urls = (
|
|
1391
|
+
headers.get("x-mlrun-internal-invocation-urls", "").split(",")
|
|
1392
|
+
if headers.get("x-mlrun-internal-invocation-urls")
|
|
1393
|
+
else []
|
|
1394
|
+
)
|
|
1395
|
+
func.status.external_invocation_urls = (
|
|
1396
|
+
headers.get("x-mlrun-external-invocation-urls", "").split(",")
|
|
1397
|
+
if headers.get("x-mlrun-external-invocation-urls")
|
|
1398
|
+
else []
|
|
1399
|
+
)
|
|
1400
|
+
func.status.container_image = headers.get("x-mlrun-container-image", "")
|