mlrun 1.7.0rc14__py3-none-any.whl → 1.7.0rc22__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 +10 -1
- mlrun/__main__.py +23 -111
- mlrun/alerts/__init__.py +15 -0
- mlrun/alerts/alert.py +169 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +36 -253
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +46 -42
- mlrun/artifacts/model.py +9 -141
- mlrun/artifacts/plots.py +14 -375
- mlrun/common/constants.py +65 -3
- mlrun/common/formatters/__init__.py +19 -0
- mlrun/{runtimes/mpijob/v1alpha1.py → common/formatters/artifact.py} +6 -14
- mlrun/common/formatters/base.py +113 -0
- mlrun/common/formatters/function.py +46 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +10 -5
- mlrun/common/schemas/alert.py +92 -11
- mlrun/common/schemas/api_gateway.py +56 -0
- mlrun/common/schemas/artifact.py +15 -5
- mlrun/common/schemas/auth.py +2 -0
- mlrun/common/schemas/client_spec.py +1 -0
- mlrun/common/schemas/frontend_spec.py +1 -0
- mlrun/common/schemas/function.py +4 -0
- mlrun/common/schemas/model_monitoring/__init__.py +15 -3
- mlrun/common/schemas/model_monitoring/constants.py +58 -7
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +86 -2
- mlrun/common/schemas/pipeline.py +0 -9
- mlrun/common/schemas/project.py +5 -11
- mlrun/common/types.py +1 -0
- mlrun/config.py +30 -9
- mlrun/data_types/to_pandas.py +9 -9
- mlrun/datastore/base.py +41 -9
- mlrun/datastore/datastore.py +6 -2
- mlrun/datastore/datastore_profile.py +56 -4
- mlrun/datastore/inmem.py +2 -2
- mlrun/datastore/redis.py +2 -2
- mlrun/datastore/s3.py +5 -0
- mlrun/datastore/sources.py +147 -7
- mlrun/datastore/store_resources.py +7 -7
- mlrun/datastore/targets.py +110 -42
- mlrun/datastore/utils.py +42 -0
- mlrun/db/base.py +54 -10
- mlrun/db/httpdb.py +282 -79
- mlrun/db/nopdb.py +52 -10
- mlrun/errors.py +11 -0
- mlrun/execution.py +26 -9
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +12 -47
- mlrun/feature_store/feature_set.py +9 -0
- mlrun/feature_store/feature_vector.py +8 -0
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/conversion.py +9 -9
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +9 -3
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +16 -0
- mlrun/frameworks/__init__.py +6 -0
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- mlrun/frameworks/parallel_coordinates.py +2 -1
- mlrun/frameworks/tf_keras/__init__.py +4 -1
- mlrun/k8s_utils.py +10 -11
- mlrun/launcher/base.py +4 -3
- mlrun/launcher/client.py +5 -3
- mlrun/launcher/local.py +12 -2
- mlrun/launcher/remote.py +9 -2
- mlrun/lists.py +6 -2
- mlrun/model.py +47 -21
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +42 -18
- mlrun/model_monitoring/application.py +5 -305
- mlrun/model_monitoring/applications/__init__.py +11 -0
- mlrun/model_monitoring/applications/_application_steps.py +157 -0
- mlrun/model_monitoring/applications/base.py +280 -0
- mlrun/model_monitoring/applications/context.py +214 -0
- mlrun/model_monitoring/applications/evidently_base.py +211 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +132 -91
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +3 -1
- mlrun/model_monitoring/db/__init__.py +2 -0
- mlrun/model_monitoring/db/stores/__init__.py +0 -2
- mlrun/model_monitoring/db/stores/base/store.py +22 -37
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +43 -21
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +39 -8
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +27 -7
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +5 -0
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +246 -224
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +232 -216
- mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
- mlrun/model_monitoring/db/tsdb/base.py +316 -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 +240 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +401 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +658 -0
- mlrun/model_monitoring/evidently_application.py +6 -118
- mlrun/model_monitoring/helpers.py +63 -1
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +57 -216
- mlrun/model_monitoring/writer.py +134 -124
- mlrun/package/__init__.py +13 -1
- mlrun/package/packagers/__init__.py +6 -1
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +10 -9
- mlrun/platforms/iguazio.py +21 -202
- mlrun/projects/operations.py +24 -12
- mlrun/projects/pipelines.py +79 -102
- mlrun/projects/project.py +271 -103
- mlrun/render.py +15 -14
- mlrun/run.py +16 -46
- mlrun/runtimes/__init__.py +6 -3
- mlrun/runtimes/base.py +14 -7
- mlrun/runtimes/daskjob.py +1 -0
- mlrun/runtimes/databricks_job/databricks_runtime.py +1 -0
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +0 -28
- mlrun/runtimes/kubejob.py +2 -1
- mlrun/runtimes/local.py +12 -3
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/runtimes/nuclio/api_gateway.py +194 -84
- mlrun/runtimes/nuclio/application/application.py +170 -8
- mlrun/runtimes/nuclio/function.py +39 -49
- mlrun/runtimes/pod.py +16 -36
- mlrun/runtimes/remotesparkjob.py +9 -3
- mlrun/runtimes/sparkjob/spark3job.py +1 -1
- mlrun/runtimes/utils.py +6 -45
- mlrun/serving/__init__.py +8 -1
- mlrun/serving/server.py +2 -1
- mlrun/serving/states.py +51 -8
- mlrun/serving/utils.py +19 -11
- mlrun/serving/v2_serving.py +5 -1
- mlrun/track/tracker.py +2 -1
- mlrun/utils/async_http.py +25 -5
- mlrun/utils/helpers.py +157 -83
- mlrun/utils/logger.py +39 -7
- mlrun/utils/notifications/notification/__init__.py +14 -9
- mlrun/utils/notifications/notification/base.py +1 -1
- mlrun/utils/notifications/notification/slack.py +34 -7
- mlrun/utils/notifications/notification/webhook.py +1 -1
- mlrun/utils/notifications/notification_pusher.py +147 -16
- mlrun/utils/regex.py +9 -0
- mlrun/utils/v3io_clients.py +0 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/METADATA +14 -6
- {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/RECORD +158 -138
- mlrun/kfpops.py +0 -865
- mlrun/platforms/other.py +0 -305
- {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/WHEEL +0 -0
- {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/top_level.txt +0 -0
|
@@ -17,31 +17,30 @@ from typing import Optional, Union
|
|
|
17
17
|
from urllib.parse import urljoin
|
|
18
18
|
|
|
19
19
|
import requests
|
|
20
|
-
from
|
|
20
|
+
from nuclio.auth import AuthInfo as NuclioAuthInfo
|
|
21
|
+
from nuclio.auth import AuthKinds as NuclioAuthKinds
|
|
21
22
|
|
|
22
23
|
import mlrun
|
|
23
|
-
import mlrun.common.
|
|
24
|
+
import mlrun.common.constants as mlrun_constants
|
|
25
|
+
import mlrun.common.schemas as schemas
|
|
26
|
+
import mlrun.common.types
|
|
27
|
+
from mlrun.model import ModelObj
|
|
28
|
+
from mlrun.platforms.iguazio import min_iguazio_versions
|
|
29
|
+
from mlrun.utils import logger
|
|
24
30
|
|
|
25
|
-
from
|
|
26
|
-
from ..utils import logger
|
|
27
|
-
from .function import RemoteRuntime, get_fullname, min_nuclio_versions
|
|
28
|
-
from .serving import ServingRuntime
|
|
31
|
+
from .function import min_nuclio_versions
|
|
29
32
|
|
|
30
|
-
NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH = "basicAuth"
|
|
31
|
-
NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_NONE = "none"
|
|
32
|
-
PROJECT_NAME_LABEL = "nuclio.io/project-name"
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
class APIGatewayAuthenticator(typing.Protocol):
|
|
34
|
+
class Authenticator(typing.Protocol):
|
|
36
35
|
@property
|
|
37
36
|
def authentication_mode(self) -> str:
|
|
38
|
-
return
|
|
37
|
+
return schemas.APIGatewayAuthenticationMode.none.value
|
|
39
38
|
|
|
40
39
|
@classmethod
|
|
41
|
-
def from_scheme(cls, api_gateway_spec:
|
|
40
|
+
def from_scheme(cls, api_gateway_spec: schemas.APIGatewaySpec):
|
|
42
41
|
if (
|
|
43
42
|
api_gateway_spec.authenticationMode
|
|
44
|
-
==
|
|
43
|
+
== schemas.APIGatewayAuthenticationMode.basic.value
|
|
45
44
|
):
|
|
46
45
|
if api_gateway_spec.authentication:
|
|
47
46
|
return BasicAuth(
|
|
@@ -50,15 +49,24 @@ class APIGatewayAuthenticator(typing.Protocol):
|
|
|
50
49
|
)
|
|
51
50
|
else:
|
|
52
51
|
return BasicAuth()
|
|
52
|
+
elif (
|
|
53
|
+
api_gateway_spec.authenticationMode
|
|
54
|
+
== schemas.APIGatewayAuthenticationMode.access_key.value
|
|
55
|
+
):
|
|
56
|
+
return AccessKeyAuth()
|
|
53
57
|
else:
|
|
54
58
|
return NoneAuth()
|
|
55
59
|
|
|
56
60
|
def to_scheme(
|
|
57
61
|
self,
|
|
58
|
-
) -> Optional[dict[str, Optional[
|
|
62
|
+
) -> Optional[dict[str, Optional[schemas.APIGatewayBasicAuth]]]:
|
|
59
63
|
return None
|
|
60
64
|
|
|
61
65
|
|
|
66
|
+
class APIGatewayAuthenticator(Authenticator, ModelObj):
|
|
67
|
+
_dict_fields = ["authentication_mode"]
|
|
68
|
+
|
|
69
|
+
|
|
62
70
|
class NoneAuth(APIGatewayAuthenticator):
|
|
63
71
|
"""
|
|
64
72
|
An API gateway authenticator with no authentication.
|
|
@@ -81,18 +89,28 @@ class BasicAuth(APIGatewayAuthenticator):
|
|
|
81
89
|
|
|
82
90
|
@property
|
|
83
91
|
def authentication_mode(self) -> str:
|
|
84
|
-
return
|
|
92
|
+
return schemas.APIGatewayAuthenticationMode.basic.value
|
|
85
93
|
|
|
86
94
|
def to_scheme(
|
|
87
95
|
self,
|
|
88
|
-
) -> Optional[dict[str, Optional[
|
|
96
|
+
) -> Optional[dict[str, Optional[schemas.APIGatewayBasicAuth]]]:
|
|
89
97
|
return {
|
|
90
|
-
"basicAuth":
|
|
98
|
+
"basicAuth": schemas.APIGatewayBasicAuth(
|
|
91
99
|
username=self._username, password=self._password
|
|
92
100
|
)
|
|
93
101
|
}
|
|
94
102
|
|
|
95
103
|
|
|
104
|
+
class AccessKeyAuth(APIGatewayAuthenticator):
|
|
105
|
+
"""
|
|
106
|
+
An API gateway authenticator with access key authentication.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def authentication_mode(self) -> str:
|
|
111
|
+
return schemas.APIGatewayAuthenticationMode.access_key.value
|
|
112
|
+
|
|
113
|
+
|
|
96
114
|
class APIGatewayMetadata(ModelObj):
|
|
97
115
|
_dict_fields = ["name", "namespace", "labels", "annotations", "creation_timestamp"]
|
|
98
116
|
|
|
@@ -138,17 +156,17 @@ class APIGatewaySpec(ModelObj):
|
|
|
138
156
|
def __init__(
|
|
139
157
|
self,
|
|
140
158
|
functions: Union[
|
|
141
|
-
list[
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
],
|
|
149
|
-
RemoteRuntime,
|
|
150
|
-
ServingRuntime,
|
|
159
|
+
list[
|
|
160
|
+
Union[
|
|
161
|
+
str,
|
|
162
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
163
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
164
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
165
|
+
]
|
|
151
166
|
],
|
|
167
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
168
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
169
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
152
170
|
],
|
|
153
171
|
project: str = None,
|
|
154
172
|
description: str = "",
|
|
@@ -156,20 +174,24 @@ class APIGatewaySpec(ModelObj):
|
|
|
156
174
|
path: str = "/",
|
|
157
175
|
authentication: Optional[APIGatewayAuthenticator] = NoneAuth(),
|
|
158
176
|
canary: Optional[list[int]] = None,
|
|
177
|
+
ports: Optional[list[int]] = None,
|
|
159
178
|
):
|
|
160
179
|
"""
|
|
161
180
|
:param functions: The list of functions associated with the API gateway
|
|
162
181
|
Can be a list of function names (["my-func1", "my-func2"])
|
|
163
182
|
or a list or a single entity of
|
|
164
183
|
:py:class:`~mlrun.runtimes.nuclio.function.RemoteRuntime` OR
|
|
165
|
-
:py:class:`~mlrun.runtimes.nuclio.serving.ServingRuntime`
|
|
184
|
+
:py:class:`~mlrun.runtimes.nuclio.serving.ServingRuntime` OR
|
|
185
|
+
:py:class:`~mlrun.runtimes.nuclio.application.ApplicationRuntime`
|
|
166
186
|
:param project: The project name
|
|
167
187
|
:param description: Optional description of the API gateway
|
|
168
188
|
:param path: Optional path of the API gateway, default value is "/"
|
|
169
189
|
:param authentication: The authentication for the API gateway of type
|
|
170
190
|
:py:class:`~mlrun.runtimes.nuclio.api_gateway.BasicAuth`
|
|
171
191
|
:param host: The host of the API gateway (optional). If not set, it will be automatically generated
|
|
172
|
-
:param canary: The canary percents for the API gateway of type list[int]; for instance: [20,80]
|
|
192
|
+
:param canary: The canary percents for the API gateway of type list[int]; for instance: [20,80] (optional)
|
|
193
|
+
:param ports: The ports of the API gateway, as a list of integers that correspond to the functions in the
|
|
194
|
+
functions list. for instance: [8050] or [8050, 8081] (optional)
|
|
173
195
|
"""
|
|
174
196
|
self.description = description
|
|
175
197
|
self.host = host
|
|
@@ -178,26 +200,28 @@ class APIGatewaySpec(ModelObj):
|
|
|
178
200
|
self.functions = functions
|
|
179
201
|
self.canary = canary
|
|
180
202
|
self.project = project
|
|
203
|
+
self.ports = ports
|
|
181
204
|
|
|
182
|
-
self.validate(project=project, functions=functions, canary=canary)
|
|
205
|
+
self.validate(project=project, functions=functions, canary=canary, ports=ports)
|
|
183
206
|
|
|
184
207
|
def validate(
|
|
185
208
|
self,
|
|
186
209
|
project: str,
|
|
187
210
|
functions: Union[
|
|
188
|
-
list[
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
],
|
|
196
|
-
RemoteRuntime,
|
|
197
|
-
ServingRuntime,
|
|
211
|
+
list[
|
|
212
|
+
Union[
|
|
213
|
+
str,
|
|
214
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
215
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
216
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
217
|
+
]
|
|
198
218
|
],
|
|
219
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
220
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
221
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
199
222
|
],
|
|
200
223
|
canary: Optional[list[int]] = None,
|
|
224
|
+
ports: Optional[list[int]] = None,
|
|
201
225
|
):
|
|
202
226
|
self.functions = self._validate_functions(project=project, functions=functions)
|
|
203
227
|
|
|
@@ -205,6 +229,10 @@ class APIGatewaySpec(ModelObj):
|
|
|
205
229
|
if canary:
|
|
206
230
|
self.canary = self._validate_canary(canary)
|
|
207
231
|
|
|
232
|
+
# validating ports
|
|
233
|
+
if ports:
|
|
234
|
+
self.ports = self._validate_ports(ports)
|
|
235
|
+
|
|
208
236
|
def _validate_canary(self, canary: list[int]):
|
|
209
237
|
if len(self.functions) != len(canary):
|
|
210
238
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
@@ -221,20 +249,29 @@ class APIGatewaySpec(ModelObj):
|
|
|
221
249
|
)
|
|
222
250
|
return canary
|
|
223
251
|
|
|
252
|
+
def _validate_ports(self, ports):
|
|
253
|
+
if len(self.functions) != len(ports):
|
|
254
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
255
|
+
"Function and port lists lengths do not match"
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
return ports
|
|
259
|
+
|
|
224
260
|
@staticmethod
|
|
225
261
|
def _validate_functions(
|
|
226
262
|
project: str,
|
|
227
263
|
functions: Union[
|
|
228
|
-
list[
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
],
|
|
236
|
-
Union[RemoteRuntime, ServingRuntime],
|
|
264
|
+
list[
|
|
265
|
+
Union[
|
|
266
|
+
str,
|
|
267
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
268
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
269
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
270
|
+
]
|
|
237
271
|
],
|
|
272
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
273
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
274
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
238
275
|
],
|
|
239
276
|
):
|
|
240
277
|
if not isinstance(functions, list):
|
|
@@ -250,7 +287,21 @@ class APIGatewaySpec(ModelObj):
|
|
|
250
287
|
function_names = []
|
|
251
288
|
for func in functions:
|
|
252
289
|
if isinstance(func, str):
|
|
253
|
-
|
|
290
|
+
# check whether the function was passed as a URI or just a name
|
|
291
|
+
parsed_project, function_name, _, _ = (
|
|
292
|
+
mlrun.common.helpers.parse_versioned_object_uri(func)
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
if parsed_project and function_name:
|
|
296
|
+
# check that parsed project and passed project are the same
|
|
297
|
+
if parsed_project != project:
|
|
298
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
299
|
+
"Function doesn't belong to passed project"
|
|
300
|
+
)
|
|
301
|
+
function_uri = func
|
|
302
|
+
else:
|
|
303
|
+
function_uri = mlrun.utils.generate_object_uri(project, func)
|
|
304
|
+
function_names.append(function_uri)
|
|
254
305
|
continue
|
|
255
306
|
|
|
256
307
|
function_name = (
|
|
@@ -265,8 +316,13 @@ class APIGatewaySpec(ModelObj):
|
|
|
265
316
|
f"input function {function_name} "
|
|
266
317
|
f"does not belong to this project"
|
|
267
318
|
)
|
|
268
|
-
|
|
269
|
-
|
|
319
|
+
function_uri = mlrun.utils.generate_object_uri(
|
|
320
|
+
project,
|
|
321
|
+
function_name,
|
|
322
|
+
func.metadata.tag,
|
|
323
|
+
func.metadata.hash,
|
|
324
|
+
)
|
|
325
|
+
function_names.append(function_uri)
|
|
270
326
|
return function_names
|
|
271
327
|
|
|
272
328
|
|
|
@@ -312,8 +368,9 @@ class APIGateway(ModelObj):
|
|
|
312
368
|
def invoke(
|
|
313
369
|
self,
|
|
314
370
|
method="POST",
|
|
315
|
-
headers: dict =
|
|
316
|
-
|
|
371
|
+
headers: dict = None,
|
|
372
|
+
credentials: Optional[tuple[str, str]] = None,
|
|
373
|
+
path: Optional[str] = None,
|
|
317
374
|
**kwargs,
|
|
318
375
|
):
|
|
319
376
|
"""
|
|
@@ -321,7 +378,9 @@ class APIGateway(ModelObj):
|
|
|
321
378
|
|
|
322
379
|
:param method: (str, optional) The HTTP method for the invocation.
|
|
323
380
|
:param headers: (dict, optional) The HTTP headers for the invocation.
|
|
324
|
-
:param
|
|
381
|
+
:param credentials: (Optional[tuple[str, str]], optional) The (username,password) for the invocation if required
|
|
382
|
+
can also be set by the environment variable (_, V3IO_ACCESS_KEY) for access key authentication.
|
|
383
|
+
:param path: (str, optional) The sub-path for the invocation.
|
|
325
384
|
:param kwargs: (dict) Additional keyword arguments.
|
|
326
385
|
|
|
327
386
|
:return: The response from the API gateway invocation.
|
|
@@ -338,20 +397,44 @@ class APIGateway(ModelObj):
|
|
|
338
397
|
f"API gateway is not ready. " f"Current state: {self.state}"
|
|
339
398
|
)
|
|
340
399
|
|
|
400
|
+
auth = None
|
|
401
|
+
|
|
341
402
|
if (
|
|
342
403
|
self.spec.authentication.authentication_mode
|
|
343
|
-
==
|
|
344
|
-
and not auth
|
|
404
|
+
== schemas.APIGatewayAuthenticationMode.basic.value
|
|
345
405
|
):
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
406
|
+
if not credentials:
|
|
407
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
408
|
+
"API Gateway invocation requires authentication. Please pass credentials"
|
|
409
|
+
)
|
|
410
|
+
auth = NuclioAuthInfo(
|
|
411
|
+
username=credentials[0], password=credentials[1]
|
|
412
|
+
).to_requests_auth()
|
|
413
|
+
|
|
414
|
+
if (
|
|
415
|
+
self.spec.authentication.authentication_mode
|
|
416
|
+
== schemas.APIGatewayAuthenticationMode.access_key.value
|
|
417
|
+
):
|
|
418
|
+
# inject access key from env
|
|
419
|
+
if credentials:
|
|
420
|
+
auth = NuclioAuthInfo(
|
|
421
|
+
username=credentials[0],
|
|
422
|
+
password=credentials[1],
|
|
423
|
+
mode=NuclioAuthKinds.iguazio,
|
|
424
|
+
).to_requests_auth()
|
|
425
|
+
else:
|
|
426
|
+
auth = NuclioAuthInfo().from_envvar().to_requests_auth()
|
|
427
|
+
if not auth:
|
|
428
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
429
|
+
"API Gateway invocation requires authentication. Please set V3IO_ACCESS_KEY env var"
|
|
430
|
+
)
|
|
431
|
+
url = urljoin(self.invoke_url, path or "")
|
|
349
432
|
return requests.request(
|
|
350
433
|
method=method,
|
|
351
|
-
url=
|
|
352
|
-
headers=headers,
|
|
434
|
+
url=url,
|
|
435
|
+
headers=headers or {},
|
|
436
|
+
auth=auth,
|
|
353
437
|
**kwargs,
|
|
354
|
-
auth=HTTPBasicAuth(*auth) if auth else None,
|
|
355
438
|
)
|
|
356
439
|
|
|
357
440
|
def wait_for_readiness(self, max_wait_time=90):
|
|
@@ -376,10 +459,10 @@ class APIGateway(ModelObj):
|
|
|
376
459
|
)
|
|
377
460
|
|
|
378
461
|
def is_ready(self):
|
|
379
|
-
if self.state is not
|
|
462
|
+
if self.state is not schemas.api_gateway.APIGatewayState.ready:
|
|
380
463
|
# try to sync the state
|
|
381
464
|
self.sync()
|
|
382
|
-
return self.state ==
|
|
465
|
+
return self.state == schemas.api_gateway.APIGatewayState.ready
|
|
383
466
|
|
|
384
467
|
def sync(self):
|
|
385
468
|
"""
|
|
@@ -407,16 +490,27 @@ class APIGateway(ModelObj):
|
|
|
407
490
|
"""
|
|
408
491
|
self.spec.authentication = BasicAuth(username=username, password=password)
|
|
409
492
|
|
|
493
|
+
@min_iguazio_versions("3.5.5")
|
|
494
|
+
def with_access_key_auth(self):
|
|
495
|
+
"""
|
|
496
|
+
Set access key authentication for the API gateway.
|
|
497
|
+
"""
|
|
498
|
+
self.spec.authentication = AccessKeyAuth()
|
|
499
|
+
|
|
410
500
|
def with_canary(
|
|
411
501
|
self,
|
|
412
502
|
functions: Union[
|
|
413
|
-
list[str],
|
|
414
503
|
list[
|
|
415
504
|
Union[
|
|
416
|
-
|
|
417
|
-
|
|
505
|
+
str,
|
|
506
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
507
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
508
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
418
509
|
]
|
|
419
510
|
],
|
|
511
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
512
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
513
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
420
514
|
],
|
|
421
515
|
canary: list[int],
|
|
422
516
|
):
|
|
@@ -427,7 +521,8 @@ class APIGateway(ModelObj):
|
|
|
427
521
|
Can be a list of function names (["my-func1", "my-func2"])
|
|
428
522
|
or a list of nuclio functions of types
|
|
429
523
|
:py:class:`~mlrun.runtimes.nuclio.function.RemoteRuntime` OR
|
|
430
|
-
:py:class:`~mlrun.runtimes.nuclio.serving.ServingRuntime`
|
|
524
|
+
:py:class:`~mlrun.runtimes.nuclio.serving.ServingRuntime` OR
|
|
525
|
+
:py:class:`~mlrun.runtimes.nuclio.application.ApplicationRuntime`
|
|
431
526
|
:param canary: The canary percents for the API gateway of type list[int]; for instance: [20,80]
|
|
432
527
|
|
|
433
528
|
"""
|
|
@@ -440,14 +535,27 @@ class APIGateway(ModelObj):
|
|
|
440
535
|
project=self.spec.project, functions=functions, canary=canary
|
|
441
536
|
)
|
|
442
537
|
|
|
538
|
+
def with_ports(self, ports: list[int]):
|
|
539
|
+
"""
|
|
540
|
+
Set ports for the API gateway
|
|
541
|
+
|
|
542
|
+
:param ports: The ports of the API gateway, as a list of integers that correspond to the functions in the
|
|
543
|
+
functions list. for instance: [8050] or [8050, 8081]
|
|
544
|
+
"""
|
|
545
|
+
self.spec.validate(
|
|
546
|
+
project=self.spec.project, functions=self.spec.functions, ports=ports
|
|
547
|
+
)
|
|
548
|
+
|
|
443
549
|
@classmethod
|
|
444
|
-
def from_scheme(cls, api_gateway:
|
|
445
|
-
project = api_gateway.metadata.labels.get(
|
|
550
|
+
def from_scheme(cls, api_gateway: schemas.APIGateway):
|
|
551
|
+
project = api_gateway.metadata.labels.get(
|
|
552
|
+
mlrun_constants.MLRunInternalLabels.nuclio_project_name
|
|
553
|
+
)
|
|
446
554
|
functions, canary = cls._resolve_canary(api_gateway.spec.upstreams)
|
|
447
555
|
state = (
|
|
448
556
|
api_gateway.status.state
|
|
449
557
|
if api_gateway.status
|
|
450
|
-
else
|
|
558
|
+
else schemas.APIGatewayState.none
|
|
451
559
|
)
|
|
452
560
|
new_api_gateway = cls(
|
|
453
561
|
metadata=APIGatewayMetadata(
|
|
@@ -466,14 +574,14 @@ class APIGateway(ModelObj):
|
|
|
466
574
|
new_api_gateway.state = state
|
|
467
575
|
return new_api_gateway
|
|
468
576
|
|
|
469
|
-
def to_scheme(self) ->
|
|
577
|
+
def to_scheme(self) -> schemas.APIGateway:
|
|
470
578
|
upstreams = (
|
|
471
579
|
[
|
|
472
|
-
|
|
580
|
+
schemas.APIGatewayUpstream(
|
|
473
581
|
nucliofunction={"name": self.spec.functions[0]},
|
|
474
582
|
percentage=self.spec.canary[0],
|
|
475
583
|
),
|
|
476
|
-
|
|
584
|
+
schemas.APIGatewayUpstream(
|
|
477
585
|
# do not set percent for the second function,
|
|
478
586
|
# so we can define which function to display as a primary one in UI
|
|
479
587
|
nucliofunction={"name": self.spec.functions[1]},
|
|
@@ -481,22 +589,24 @@ class APIGateway(ModelObj):
|
|
|
481
589
|
]
|
|
482
590
|
if self.spec.canary
|
|
483
591
|
else [
|
|
484
|
-
|
|
592
|
+
schemas.APIGatewayUpstream(
|
|
485
593
|
nucliofunction={"name": function_name},
|
|
486
594
|
)
|
|
487
595
|
for function_name in self.spec.functions
|
|
488
596
|
]
|
|
489
597
|
)
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
598
|
+
if self.spec.ports:
|
|
599
|
+
for i, port in enumerate(self.spec.ports):
|
|
600
|
+
upstreams[i].port = port
|
|
601
|
+
|
|
602
|
+
api_gateway = schemas.APIGateway(
|
|
603
|
+
metadata=schemas.APIGatewayMetadata(name=self.metadata.name, labels={}),
|
|
604
|
+
spec=schemas.APIGatewaySpec(
|
|
495
605
|
name=self.metadata.name,
|
|
496
606
|
description=self.spec.description,
|
|
497
607
|
host=self.spec.host,
|
|
498
608
|
path=self.spec.path,
|
|
499
|
-
authenticationMode=
|
|
609
|
+
authenticationMode=schemas.APIGatewayAuthenticationMode.from_str(
|
|
500
610
|
self.spec.authentication.authentication_mode
|
|
501
611
|
),
|
|
502
612
|
upstreams=upstreams,
|
|
@@ -526,7 +636,7 @@ class APIGateway(ModelObj):
|
|
|
526
636
|
|
|
527
637
|
@staticmethod
|
|
528
638
|
def _resolve_canary(
|
|
529
|
-
upstreams: list[
|
|
639
|
+
upstreams: list[schemas.APIGatewayUpstream],
|
|
530
640
|
) -> tuple[Union[list[str], None], Union[list[int], None]]:
|
|
531
641
|
if len(upstreams) == 1:
|
|
532
642
|
return [upstreams[0].nucliofunction.get("name")], None
|