mlrun 1.6.4rc8__py3-none-any.whl → 1.7.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.

Files changed (305) hide show
  1. mlrun/__init__.py +11 -1
  2. mlrun/__main__.py +40 -122
  3. mlrun/alerts/__init__.py +15 -0
  4. mlrun/alerts/alert.py +248 -0
  5. mlrun/api/schemas/__init__.py +5 -4
  6. mlrun/artifacts/__init__.py +8 -3
  7. mlrun/artifacts/base.py +47 -257
  8. mlrun/artifacts/dataset.py +11 -192
  9. mlrun/artifacts/manager.py +79 -47
  10. mlrun/artifacts/model.py +31 -159
  11. mlrun/artifacts/plots.py +23 -380
  12. mlrun/common/constants.py +74 -1
  13. mlrun/common/db/sql_session.py +5 -5
  14. mlrun/common/formatters/__init__.py +21 -0
  15. mlrun/common/formatters/artifact.py +45 -0
  16. mlrun/common/formatters/base.py +113 -0
  17. mlrun/common/formatters/feature_set.py +33 -0
  18. mlrun/common/formatters/function.py +46 -0
  19. mlrun/common/formatters/pipeline.py +53 -0
  20. mlrun/common/formatters/project.py +51 -0
  21. mlrun/common/formatters/run.py +29 -0
  22. mlrun/common/helpers.py +12 -3
  23. mlrun/common/model_monitoring/helpers.py +9 -5
  24. mlrun/{runtimes → common/runtimes}/constants.py +37 -9
  25. mlrun/common/schemas/__init__.py +31 -5
  26. mlrun/common/schemas/alert.py +202 -0
  27. mlrun/common/schemas/api_gateway.py +196 -0
  28. mlrun/common/schemas/artifact.py +25 -4
  29. mlrun/common/schemas/auth.py +16 -5
  30. mlrun/common/schemas/background_task.py +1 -1
  31. mlrun/common/schemas/client_spec.py +4 -2
  32. mlrun/common/schemas/common.py +7 -4
  33. mlrun/common/schemas/constants.py +3 -0
  34. mlrun/common/schemas/feature_store.py +74 -44
  35. mlrun/common/schemas/frontend_spec.py +15 -7
  36. mlrun/common/schemas/function.py +12 -1
  37. mlrun/common/schemas/hub.py +11 -18
  38. mlrun/common/schemas/memory_reports.py +2 -2
  39. mlrun/common/schemas/model_monitoring/__init__.py +20 -4
  40. mlrun/common/schemas/model_monitoring/constants.py +123 -42
  41. mlrun/common/schemas/model_monitoring/grafana.py +13 -9
  42. mlrun/common/schemas/model_monitoring/model_endpoints.py +101 -54
  43. mlrun/common/schemas/notification.py +71 -14
  44. mlrun/common/schemas/object.py +2 -2
  45. mlrun/{model_monitoring/controller_handler.py → common/schemas/pagination.py} +9 -12
  46. mlrun/common/schemas/pipeline.py +8 -1
  47. mlrun/common/schemas/project.py +69 -18
  48. mlrun/common/schemas/runs.py +7 -1
  49. mlrun/common/schemas/runtime_resource.py +8 -12
  50. mlrun/common/schemas/schedule.py +4 -4
  51. mlrun/common/schemas/tag.py +1 -2
  52. mlrun/common/schemas/workflow.py +12 -4
  53. mlrun/common/types.py +14 -1
  54. mlrun/config.py +154 -69
  55. mlrun/data_types/data_types.py +6 -1
  56. mlrun/data_types/spark.py +2 -2
  57. mlrun/data_types/to_pandas.py +67 -37
  58. mlrun/datastore/__init__.py +6 -8
  59. mlrun/datastore/alibaba_oss.py +131 -0
  60. mlrun/datastore/azure_blob.py +143 -42
  61. mlrun/datastore/base.py +102 -58
  62. mlrun/datastore/datastore.py +34 -13
  63. mlrun/datastore/datastore_profile.py +146 -20
  64. mlrun/datastore/dbfs_store.py +3 -7
  65. mlrun/datastore/filestore.py +1 -4
  66. mlrun/datastore/google_cloud_storage.py +97 -33
  67. mlrun/datastore/hdfs.py +56 -0
  68. mlrun/datastore/inmem.py +6 -3
  69. mlrun/datastore/redis.py +7 -2
  70. mlrun/datastore/s3.py +34 -12
  71. mlrun/datastore/snowflake_utils.py +45 -0
  72. mlrun/datastore/sources.py +303 -111
  73. mlrun/datastore/spark_utils.py +31 -2
  74. mlrun/datastore/store_resources.py +9 -7
  75. mlrun/datastore/storeytargets.py +151 -0
  76. mlrun/datastore/targets.py +453 -176
  77. mlrun/datastore/utils.py +72 -58
  78. mlrun/datastore/v3io.py +6 -1
  79. mlrun/db/base.py +274 -41
  80. mlrun/db/factory.py +1 -1
  81. mlrun/db/httpdb.py +893 -225
  82. mlrun/db/nopdb.py +291 -33
  83. mlrun/errors.py +36 -6
  84. mlrun/execution.py +115 -42
  85. mlrun/feature_store/__init__.py +0 -2
  86. mlrun/feature_store/api.py +65 -73
  87. mlrun/feature_store/common.py +7 -12
  88. mlrun/feature_store/feature_set.py +76 -55
  89. mlrun/feature_store/feature_vector.py +39 -31
  90. mlrun/feature_store/ingestion.py +7 -6
  91. mlrun/feature_store/retrieval/base.py +16 -11
  92. mlrun/feature_store/retrieval/dask_merger.py +2 -0
  93. mlrun/feature_store/retrieval/job.py +13 -4
  94. mlrun/feature_store/retrieval/local_merger.py +2 -0
  95. mlrun/feature_store/retrieval/spark_merger.py +24 -32
  96. mlrun/feature_store/steps.py +45 -34
  97. mlrun/features.py +11 -21
  98. mlrun/frameworks/_common/artifacts_library.py +9 -9
  99. mlrun/frameworks/_common/mlrun_interface.py +5 -5
  100. mlrun/frameworks/_common/model_handler.py +48 -48
  101. mlrun/frameworks/_common/plan.py +5 -6
  102. mlrun/frameworks/_common/producer.py +3 -4
  103. mlrun/frameworks/_common/utils.py +5 -5
  104. mlrun/frameworks/_dl_common/loggers/logger.py +6 -7
  105. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +9 -9
  106. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +23 -47
  107. mlrun/frameworks/_ml_common/artifacts_library.py +1 -2
  108. mlrun/frameworks/_ml_common/loggers/logger.py +3 -4
  109. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +4 -5
  110. mlrun/frameworks/_ml_common/model_handler.py +24 -24
  111. mlrun/frameworks/_ml_common/pkl_model_server.py +2 -2
  112. mlrun/frameworks/_ml_common/plan.py +2 -2
  113. mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +2 -3
  114. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +2 -3
  115. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  116. mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +3 -3
  117. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  118. mlrun/frameworks/_ml_common/utils.py +4 -4
  119. mlrun/frameworks/auto_mlrun/auto_mlrun.py +9 -9
  120. mlrun/frameworks/huggingface/model_server.py +4 -4
  121. mlrun/frameworks/lgbm/__init__.py +33 -33
  122. mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
  123. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -5
  124. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -5
  125. mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -3
  126. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +6 -6
  127. mlrun/frameworks/lgbm/model_handler.py +10 -10
  128. mlrun/frameworks/lgbm/model_server.py +6 -6
  129. mlrun/frameworks/lgbm/utils.py +5 -5
  130. mlrun/frameworks/onnx/dataset.py +8 -8
  131. mlrun/frameworks/onnx/mlrun_interface.py +3 -3
  132. mlrun/frameworks/onnx/model_handler.py +6 -6
  133. mlrun/frameworks/onnx/model_server.py +7 -7
  134. mlrun/frameworks/parallel_coordinates.py +6 -6
  135. mlrun/frameworks/pytorch/__init__.py +18 -18
  136. mlrun/frameworks/pytorch/callbacks/callback.py +4 -5
  137. mlrun/frameworks/pytorch/callbacks/logging_callback.py +17 -17
  138. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +11 -11
  139. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +23 -29
  140. mlrun/frameworks/pytorch/callbacks_handler.py +38 -38
  141. mlrun/frameworks/pytorch/mlrun_interface.py +20 -20
  142. mlrun/frameworks/pytorch/model_handler.py +17 -17
  143. mlrun/frameworks/pytorch/model_server.py +7 -7
  144. mlrun/frameworks/sklearn/__init__.py +13 -13
  145. mlrun/frameworks/sklearn/estimator.py +4 -4
  146. mlrun/frameworks/sklearn/metrics_library.py +14 -14
  147. mlrun/frameworks/sklearn/mlrun_interface.py +16 -9
  148. mlrun/frameworks/sklearn/model_handler.py +2 -2
  149. mlrun/frameworks/tf_keras/__init__.py +10 -7
  150. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +15 -15
  151. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +11 -11
  152. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +19 -23
  153. mlrun/frameworks/tf_keras/mlrun_interface.py +9 -11
  154. mlrun/frameworks/tf_keras/model_handler.py +14 -14
  155. mlrun/frameworks/tf_keras/model_server.py +6 -6
  156. mlrun/frameworks/xgboost/__init__.py +13 -13
  157. mlrun/frameworks/xgboost/model_handler.py +6 -6
  158. mlrun/k8s_utils.py +61 -17
  159. mlrun/launcher/__init__.py +1 -1
  160. mlrun/launcher/base.py +16 -15
  161. mlrun/launcher/client.py +13 -11
  162. mlrun/launcher/factory.py +1 -1
  163. mlrun/launcher/local.py +23 -13
  164. mlrun/launcher/remote.py +17 -10
  165. mlrun/lists.py +7 -6
  166. mlrun/model.py +478 -103
  167. mlrun/model_monitoring/__init__.py +1 -1
  168. mlrun/model_monitoring/api.py +163 -371
  169. mlrun/{runtimes/mpijob/v1alpha1.py → model_monitoring/applications/__init__.py} +9 -15
  170. mlrun/model_monitoring/applications/_application_steps.py +188 -0
  171. mlrun/model_monitoring/applications/base.py +108 -0
  172. mlrun/model_monitoring/applications/context.py +341 -0
  173. mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
  174. mlrun/model_monitoring/applications/histogram_data_drift.py +354 -0
  175. mlrun/model_monitoring/applications/results.py +99 -0
  176. mlrun/model_monitoring/controller.py +131 -278
  177. mlrun/model_monitoring/db/__init__.py +18 -0
  178. mlrun/model_monitoring/db/stores/__init__.py +136 -0
  179. mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
  180. mlrun/model_monitoring/db/stores/base/store.py +213 -0
  181. mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
  182. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
  183. mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
  184. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
  185. mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
  186. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
  187. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
  188. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
  189. mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
  190. mlrun/model_monitoring/db/tsdb/base.py +448 -0
  191. mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
  192. mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
  193. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +279 -0
  194. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
  195. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +507 -0
  196. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  197. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
  198. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
  199. mlrun/model_monitoring/features_drift_table.py +134 -106
  200. mlrun/model_monitoring/helpers.py +199 -55
  201. mlrun/model_monitoring/metrics/__init__.py +13 -0
  202. mlrun/model_monitoring/metrics/histogram_distance.py +127 -0
  203. mlrun/model_monitoring/model_endpoint.py +3 -2
  204. mlrun/model_monitoring/stream_processing.py +134 -398
  205. mlrun/model_monitoring/tracking_policy.py +9 -2
  206. mlrun/model_monitoring/writer.py +161 -125
  207. mlrun/package/__init__.py +6 -6
  208. mlrun/package/context_handler.py +5 -5
  209. mlrun/package/packager.py +7 -7
  210. mlrun/package/packagers/default_packager.py +8 -8
  211. mlrun/package/packagers/numpy_packagers.py +15 -15
  212. mlrun/package/packagers/pandas_packagers.py +5 -5
  213. mlrun/package/packagers/python_standard_library_packagers.py +10 -10
  214. mlrun/package/packagers_manager.py +19 -23
  215. mlrun/package/utils/_formatter.py +6 -6
  216. mlrun/package/utils/_pickler.py +2 -2
  217. mlrun/package/utils/_supported_format.py +4 -4
  218. mlrun/package/utils/log_hint_utils.py +2 -2
  219. mlrun/package/utils/type_hint_utils.py +4 -9
  220. mlrun/platforms/__init__.py +11 -10
  221. mlrun/platforms/iguazio.py +24 -203
  222. mlrun/projects/operations.py +52 -25
  223. mlrun/projects/pipelines.py +191 -197
  224. mlrun/projects/project.py +1227 -400
  225. mlrun/render.py +16 -19
  226. mlrun/run.py +209 -184
  227. mlrun/runtimes/__init__.py +83 -15
  228. mlrun/runtimes/base.py +51 -35
  229. mlrun/runtimes/daskjob.py +17 -10
  230. mlrun/runtimes/databricks_job/databricks_cancel_task.py +1 -1
  231. mlrun/runtimes/databricks_job/databricks_runtime.py +8 -7
  232. mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
  233. mlrun/runtimes/funcdoc.py +1 -29
  234. mlrun/runtimes/function_reference.py +1 -1
  235. mlrun/runtimes/kubejob.py +34 -128
  236. mlrun/runtimes/local.py +40 -11
  237. mlrun/runtimes/mpijob/__init__.py +0 -20
  238. mlrun/runtimes/mpijob/abstract.py +9 -10
  239. mlrun/runtimes/mpijob/v1.py +1 -1
  240. mlrun/{model_monitoring/stores/models/sqlite.py → runtimes/nuclio/__init__.py} +7 -9
  241. mlrun/runtimes/nuclio/api_gateway.py +769 -0
  242. mlrun/runtimes/nuclio/application/__init__.py +15 -0
  243. mlrun/runtimes/nuclio/application/application.py +758 -0
  244. mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
  245. mlrun/runtimes/{function.py → nuclio/function.py} +200 -83
  246. mlrun/runtimes/{nuclio.py → nuclio/nuclio.py} +6 -6
  247. mlrun/runtimes/{serving.py → nuclio/serving.py} +65 -68
  248. mlrun/runtimes/pod.py +281 -101
  249. mlrun/runtimes/remotesparkjob.py +12 -9
  250. mlrun/runtimes/sparkjob/spark3job.py +67 -51
  251. mlrun/runtimes/utils.py +41 -75
  252. mlrun/secrets.py +9 -5
  253. mlrun/serving/__init__.py +8 -1
  254. mlrun/serving/remote.py +2 -7
  255. mlrun/serving/routers.py +85 -69
  256. mlrun/serving/server.py +69 -44
  257. mlrun/serving/states.py +209 -36
  258. mlrun/serving/utils.py +22 -14
  259. mlrun/serving/v1_serving.py +6 -7
  260. mlrun/serving/v2_serving.py +133 -54
  261. mlrun/track/tracker.py +2 -1
  262. mlrun/track/tracker_manager.py +3 -3
  263. mlrun/track/trackers/mlflow_tracker.py +6 -2
  264. mlrun/utils/async_http.py +6 -8
  265. mlrun/utils/azure_vault.py +1 -1
  266. mlrun/utils/clones.py +1 -2
  267. mlrun/utils/condition_evaluator.py +3 -3
  268. mlrun/utils/db.py +21 -3
  269. mlrun/utils/helpers.py +405 -225
  270. mlrun/utils/http.py +3 -6
  271. mlrun/utils/logger.py +112 -16
  272. mlrun/utils/notifications/notification/__init__.py +17 -13
  273. mlrun/utils/notifications/notification/base.py +50 -2
  274. mlrun/utils/notifications/notification/console.py +2 -0
  275. mlrun/utils/notifications/notification/git.py +24 -1
  276. mlrun/utils/notifications/notification/ipython.py +3 -1
  277. mlrun/utils/notifications/notification/slack.py +96 -21
  278. mlrun/utils/notifications/notification/webhook.py +59 -2
  279. mlrun/utils/notifications/notification_pusher.py +149 -30
  280. mlrun/utils/regex.py +9 -0
  281. mlrun/utils/retryer.py +208 -0
  282. mlrun/utils/singleton.py +1 -1
  283. mlrun/utils/v3io_clients.py +4 -6
  284. mlrun/utils/version/version.json +2 -2
  285. mlrun/utils/version/version.py +2 -6
  286. mlrun-1.7.0.dist-info/METADATA +378 -0
  287. mlrun-1.7.0.dist-info/RECORD +351 -0
  288. {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/WHEEL +1 -1
  289. mlrun/feature_store/retrieval/conversion.py +0 -273
  290. mlrun/kfpops.py +0 -868
  291. mlrun/model_monitoring/application.py +0 -310
  292. mlrun/model_monitoring/batch.py +0 -1095
  293. mlrun/model_monitoring/prometheus.py +0 -219
  294. mlrun/model_monitoring/stores/__init__.py +0 -111
  295. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -576
  296. mlrun/model_monitoring/stores/model_endpoint_store.py +0 -147
  297. mlrun/model_monitoring/stores/models/__init__.py +0 -27
  298. mlrun/model_monitoring/stores/models/base.py +0 -84
  299. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -384
  300. mlrun/platforms/other.py +0 -306
  301. mlrun-1.6.4rc8.dist-info/METADATA +0 -272
  302. mlrun-1.6.4rc8.dist-info/RECORD +0 -314
  303. {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/LICENSE +0 -0
  304. {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/entry_points.txt +0 -0
  305. {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.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
 
@@ -34,56 +38,27 @@ import mlrun.k8s_utils
34
38
  import mlrun.utils
35
39
  import mlrun.utils.helpers
36
40
  from mlrun.common.schemas import AuthInfo
37
-
38
- from ..config import config as mlconf
39
- from ..errors import err_to_str
40
- from ..kfpops import deploy_op
41
- from ..lists import RunList
42
- from ..model import RunObject
43
- from ..platforms.iguazio import (
44
- VolumeMount,
45
- mount_v3io,
41
+ from mlrun.config import config as mlconf
42
+ from mlrun.errors import err_to_str
43
+ from mlrun.lists import RunList
44
+ from mlrun.model import RunObject
45
+ from mlrun.platforms.iguazio import (
46
46
  parse_path,
47
47
  split_path,
48
- v3io_cred,
49
48
  )
50
- from ..utils import get_in, logger, update_in
51
- from .base import FunctionStatus, RunError
52
- from .pod import KubeResource, KubeResourceSpec
53
- from .utils import get_item_name, log_std
49
+ from mlrun.runtimes.base import FunctionStatus, RunError
50
+ from mlrun.runtimes.pod import KubeResource, KubeResourceSpec
51
+ from mlrun.runtimes.utils import get_item_name, log_std
52
+ from mlrun.utils import get_in, logger, update_in
54
53
 
55
54
 
56
55
  def validate_nuclio_version_compatibility(*min_versions):
57
56
  """
58
57
  :param min_versions: Valid minimum version(s) required, assuming no 2 versions has equal major and minor.
59
58
  """
60
- parsed_min_versions = [
61
- semver.VersionInfo.parse(min_version) for min_version in min_versions
62
- ]
63
- try:
64
- parsed_current_version = semver.VersionInfo.parse(mlconf.nuclio_version)
65
- except ValueError:
66
- # only log when version is set but invalid
67
- if mlconf.nuclio_version:
68
- logger.warning(
69
- "Unable to parse nuclio version, assuming compatibility",
70
- nuclio_version=mlconf.nuclio_version,
71
- min_versions=min_versions,
72
- )
73
- return True
74
-
75
- parsed_min_versions.sort(reverse=True)
76
- for parsed_min_version in parsed_min_versions:
77
- if (
78
- parsed_current_version.major == parsed_min_version.major
79
- and parsed_current_version.minor == parsed_min_version.minor
80
- and parsed_current_version.patch < parsed_min_version.patch
81
- ):
82
- return False
83
-
84
- if parsed_current_version >= parsed_min_version:
85
- return True
86
- return False
59
+ return mlrun.utils.helpers.validate_component_version_compatibility(
60
+ "nuclio", *min_versions
61
+ )
87
62
 
88
63
 
89
64
  def min_nuclio_versions(*versions):
@@ -92,9 +67,13 @@ def min_nuclio_versions(*versions):
92
67
  if validate_nuclio_version_compatibility(*versions):
93
68
  return function(*args, **kwargs)
94
69
 
70
+ if function.__name__ == "__init__":
71
+ name = inflection.titleize(function.__qualname__.split(".")[0])
72
+ else:
73
+ name = function.__qualname__
74
+
95
75
  message = (
96
- f"{function.__name__} is supported since nuclio {' or '.join(versions)}, currently using "
97
- f"nuclio {mlconf.nuclio_version}, please upgrade."
76
+ f"'{name}' function requires Nuclio v{' or v'.join(versions)} or higher"
98
77
  )
99
78
  raise mlrun.errors.MLRunIncompatibleVersionError(message)
100
79
 
@@ -292,6 +271,10 @@ class RemoteRuntime(KubeResource):
292
271
  def status(self, status):
293
272
  self._status = self._verify_dict(status, "status", NuclioStatus)
294
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
+
295
278
  def set_config(self, key, value):
296
279
  self.spec.config[key] = value
297
280
  return self
@@ -314,10 +297,37 @@ class RemoteRuntime(KubeResource):
314
297
  """
315
298
  if hasattr(spec, "to_dict"):
316
299
  spec = spec.to_dict()
300
+
301
+ self._validate_triggers(spec)
302
+
317
303
  spec["name"] = name
318
304
  self.spec.config[f"spec.triggers.{name}"] = spec
319
305
  return self
320
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
+
321
331
  def with_source_archive(
322
332
  self,
323
333
  source,
@@ -343,17 +353,21 @@ class RemoteRuntime(KubeResource):
343
353
 
344
354
  git::
345
355
 
346
- fn.with_source_archive("git://github.com/org/repo#my-branch",
347
- handler="main:handler",
348
- workdir="path/inside/repo")
356
+ fn.with_source_archive(
357
+ "git://github.com/org/repo#my-branch",
358
+ handler="main:handler",
359
+ workdir="path/inside/repo",
360
+ )
349
361
 
350
362
  s3::
351
363
 
352
364
  fn.spec.nuclio_runtime = "golang"
353
- fn.with_source_archive("s3://my-bucket/path/in/bucket/my-functions-archive",
365
+ fn.with_source_archive(
366
+ "s3://my-bucket/path/in/bucket/my-functions-archive",
354
367
  handler="my_func:Handler",
355
368
  workdir="path/inside/functions/archive",
356
- runtime="golang")
369
+ runtime="golang",
370
+ )
357
371
  """
358
372
  self.spec.build.source = source
359
373
  # update handler in function_handler
@@ -386,7 +400,7 @@ class RemoteRuntime(KubeResource):
386
400
  workers: typing.Optional[int] = 8,
387
401
  port: typing.Optional[int] = None,
388
402
  host: typing.Optional[str] = None,
389
- paths: typing.Optional[typing.List[str]] = None,
403
+ paths: typing.Optional[list[str]] = None,
390
404
  canary: typing.Optional[float] = None,
391
405
  secret: typing.Optional[str] = None,
392
406
  worker_timeout: typing.Optional[int] = None,
@@ -432,14 +446,8 @@ class RemoteRuntime(KubeResource):
432
446
  raise ValueError(
433
447
  "gateway timeout must be greater than the worker timeout"
434
448
  )
435
- annotations["nginx.ingress.kubernetes.io/proxy-connect-timeout"] = (
436
- f"{gateway_timeout}"
437
- )
438
- annotations["nginx.ingress.kubernetes.io/proxy-read-timeout"] = (
439
- f"{gateway_timeout}"
440
- )
441
- annotations["nginx.ingress.kubernetes.io/proxy-send-timeout"] = (
442
- f"{gateway_timeout}"
449
+ mlrun.runtimes.utils.enrich_gateway_timeout_annotations(
450
+ annotations, gateway_timeout
443
451
  )
444
452
 
445
453
  trigger = nuclio.HttpTrigger(
@@ -460,6 +468,11 @@ class RemoteRuntime(KubeResource):
460
468
  return self
461
469
 
462
470
  def from_image(self, image):
471
+ """
472
+ Deploy the function with an existing nuclio processor image.
473
+
474
+ :param image: image name
475
+ """
463
476
  config = nuclio.config.new_config()
464
477
  update_in(
465
478
  config,
@@ -510,6 +523,11 @@ class RemoteRuntime(KubeResource):
510
523
  extra_attributes = extra_attributes or {}
511
524
  if ack_window_size:
512
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
+
513
531
  self.add_trigger(
514
532
  name,
515
533
  V3IOStreamTrigger(
@@ -521,11 +539,14 @@ class RemoteRuntime(KubeResource):
521
539
  webapi=endpoint or "http://v3io-webapi:8081",
522
540
  extra_attributes=extra_attributes,
523
541
  read_batch_size=256,
542
+ access_key=access_key,
524
543
  **kwargs,
525
544
  ),
526
545
  )
527
- self.spec.min_replicas = shards
528
- self.spec.max_replicas = shards
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
529
550
 
530
551
  def deploy(
531
552
  self,
@@ -541,11 +562,16 @@ class RemoteRuntime(KubeResource):
541
562
  :param project: project name
542
563
  :param tag: function tag
543
564
  :param verbose: set True for verbose logging
544
- :param auth_info: service AuthInfo
565
+ :param auth_info: service AuthInfo (deprecated and ignored)
545
566
  :param builder_env: env vars dict for source archive config/credentials e.g. builder_env={"GIT_TOKEN": token}
546
567
  :param force_build: set True for force building the image
547
568
  """
548
- # todo: verify that the function name is normalized
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
+ )
549
575
 
550
576
  old_http_session = getattr(self, "_http_session", None)
551
577
  if old_http_session:
@@ -562,15 +588,12 @@ class RemoteRuntime(KubeResource):
562
588
  if tag:
563
589
  self.metadata.tag = tag
564
590
 
565
- save_record = False
566
591
  # Attempt auto-mounting, before sending to remote build
567
592
  self.try_auto_mount_based_on_config()
568
593
  self._fill_credentials()
569
594
  db = self._get_db()
570
595
  logger.info("Starting remote function deploy")
571
- data = db.remote_builder(
572
- self, False, builder_env=builder_env, force_build=force_build
573
- )
596
+ data = db.deploy_nuclio_function(func=self, builder_env=builder_env)
574
597
  self.status = data["data"].get("status")
575
598
  self._update_credentials_from_remote_build(data["data"])
576
599
 
@@ -578,19 +601,25 @@ class RemoteRuntime(KubeResource):
578
601
  # this also means that the function object will be updated with the function status
579
602
  self._wait_for_function_deployment(db, verbose=verbose)
580
603
 
604
+ return self._enrich_command_from_status()
605
+
606
+ def _enrich_command_from_status(self):
581
607
  # NOTE: on older mlrun versions & nuclio versions, function are exposed via NodePort
582
608
  # now, functions can be not exposed (using service type ClusterIP) and hence
583
609
  # for BC we first try to populate the external invocation url, and then
584
610
  # if not exists, take the internal invocation url
585
- if self.status.external_invocation_urls:
611
+ if (
612
+ self.status.external_invocation_urls
613
+ and self.status.external_invocation_urls[0] != ""
614
+ ):
586
615
  self.spec.command = f"http://{self.status.external_invocation_urls[0]}"
587
- save_record = True
588
- elif self.status.internal_invocation_urls:
616
+ elif (
617
+ self.status.internal_invocation_urls
618
+ and self.status.internal_invocation_urls[0] != ""
619
+ ):
589
620
  self.spec.command = f"http://{self.status.internal_invocation_urls[0]}"
590
- save_record = True
591
- elif self.status.address:
621
+ elif self.status.address and self.status.address != "":
592
622
  self.spec.command = f"http://{self.status.address}"
593
- save_record = True
594
623
 
595
624
  logger.info(
596
625
  "Successfully deployed function",
@@ -598,13 +627,11 @@ class RemoteRuntime(KubeResource):
598
627
  external_invocation_urls=self.status.external_invocation_urls,
599
628
  )
600
629
 
601
- if save_record:
602
- self.save(versioned=False)
630
+ self.save(versioned=False)
603
631
 
604
632
  return self.spec.command
605
633
 
606
634
  def _wait_for_function_deployment(self, db, verbose=False):
607
- text = ""
608
635
  state = ""
609
636
  last_log_timestamp = 1
610
637
  while state not in ["ready", "error", "unhealthy"]:
@@ -612,7 +639,7 @@ class RemoteRuntime(KubeResource):
612
639
  int(mlrun.mlconf.httpdb.logs.nuclio.pull_deploy_status_default_interval)
613
640
  )
614
641
  try:
615
- text, last_log_timestamp = db.get_builder_status(
642
+ text, last_log_timestamp = db.get_nuclio_deploy_status(
616
643
  self, last_log_timestamp=last_log_timestamp, verbose=verbose
617
644
  )
618
645
  except mlrun.db.RunDBError:
@@ -629,9 +656,9 @@ class RemoteRuntime(KubeResource):
629
656
  def with_node_selection(
630
657
  self,
631
658
  node_name: typing.Optional[str] = None,
632
- node_selector: typing.Optional[typing.Dict[str, str]] = None,
659
+ node_selector: typing.Optional[dict[str, str]] = None,
633
660
  affinity: typing.Optional[client.V1Affinity] = None,
634
- tolerations: typing.Optional[typing.List[client.V1Toleration]] = None,
661
+ tolerations: typing.Optional[list[client.V1Toleration]] = None,
635
662
  ):
636
663
  """k8s node selection attributes"""
637
664
  if tolerations and not validate_nuclio_version_compatibility("1.7.5"):
@@ -683,14 +710,14 @@ class RemoteRuntime(KubeResource):
683
710
 
684
711
  def set_state_thresholds(
685
712
  self,
686
- state_thresholds: typing.Dict[str, int],
713
+ state_thresholds: dict[str, int],
687
714
  patch: bool = True,
688
715
  ):
689
716
  raise NotImplementedError(
690
717
  "State thresholds do not apply for nuclio as it has its own function pods healthiness monitoring"
691
718
  )
692
719
 
693
- @min_nuclio_versions("1.12.8")
720
+ @min_nuclio_versions("1.13.1")
694
721
  def disable_default_http_trigger(
695
722
  self,
696
723
  ):
@@ -699,7 +726,7 @@ class RemoteRuntime(KubeResource):
699
726
  """
700
727
  self.spec.disable_default_http_trigger = True
701
728
 
702
- @min_nuclio_versions("1.12.8")
729
+ @min_nuclio_versions("1.13.1")
703
730
  def enable_default_http_trigger(
704
731
  self,
705
732
  ):
@@ -708,6 +735,10 @@ class RemoteRuntime(KubeResource):
708
735
  """
709
736
  self.spec.disable_default_http_trigger = False
710
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
+
711
742
  def _get_state(
712
743
  self,
713
744
  dashboard="",
@@ -716,7 +747,7 @@ class RemoteRuntime(KubeResource):
716
747
  raise_on_exception=True,
717
748
  resolve_address=True,
718
749
  auth_info: AuthInfo = None,
719
- ) -> typing.Tuple[str, str, typing.Optional[float]]:
750
+ ) -> tuple[str, str, typing.Optional[float]]:
720
751
  if dashboard:
721
752
  (
722
753
  state,
@@ -750,7 +781,7 @@ class RemoteRuntime(KubeResource):
750
781
  return state, text, last_log_timestamp
751
782
 
752
783
  try:
753
- text, last_log_timestamp = self._get_db().get_builder_status(
784
+ text, last_log_timestamp = self._get_db().get_nuclio_deploy_status(
754
785
  self, last_log_timestamp=last_log_timestamp, verbose=verbose
755
786
  )
756
787
  except mlrun.db.RunDBError:
@@ -770,10 +801,13 @@ class RemoteRuntime(KubeResource):
770
801
  runtime_env["MLRUN_NAMESPACE"] = mlconf.namespace
771
802
  if self.metadata.credentials.access_key:
772
803
  runtime_env[
773
- mlrun.runtimes.constants.FunctionEnvironmentVariables.auth_session
804
+ mlrun.common.runtimes.constants.FunctionEnvironmentVariables.auth_session
774
805
  ] = self.metadata.credentials.access_key
775
806
  return runtime_env
776
807
 
808
+ def _get_serving_spec(self):
809
+ return None
810
+
777
811
  def _get_nuclio_config_spec_env(self):
778
812
  env_dict = {}
779
813
  external_source_env_dict = {}
@@ -959,6 +993,62 @@ class RemoteRuntime(KubeResource):
959
993
  data = json.loads(data)
960
994
  return data
961
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
+ :param name: Sidecar container name.
1007
+ :param image: Sidecar container image.
1008
+ :param ports: Sidecar container ports to expose. Can be a single port or a list of ports.
1009
+ :param command: Sidecar container command instead of the image entrypoint.
1010
+ :param args: Sidecar container command args (requires command to be set).
1011
+ """
1012
+ name = name or f"{self.metadata.name}-sidecar"
1013
+ sidecar = self._set_sidecar(name)
1014
+ if image:
1015
+ sidecar["image"] = image
1016
+
1017
+ ports = mlrun.utils.helpers.as_list(ports)
1018
+ # according to RFC-6335, port name should be less than 15 characters,
1019
+ # so we truncate it if needed and leave room for the index
1020
+ port_name = name[:13].rstrip("-_") if len(name) > 13 else name
1021
+ sidecar["ports"] = [
1022
+ {
1023
+ "name": f"{port_name}-{i}",
1024
+ "containerPort": port,
1025
+ "protocol": "TCP",
1026
+ }
1027
+ for i, port in enumerate(ports)
1028
+ ]
1029
+
1030
+ # if it is a redeploy, 'command' might be set with the previous invocation url.
1031
+ # in this case, we don't want to use it as the sidecar command
1032
+ if command and not command.startswith("http"):
1033
+ sidecar["command"] = mlrun.utils.helpers.as_list(command)
1034
+
1035
+ if args and sidecar.get("command"):
1036
+ sidecar["args"] = mlrun.utils.helpers.as_list(args)
1037
+
1038
+ # populate the sidecar resources from the function spec
1039
+ if self.spec.resources:
1040
+ sidecar["resources"] = self.spec.resources
1041
+
1042
+ def _set_sidecar(self, name: str) -> dict:
1043
+ self.spec.config.setdefault("spec.sidecars", [])
1044
+ sidecars = self.spec.config["spec.sidecars"]
1045
+ for sidecar in sidecars:
1046
+ if sidecar["name"] == name:
1047
+ return sidecar
1048
+
1049
+ sidecars.append({"name": name})
1050
+ return sidecars[-1]
1051
+
962
1052
  def _trigger_of_kind_exists(self, kind: str) -> bool:
963
1053
  if not self.spec.config:
964
1054
  return False
@@ -1185,6 +1275,13 @@ class RemoteRuntime(KubeResource):
1185
1275
 
1186
1276
  return self._resolve_invocation_url("", force_external_address)
1187
1277
 
1278
+ @staticmethod
1279
+ def _resolve_v3io_access_key():
1280
+ # Nuclio supports generating access key for v3io stream trigger only from version 1.13.11
1281
+ if validate_nuclio_version_compatibility("1.13.11"):
1282
+ return mlrun.model.Credentials.generate_access_key
1283
+ return None
1284
+
1188
1285
 
1189
1286
  def parse_logs(logs):
1190
1287
  logs = json.loads(logs)
@@ -1279,3 +1376,23 @@ def get_nuclio_deploy_status(
1279
1376
  else:
1280
1377
  text = "\n".join(outputs) if outputs else ""
1281
1378
  return state, address, name, last_log_timestamp, text, function_status
1379
+
1380
+
1381
+ def enrich_nuclio_function_from_headers(
1382
+ func: RemoteRuntime,
1383
+ headers: dict,
1384
+ ):
1385
+ func.status.state = headers.get("x-mlrun-function-status", "")
1386
+ func.status.address = headers.get("x-mlrun-address", "")
1387
+ func.status.nuclio_name = headers.get("x-mlrun-name", "")
1388
+ func.status.internal_invocation_urls = (
1389
+ headers.get("x-mlrun-internal-invocation-urls", "").split(",")
1390
+ if headers.get("x-mlrun-internal-invocation-urls")
1391
+ else []
1392
+ )
1393
+ func.status.external_invocation_urls = (
1394
+ headers.get("x-mlrun-external-invocation-urls", "").split(",")
1395
+ if headers.get("x-mlrun-external-invocation-urls")
1396
+ else []
1397
+ )
1398
+ func.status.container_image = headers.get("x-mlrun-container-image", "")
@@ -17,13 +17,13 @@ import os
17
17
  import socket
18
18
 
19
19
  import mlrun.db
20
+ from mlrun.errors import err_to_str
21
+ from mlrun.execution import MLClientCtx
22
+ from mlrun.model import RunTemplate
23
+ from mlrun.runtimes.local import get_func_arg
24
+ from mlrun.serving.server import v2_serving_init
25
+ from mlrun.serving.v1_serving import nuclio_serving_init
20
26
 
21
- from ..errors import err_to_str
22
- from ..execution import MLClientCtx
23
- from ..model import RunTemplate
24
- from ..serving.server import v2_serving_init
25
- from ..serving.v1_serving import nuclio_serving_init
26
- from .local import get_func_arg
27
27
  from .serving import serving_subkind
28
28
 
29
29