mlrun 1.8.0rc5__py3-none-any.whl → 1.8.0rc6__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/artifacts/__init__.py +1 -1
- mlrun/artifacts/base.py +12 -1
- mlrun/artifacts/document.py +59 -38
- mlrun/common/model_monitoring/__init__.py +0 -2
- mlrun/common/model_monitoring/helpers.py +0 -28
- mlrun/common/schemas/__init__.py +1 -4
- mlrun/common/schemas/client_spec.py +0 -1
- mlrun/common/schemas/model_monitoring/__init__.py +0 -6
- mlrun/common/schemas/model_monitoring/constants.py +11 -9
- mlrun/common/schemas/model_monitoring/model_endpoints.py +77 -149
- mlrun/common/schemas/notification.py +6 -0
- mlrun/config.py +0 -2
- mlrun/datastore/datastore_profile.py +57 -17
- mlrun/datastore/vectorstore.py +67 -59
- mlrun/db/base.py +22 -18
- mlrun/db/httpdb.py +116 -148
- mlrun/db/nopdb.py +33 -17
- mlrun/execution.py +11 -4
- mlrun/model.py +3 -0
- mlrun/model_monitoring/__init__.py +3 -2
- mlrun/model_monitoring/api.py +40 -43
- mlrun/model_monitoring/applications/_application_steps.py +3 -1
- mlrun/model_monitoring/applications/context.py +15 -17
- mlrun/model_monitoring/controller.py +43 -37
- mlrun/model_monitoring/db/__init__.py +0 -2
- mlrun/model_monitoring/db/tsdb/base.py +2 -1
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +2 -1
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +43 -0
- mlrun/model_monitoring/helpers.py +12 -66
- mlrun/model_monitoring/stream_processing.py +83 -270
- mlrun/model_monitoring/writer.py +1 -10
- mlrun/projects/project.py +63 -55
- mlrun/runtimes/nuclio/function.py +7 -6
- mlrun/runtimes/nuclio/serving.py +7 -1
- mlrun/serving/routers.py +158 -145
- mlrun/serving/server.py +6 -0
- mlrun/serving/states.py +2 -0
- mlrun/serving/v2_serving.py +69 -60
- mlrun/utils/helpers.py +14 -30
- mlrun/utils/notifications/notification/mail.py +17 -6
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc6.dist-info}/METADATA +1 -1
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc6.dist-info}/RECORD +47 -60
- mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +0 -149
- mlrun/model_monitoring/db/stores/__init__.py +0 -136
- mlrun/model_monitoring/db/stores/base/__init__.py +0 -15
- mlrun/model_monitoring/db/stores/base/store.py +0 -154
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -46
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -93
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -47
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -25
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -408
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -464
- mlrun/model_monitoring/model_endpoint.py +0 -120
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc6.dist-info}/LICENSE +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc6.dist-info}/WHEEL +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc6.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc6.dist-info}/top_level.txt +0 -0
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# Copyright 2023 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
#
|
|
15
|
-
import abc
|
|
16
|
-
from typing import Optional
|
|
17
|
-
|
|
18
|
-
from pydantic.v1 import BaseModel, Field, constr
|
|
19
|
-
|
|
20
|
-
from ..object import ObjectKind, ObjectMetadata, ObjectSpec, ObjectStatus
|
|
21
|
-
from .constants import (
|
|
22
|
-
PROJECT_PATTERN,
|
|
23
|
-
EndpointType,
|
|
24
|
-
ModelMonitoringMode,
|
|
25
|
-
)
|
|
26
|
-
from .model_endpoints import _mapping_attributes
|
|
27
|
-
|
|
28
|
-
# TODO : replace ModelEndpoint
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class ModelEndpointParser(abc.ABC, BaseModel):
|
|
32
|
-
@classmethod
|
|
33
|
-
def json_parse_values(cls) -> list[str]:
|
|
34
|
-
return []
|
|
35
|
-
|
|
36
|
-
@classmethod
|
|
37
|
-
def from_flat_dict(
|
|
38
|
-
cls, endpoint_dict: dict, json_parse_values: Optional[list] = None
|
|
39
|
-
):
|
|
40
|
-
"""Create a `ModelEndpointMetadata` object from an endpoint dictionary
|
|
41
|
-
|
|
42
|
-
:param endpoint_dict: Model endpoint dictionary.
|
|
43
|
-
:param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
|
|
44
|
-
dictionary using json.loads().
|
|
45
|
-
"""
|
|
46
|
-
if json_parse_values is None:
|
|
47
|
-
json_parse_values = cls.json_parse_values()
|
|
48
|
-
|
|
49
|
-
return _mapping_attributes(
|
|
50
|
-
model_class=cls,
|
|
51
|
-
flattened_dictionary=endpoint_dict,
|
|
52
|
-
json_parse_values=json_parse_values,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class ModelEndpointV2Metadata(ObjectMetadata, ModelEndpointParser):
|
|
57
|
-
project: constr(regex=PROJECT_PATTERN)
|
|
58
|
-
endpoint_type: Optional[EndpointType] = EndpointType.NODE_EP.value
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class ModelEndpointV2Spec(ObjectSpec, ModelEndpointParser):
|
|
62
|
-
model_uid: Optional[str] = ""
|
|
63
|
-
model_name: Optional[str] = ""
|
|
64
|
-
model_tag: Optional[str] = ""
|
|
65
|
-
model_class: Optional[str] = ""
|
|
66
|
-
function_name: Optional[str] = ""
|
|
67
|
-
function_uid: Optional[str] = ""
|
|
68
|
-
feature_names: Optional[list[str]] = []
|
|
69
|
-
label_names: Optional[list[str]] = []
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class ModelEndpointV2Status(ObjectStatus, ModelEndpointParser):
|
|
73
|
-
state: Optional[str] = "unknown" # will be updated according to the function state
|
|
74
|
-
first_request: Optional[str] = ""
|
|
75
|
-
children: Optional[list[str]] = []
|
|
76
|
-
children_uids: Optional[list[str]] = []
|
|
77
|
-
monitoring_feature_set_uri: Optional[str] = ""
|
|
78
|
-
monitoring_mode: Optional[ModelMonitoringMode] = ModelMonitoringMode.disabled.value
|
|
79
|
-
function_uri: Optional[str] = "" # <project_name>/<function_name>:<tag>
|
|
80
|
-
model_uri: Optional[str] = ""
|
|
81
|
-
|
|
82
|
-
# operative
|
|
83
|
-
last_request: Optional[str] = ""
|
|
84
|
-
drift_status: Optional[str] = ""
|
|
85
|
-
avg_latency: Optional[float] = None
|
|
86
|
-
error_count: Optional[int] = 0
|
|
87
|
-
feature_stats: Optional[dict] = {}
|
|
88
|
-
current_stats: Optional[dict] = {}
|
|
89
|
-
drift_measures: Optional[dict] = {}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
class ModelEndpointV2(BaseModel):
|
|
93
|
-
kind: ObjectKind = Field(ObjectKind.model_endpoint, const=True)
|
|
94
|
-
metadata: ModelEndpointV2Metadata
|
|
95
|
-
spec: ModelEndpointV2Spec
|
|
96
|
-
status: ModelEndpointV2Status
|
|
97
|
-
|
|
98
|
-
def flat_dict(self, exclude: Optional[set] = None):
|
|
99
|
-
"""Generate a flattened `ModelEndpoint` dictionary. The flattened dictionary result is important for storing
|
|
100
|
-
the model endpoint object in the database.
|
|
101
|
-
|
|
102
|
-
:return: Flattened `ModelEndpoint` dictionary.
|
|
103
|
-
"""
|
|
104
|
-
# Convert the ModelEndpoint object into a dictionary using BaseModel dict() function
|
|
105
|
-
# In addition, remove the BaseModel kind as it is not required by the DB schema
|
|
106
|
-
if exclude:
|
|
107
|
-
exclude = exclude | {"kind", "tag"}
|
|
108
|
-
else:
|
|
109
|
-
exclude = {"kind", "tag"}
|
|
110
|
-
model_endpoint_dictionary = self.dict(exclude=exclude)
|
|
111
|
-
|
|
112
|
-
# Initialize a flattened dictionary that will be filled with the model endpoint dictionary attributes
|
|
113
|
-
flatten_dict = {}
|
|
114
|
-
for k_object in model_endpoint_dictionary:
|
|
115
|
-
for key in model_endpoint_dictionary[k_object]:
|
|
116
|
-
# Extract the value of the current field
|
|
117
|
-
flatten_dict[key] = model_endpoint_dictionary[k_object][key]
|
|
118
|
-
|
|
119
|
-
return flatten_dict
|
|
120
|
-
|
|
121
|
-
@classmethod
|
|
122
|
-
def from_flat_dict(cls, endpoint_dict: dict) -> "ModelEndpointV2":
|
|
123
|
-
"""Create a `ModelEndpoint` object from an endpoint flattened dictionary. Because the provided dictionary
|
|
124
|
-
is flattened, we pass it as is to the subclasses without splitting the keys into spec, metadata, and status.
|
|
125
|
-
|
|
126
|
-
:param endpoint_dict: Model endpoint dictionary.
|
|
127
|
-
"""
|
|
128
|
-
|
|
129
|
-
return cls(
|
|
130
|
-
metadata=ModelEndpointV2Metadata.from_flat_dict(
|
|
131
|
-
endpoint_dict=endpoint_dict
|
|
132
|
-
),
|
|
133
|
-
spec=ModelEndpointV2Spec.from_flat_dict(endpoint_dict=endpoint_dict),
|
|
134
|
-
status=ModelEndpointV2Status.from_flat_dict(endpoint_dict=endpoint_dict),
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
@classmethod
|
|
138
|
-
def _operative_data(cls) -> set:
|
|
139
|
-
return {
|
|
140
|
-
"last_request",
|
|
141
|
-
"drift_status",
|
|
142
|
-
"avg_latency",
|
|
143
|
-
"error_count",
|
|
144
|
-
"feature_stats",
|
|
145
|
-
"current_stats",
|
|
146
|
-
"drift_measures",
|
|
147
|
-
"function_uri",
|
|
148
|
-
"model_uri",
|
|
149
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
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
|
-
|
|
15
|
-
import enum
|
|
16
|
-
import typing
|
|
17
|
-
import warnings
|
|
18
|
-
|
|
19
|
-
import mlrun.common.schemas.secret
|
|
20
|
-
import mlrun.errors
|
|
21
|
-
|
|
22
|
-
from .base import StoreBase
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class ObjectStoreFactory(enum.Enum):
|
|
26
|
-
"""Enum class to handle the different store type values for saving model monitoring records."""
|
|
27
|
-
|
|
28
|
-
v3io_nosql = "v3io-nosql"
|
|
29
|
-
SQL = "sql"
|
|
30
|
-
|
|
31
|
-
def to_object_store(
|
|
32
|
-
self,
|
|
33
|
-
project: str,
|
|
34
|
-
**kwargs,
|
|
35
|
-
) -> StoreBase:
|
|
36
|
-
"""
|
|
37
|
-
Return a StoreBase object based on the provided enum value.
|
|
38
|
-
|
|
39
|
-
:param project: The name of the project.
|
|
40
|
-
|
|
41
|
-
:return: `StoreBase` object.
|
|
42
|
-
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
if self == self.v3io_nosql:
|
|
46
|
-
from mlrun.model_monitoring.db.stores.v3io_kv.kv_store import KVStoreBase
|
|
47
|
-
|
|
48
|
-
return KVStoreBase(project=project)
|
|
49
|
-
|
|
50
|
-
# Assuming SQL store target if store type is not KV.
|
|
51
|
-
# Update these lines once there are more than two store target types.
|
|
52
|
-
|
|
53
|
-
from mlrun.model_monitoring.db.stores.sqldb.sql_store import SQLStoreBase
|
|
54
|
-
|
|
55
|
-
return SQLStoreBase(
|
|
56
|
-
project=project,
|
|
57
|
-
**kwargs,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
@classmethod
|
|
61
|
-
def _missing_(cls, value: typing.Any):
|
|
62
|
-
"""A lookup function to handle an invalid value.
|
|
63
|
-
:param value: Provided enum (invalid) value.
|
|
64
|
-
"""
|
|
65
|
-
valid_values = list(cls.__members__.keys())
|
|
66
|
-
raise mlrun.errors.MLRunInvalidMMStoreTypeError(
|
|
67
|
-
f"{value} is not a valid endpoint store, please choose a valid value: %{valid_values}."
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def get_model_endpoint_store(
|
|
72
|
-
project: str,
|
|
73
|
-
access_key: typing.Optional[str] = None,
|
|
74
|
-
secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
|
|
75
|
-
) -> StoreBase:
|
|
76
|
-
# Leaving here for backwards compatibility
|
|
77
|
-
warnings.warn(
|
|
78
|
-
"The 'get_model_endpoint_store' function is deprecated and will be removed in 1.9.0. "
|
|
79
|
-
"Please use `get_store_object` instead.",
|
|
80
|
-
# TODO: remove in 1.9.0
|
|
81
|
-
FutureWarning,
|
|
82
|
-
)
|
|
83
|
-
return get_store_object(
|
|
84
|
-
project=project, access_key=access_key, secret_provider=secret_provider
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def get_store_object(
|
|
89
|
-
project: str,
|
|
90
|
-
secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
|
|
91
|
-
store_connection_string: typing.Optional[str] = None,
|
|
92
|
-
**kwargs,
|
|
93
|
-
) -> StoreBase:
|
|
94
|
-
"""
|
|
95
|
-
Generate a store object. If a connection string is provided, the store type will be updated according to the
|
|
96
|
-
connection string. Currently, the supported store types are SQL and v3io-nosql.
|
|
97
|
-
|
|
98
|
-
:param project: The name of the project.
|
|
99
|
-
:param secret_provider: An optional secret provider to get the connection string secret.
|
|
100
|
-
:param store_connection_string: Optional explicit connection string of the store.
|
|
101
|
-
|
|
102
|
-
:return: `StoreBase` object. Using this object, the user can apply different operations such as write, update, get
|
|
103
|
-
and delete a model endpoint record.
|
|
104
|
-
:raise: `MLRunInvalidMMStoreTypeError` if the user didn't provide store connection
|
|
105
|
-
or the provided store connection is invalid.
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
store_connection_string = (
|
|
109
|
-
store_connection_string
|
|
110
|
-
or mlrun.model_monitoring.helpers.get_connection_string(
|
|
111
|
-
secret_provider=secret_provider
|
|
112
|
-
)
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
if store_connection_string and (
|
|
116
|
-
store_connection_string.startswith("mysql")
|
|
117
|
-
or store_connection_string.startswith("sqlite")
|
|
118
|
-
):
|
|
119
|
-
store_type = mlrun.common.schemas.model_monitoring.ModelEndpointTarget.SQL
|
|
120
|
-
kwargs["store_connection_string"] = store_connection_string
|
|
121
|
-
elif store_connection_string and store_connection_string == "v3io":
|
|
122
|
-
store_type = (
|
|
123
|
-
mlrun.common.schemas.model_monitoring.ModelEndpointTarget.V3IO_NOSQL
|
|
124
|
-
)
|
|
125
|
-
else:
|
|
126
|
-
raise mlrun.errors.MLRunInvalidMMStoreTypeError(
|
|
127
|
-
"You must provide a valid store connection by using "
|
|
128
|
-
"set_model_monitoring_credentials API."
|
|
129
|
-
)
|
|
130
|
-
# Get store type value from ObjectStoreFactory enum class
|
|
131
|
-
store_type_fact = ObjectStoreFactory(store_type)
|
|
132
|
-
|
|
133
|
-
# Convert into store target object
|
|
134
|
-
return store_type_fact.to_object_store(
|
|
135
|
-
project=project, secret_provider=secret_provider, **kwargs
|
|
136
|
-
)
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
|
|
15
|
-
from .store import StoreBase
|
|
@@ -1,154 +0,0 @@
|
|
|
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
|
-
|
|
15
|
-
import json
|
|
16
|
-
import typing
|
|
17
|
-
from abc import ABC, abstractmethod
|
|
18
|
-
|
|
19
|
-
import mlrun.common.schemas.model_monitoring as mm_schemas
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class StoreBase(ABC):
|
|
23
|
-
type: typing.ClassVar[str]
|
|
24
|
-
"""
|
|
25
|
-
An abstract class to handle the store object in the DB target.
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
def __init__(self, project: str):
|
|
29
|
-
"""
|
|
30
|
-
Initialize a new store target.
|
|
31
|
-
|
|
32
|
-
:param project: The name of the project.
|
|
33
|
-
"""
|
|
34
|
-
self.project = project
|
|
35
|
-
|
|
36
|
-
@abstractmethod
|
|
37
|
-
def write_model_endpoint(self, endpoint: dict[str, typing.Any]):
|
|
38
|
-
"""
|
|
39
|
-
Create a new endpoint record in the DB table.
|
|
40
|
-
|
|
41
|
-
:param endpoint: model endpoint dictionary that will be written into the DB.
|
|
42
|
-
"""
|
|
43
|
-
pass
|
|
44
|
-
|
|
45
|
-
@abstractmethod
|
|
46
|
-
def update_model_endpoint(
|
|
47
|
-
self, endpoint_id: str, attributes: dict[str, typing.Any]
|
|
48
|
-
):
|
|
49
|
-
"""
|
|
50
|
-
Update a model endpoint record with a given attributes.
|
|
51
|
-
|
|
52
|
-
:param endpoint_id: The unique id of the model endpoint.
|
|
53
|
-
:param attributes: Dictionary of attributes that will be used for update the model endpoint. Note that the keys
|
|
54
|
-
of the attributes dictionary should exist in the DB table.
|
|
55
|
-
|
|
56
|
-
"""
|
|
57
|
-
pass
|
|
58
|
-
|
|
59
|
-
@abstractmethod
|
|
60
|
-
def delete_model_endpoint(self, endpoint_id: str):
|
|
61
|
-
"""
|
|
62
|
-
Deletes the record of a given model endpoint id.
|
|
63
|
-
|
|
64
|
-
:param endpoint_id: The unique id of the model endpoint.
|
|
65
|
-
"""
|
|
66
|
-
pass
|
|
67
|
-
|
|
68
|
-
@abstractmethod
|
|
69
|
-
def delete_model_endpoints_resources(self):
|
|
70
|
-
"""
|
|
71
|
-
Delete all model endpoints resources.
|
|
72
|
-
|
|
73
|
-
"""
|
|
74
|
-
pass
|
|
75
|
-
|
|
76
|
-
@abstractmethod
|
|
77
|
-
def get_model_endpoint(
|
|
78
|
-
self,
|
|
79
|
-
endpoint_id: str,
|
|
80
|
-
) -> dict[str, typing.Any]:
|
|
81
|
-
"""
|
|
82
|
-
Get a single model endpoint record.
|
|
83
|
-
|
|
84
|
-
:param endpoint_id: The unique id of the model endpoint.
|
|
85
|
-
|
|
86
|
-
:return: A model endpoint record as a dictionary.
|
|
87
|
-
"""
|
|
88
|
-
pass
|
|
89
|
-
|
|
90
|
-
@abstractmethod
|
|
91
|
-
def list_model_endpoints(
|
|
92
|
-
self,
|
|
93
|
-
model: typing.Optional[str] = None,
|
|
94
|
-
function: typing.Optional[str] = None,
|
|
95
|
-
labels: typing.Optional[list[str]] = None,
|
|
96
|
-
top_level: typing.Optional[bool] = None,
|
|
97
|
-
uids: typing.Optional[list] = None,
|
|
98
|
-
include_stats: typing.Optional[bool] = None,
|
|
99
|
-
) -> list[dict[str, typing.Any]]:
|
|
100
|
-
"""
|
|
101
|
-
Returns a list of model endpoint dictionaries, supports filtering by model, function, labels or top level.
|
|
102
|
-
By default, when no filters are applied, all available model endpoints for the given project will
|
|
103
|
-
be listed.
|
|
104
|
-
|
|
105
|
-
:param model: The name of the model to filter by.
|
|
106
|
-
:param function: The name of the function to filter by.
|
|
107
|
-
:param labels: A list of labels to filter by. Label filters work by either filtering a specific value
|
|
108
|
-
of a label (i.e. list("key=value")) or by looking for the existence of a given
|
|
109
|
-
key (i.e. "key").
|
|
110
|
-
:param top_level: If True will return only routers and endpoint that are NOT children of any router.
|
|
111
|
-
:param uids: List of model endpoint unique ids to include in the result.
|
|
112
|
-
:param include_stats: If True, will include model endpoint statistics in the result.
|
|
113
|
-
|
|
114
|
-
:return: A list of model endpoint dictionaries.
|
|
115
|
-
"""
|
|
116
|
-
pass
|
|
117
|
-
|
|
118
|
-
@staticmethod
|
|
119
|
-
def _validate_labels(
|
|
120
|
-
endpoint_dict: dict,
|
|
121
|
-
labels: list,
|
|
122
|
-
) -> bool:
|
|
123
|
-
"""Validate that the model endpoint dictionary has the provided labels. There are 2 possible cases:
|
|
124
|
-
1 - Labels were provided as a list of key-values pairs (e.g. ['label_1=value_1', 'label_2=value_2']): Validate
|
|
125
|
-
that each pair exist in the endpoint dictionary.
|
|
126
|
-
2 - Labels were provided as a list of key labels (e.g. ['label_1', 'label_2']): Validate that each key exist in
|
|
127
|
-
the endpoint labels dictionary.
|
|
128
|
-
|
|
129
|
-
:param endpoint_dict: Dictionary of the model endpoint records.
|
|
130
|
-
:param labels: List of dictionary of required labels.
|
|
131
|
-
|
|
132
|
-
:return: True if the labels exist in the endpoint labels dictionary, otherwise False.
|
|
133
|
-
"""
|
|
134
|
-
|
|
135
|
-
# Convert endpoint labels into dictionary
|
|
136
|
-
endpoint_labels = json.loads(
|
|
137
|
-
endpoint_dict.get(mm_schemas.EventFieldType.LABELS)
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
for label in labels:
|
|
141
|
-
# Case 1 - label is a key=value pair
|
|
142
|
-
if "=" in label:
|
|
143
|
-
lbl, value = list(map(lambda x: x.strip(), label.split("=")))
|
|
144
|
-
if lbl not in endpoint_labels or str(endpoint_labels[lbl]) != value:
|
|
145
|
-
return False
|
|
146
|
-
# Case 2 - label is just a key
|
|
147
|
-
else:
|
|
148
|
-
if label not in endpoint_labels:
|
|
149
|
-
return False
|
|
150
|
-
|
|
151
|
-
return True
|
|
152
|
-
|
|
153
|
-
def create_tables(self):
|
|
154
|
-
pass
|
|
@@ -1,13 +0,0 @@
|
|
|
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.
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# Copyright 2023 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from functools import partial
|
|
16
|
-
from typing import Optional, TypeVar, Union
|
|
17
|
-
|
|
18
|
-
from .mysql import ModelEndpointsTable as MySQLModelEndpointsTable
|
|
19
|
-
from .sqlite import ModelEndpointsTable as SQLiteModelEndpointsTable
|
|
20
|
-
|
|
21
|
-
MySQLTableType = TypeVar("MySQLTableType")
|
|
22
|
-
SQLiteTableType = TypeVar("SQLiteTableType")
|
|
23
|
-
|
|
24
|
-
_MYSQL_SCHEME = "mysql:"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def _get_sql_table(
|
|
28
|
-
*,
|
|
29
|
-
mysql_table: MySQLTableType,
|
|
30
|
-
sqlite_table: SQLiteTableType,
|
|
31
|
-
connection_string: Optional[str] = None,
|
|
32
|
-
) -> Union[MySQLTableType, SQLiteTableType]:
|
|
33
|
-
"""
|
|
34
|
-
Return a SQLAlchemy table for MySQL or SQLite according to the connection string.
|
|
35
|
-
Note: this function should not be directly used in other modules.
|
|
36
|
-
"""
|
|
37
|
-
if connection_string and _MYSQL_SCHEME in connection_string:
|
|
38
|
-
return mysql_table
|
|
39
|
-
return sqlite_table
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
_get_model_endpoints_table = partial(
|
|
43
|
-
_get_sql_table,
|
|
44
|
-
mysql_table=MySQLModelEndpointsTable,
|
|
45
|
-
sqlite_table=SQLiteModelEndpointsTable,
|
|
46
|
-
)
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Copyright 2023 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from sqlalchemy import (
|
|
16
|
-
TIMESTAMP, # TODO: migrate to DATETIME, see ML-6921
|
|
17
|
-
Boolean,
|
|
18
|
-
Column,
|
|
19
|
-
Integer,
|
|
20
|
-
String,
|
|
21
|
-
Text,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
from mlrun.common.schemas.model_monitoring import (
|
|
25
|
-
EventFieldType,
|
|
26
|
-
)
|
|
27
|
-
from mlrun.utils.db import BaseModel
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class ModelEndpointsBaseTable(BaseModel):
|
|
31
|
-
__tablename__ = EventFieldType.MODEL_ENDPOINTS
|
|
32
|
-
|
|
33
|
-
uid = Column(
|
|
34
|
-
EventFieldType.UID,
|
|
35
|
-
String(40),
|
|
36
|
-
primary_key=True,
|
|
37
|
-
)
|
|
38
|
-
state = Column(EventFieldType.STATE, String(10))
|
|
39
|
-
project = Column(EventFieldType.PROJECT, String(40))
|
|
40
|
-
function_uri = Column(
|
|
41
|
-
EventFieldType.FUNCTION_URI,
|
|
42
|
-
String(255),
|
|
43
|
-
)
|
|
44
|
-
model = Column(EventFieldType.MODEL, String(255))
|
|
45
|
-
model_class = Column(
|
|
46
|
-
EventFieldType.MODEL_CLASS,
|
|
47
|
-
String(255),
|
|
48
|
-
)
|
|
49
|
-
labels = Column(EventFieldType.LABELS, Text)
|
|
50
|
-
model_uri = Column(EventFieldType.MODEL_URI, String(255))
|
|
51
|
-
stream_path = Column(EventFieldType.STREAM_PATH, Text)
|
|
52
|
-
algorithm = Column(
|
|
53
|
-
EventFieldType.ALGORITHM,
|
|
54
|
-
String(255),
|
|
55
|
-
)
|
|
56
|
-
active = Column(EventFieldType.ACTIVE, Boolean)
|
|
57
|
-
monitoring_mode = Column(
|
|
58
|
-
EventFieldType.MONITORING_MODE,
|
|
59
|
-
String(10),
|
|
60
|
-
)
|
|
61
|
-
feature_stats = Column(EventFieldType.FEATURE_STATS, Text)
|
|
62
|
-
current_stats = Column(EventFieldType.CURRENT_STATS, Text)
|
|
63
|
-
feature_names = Column(EventFieldType.FEATURE_NAMES, Text)
|
|
64
|
-
children = Column(EventFieldType.CHILDREN, Text)
|
|
65
|
-
label_names = Column(EventFieldType.LABEL_NAMES, Text)
|
|
66
|
-
endpoint_type = Column(
|
|
67
|
-
EventFieldType.ENDPOINT_TYPE,
|
|
68
|
-
String(10),
|
|
69
|
-
)
|
|
70
|
-
children_uids = Column(EventFieldType.CHILDREN_UIDS, Text)
|
|
71
|
-
drift_measures = Column(EventFieldType.DRIFT_MEASURES, Text)
|
|
72
|
-
drift_status = Column(
|
|
73
|
-
EventFieldType.DRIFT_STATUS,
|
|
74
|
-
String(40),
|
|
75
|
-
)
|
|
76
|
-
monitor_configuration = Column(
|
|
77
|
-
EventFieldType.MONITOR_CONFIGURATION,
|
|
78
|
-
Text,
|
|
79
|
-
)
|
|
80
|
-
monitoring_feature_set_uri = Column(
|
|
81
|
-
EventFieldType.FEATURE_SET_URI,
|
|
82
|
-
String(255),
|
|
83
|
-
)
|
|
84
|
-
error_count = Column(EventFieldType.ERROR_COUNT, Integer)
|
|
85
|
-
metrics = Column(EventFieldType.METRICS, Text)
|
|
86
|
-
first_request = Column(
|
|
87
|
-
EventFieldType.FIRST_REQUEST,
|
|
88
|
-
TIMESTAMP(timezone=True), # TODO: migrate to DATETIME, see ML-6921
|
|
89
|
-
)
|
|
90
|
-
last_request = Column(
|
|
91
|
-
EventFieldType.LAST_REQUEST,
|
|
92
|
-
TIMESTAMP(timezone=True), # TODO: migrate to DATETIME, see ML-6921
|
|
93
|
-
)
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# Copyright 2023 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
import sqlalchemy.dialects.mysql
|
|
16
|
-
from sqlalchemy import Column
|
|
17
|
-
from sqlalchemy.ext.declarative import declarative_base
|
|
18
|
-
|
|
19
|
-
from mlrun.common.schemas.model_monitoring import (
|
|
20
|
-
EventFieldType,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
from .base import (
|
|
24
|
-
ModelEndpointsBaseTable,
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
Base = declarative_base()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class ModelEndpointsTable(Base, ModelEndpointsBaseTable):
|
|
31
|
-
feature_stats = Column(
|
|
32
|
-
EventFieldType.FEATURE_STATS, sqlalchemy.dialects.mysql.MEDIUMTEXT
|
|
33
|
-
)
|
|
34
|
-
current_stats = Column(
|
|
35
|
-
EventFieldType.CURRENT_STATS, sqlalchemy.dialects.mysql.MEDIUMTEXT
|
|
36
|
-
)
|
|
37
|
-
metrics = Column(EventFieldType.METRICS, sqlalchemy.dialects.mysql.MEDIUMTEXT)
|
|
38
|
-
first_request = Column(
|
|
39
|
-
EventFieldType.FIRST_REQUEST,
|
|
40
|
-
# TODO: migrate to DATETIME, see ML-6921
|
|
41
|
-
sqlalchemy.dialects.mysql.TIMESTAMP(fsp=3, timezone=True),
|
|
42
|
-
)
|
|
43
|
-
last_request = Column(
|
|
44
|
-
EventFieldType.LAST_REQUEST,
|
|
45
|
-
# TODO: migrate to DATETIME, see ML-6921
|
|
46
|
-
sqlalchemy.dialects.mysql.TIMESTAMP(fsp=3, timezone=True),
|
|
47
|
-
)
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Copyright 2023 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from sqlalchemy.ext.declarative import declarative_base
|
|
16
|
-
|
|
17
|
-
from .base import (
|
|
18
|
-
ModelEndpointsBaseTable,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
Base = declarative_base()
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class ModelEndpointsTable(Base, ModelEndpointsBaseTable):
|
|
25
|
-
pass
|