mlrun 1.4.0rc25__py3-none-any.whl → 1.5.0rc2__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 +2 -35
- mlrun/__main__.py +3 -41
- mlrun/api/api/api.py +6 -0
- mlrun/api/api/endpoints/feature_store.py +0 -4
- mlrun/api/api/endpoints/files.py +14 -2
- mlrun/api/api/endpoints/frontend_spec.py +2 -1
- mlrun/api/api/endpoints/functions.py +95 -59
- mlrun/api/api/endpoints/grafana_proxy.py +9 -9
- mlrun/api/api/endpoints/logs.py +17 -3
- mlrun/api/api/endpoints/model_endpoints.py +3 -2
- mlrun/api/api/endpoints/pipelines.py +1 -5
- mlrun/api/api/endpoints/projects.py +88 -0
- mlrun/api/api/endpoints/runs.py +48 -6
- mlrun/api/api/endpoints/submit.py +2 -1
- mlrun/api/api/endpoints/workflows.py +355 -0
- mlrun/api/api/utils.py +3 -4
- mlrun/api/crud/__init__.py +1 -0
- mlrun/api/crud/client_spec.py +6 -2
- mlrun/api/crud/feature_store.py +5 -0
- mlrun/api/crud/model_monitoring/__init__.py +1 -0
- mlrun/api/crud/model_monitoring/deployment.py +497 -0
- mlrun/api/crud/model_monitoring/grafana.py +96 -42
- mlrun/api/crud/model_monitoring/helpers.py +159 -0
- mlrun/api/crud/model_monitoring/model_endpoints.py +202 -476
- mlrun/api/crud/notifications.py +9 -4
- mlrun/api/crud/pipelines.py +6 -11
- mlrun/api/crud/projects.py +2 -2
- mlrun/api/crud/runtime_resources.py +4 -3
- mlrun/api/crud/runtimes/nuclio/helpers.py +5 -1
- mlrun/api/crud/secrets.py +21 -0
- mlrun/api/crud/workflows.py +352 -0
- mlrun/api/db/base.py +16 -1
- mlrun/api/db/init_db.py +2 -4
- mlrun/api/db/session.py +1 -1
- mlrun/api/db/sqldb/db.py +129 -31
- mlrun/api/db/sqldb/models/models_mysql.py +15 -1
- mlrun/api/db/sqldb/models/models_sqlite.py +16 -2
- mlrun/api/launcher.py +38 -6
- mlrun/api/main.py +3 -2
- mlrun/api/rundb/__init__.py +13 -0
- mlrun/{db → api/rundb}/sqldb.py +36 -84
- mlrun/api/runtime_handlers/__init__.py +56 -0
- mlrun/api/runtime_handlers/base.py +1247 -0
- mlrun/api/runtime_handlers/daskjob.py +209 -0
- mlrun/api/runtime_handlers/kubejob.py +37 -0
- mlrun/api/runtime_handlers/mpijob.py +147 -0
- mlrun/api/runtime_handlers/remotesparkjob.py +29 -0
- mlrun/api/runtime_handlers/sparkjob.py +148 -0
- mlrun/api/schemas/__init__.py +17 -6
- mlrun/api/utils/builder.py +1 -4
- mlrun/api/utils/clients/chief.py +14 -0
- mlrun/api/utils/clients/iguazio.py +33 -33
- mlrun/api/utils/clients/nuclio.py +2 -2
- mlrun/api/utils/periodic.py +9 -2
- mlrun/api/utils/projects/follower.py +14 -7
- mlrun/api/utils/projects/leader.py +2 -1
- mlrun/api/utils/projects/remotes/nop_follower.py +2 -2
- mlrun/api/utils/projects/remotes/nop_leader.py +2 -2
- mlrun/api/utils/runtimes/__init__.py +14 -0
- mlrun/api/utils/runtimes/nuclio.py +43 -0
- mlrun/api/utils/scheduler.py +98 -15
- mlrun/api/utils/singletons/db.py +5 -1
- mlrun/api/utils/singletons/project_member.py +4 -1
- mlrun/api/utils/singletons/scheduler.py +1 -1
- mlrun/artifacts/base.py +6 -6
- mlrun/artifacts/dataset.py +4 -4
- mlrun/artifacts/manager.py +2 -3
- mlrun/artifacts/model.py +2 -2
- mlrun/artifacts/plots.py +8 -8
- mlrun/common/db/__init__.py +14 -0
- mlrun/common/helpers.py +37 -0
- mlrun/{mlutils → common/model_monitoring}/__init__.py +3 -2
- mlrun/common/model_monitoring/helpers.py +69 -0
- mlrun/common/schemas/__init__.py +13 -1
- mlrun/common/schemas/auth.py +4 -1
- mlrun/common/schemas/client_spec.py +1 -1
- mlrun/common/schemas/function.py +17 -0
- mlrun/common/schemas/model_monitoring/__init__.py +48 -0
- mlrun/common/{model_monitoring.py → schemas/model_monitoring/constants.py} +11 -23
- mlrun/common/schemas/model_monitoring/grafana.py +55 -0
- mlrun/common/schemas/{model_endpoints.py → model_monitoring/model_endpoints.py} +32 -65
- mlrun/common/schemas/notification.py +1 -0
- mlrun/common/schemas/object.py +4 -0
- mlrun/common/schemas/project.py +1 -0
- mlrun/common/schemas/regex.py +1 -1
- mlrun/common/schemas/runs.py +1 -8
- mlrun/common/schemas/schedule.py +1 -8
- mlrun/common/schemas/workflow.py +54 -0
- mlrun/config.py +45 -42
- mlrun/datastore/__init__.py +21 -0
- mlrun/datastore/base.py +1 -1
- mlrun/datastore/datastore.py +9 -0
- mlrun/datastore/dbfs_store.py +168 -0
- mlrun/datastore/helpers.py +18 -0
- mlrun/datastore/sources.py +1 -0
- mlrun/datastore/store_resources.py +2 -5
- mlrun/datastore/v3io.py +1 -2
- mlrun/db/__init__.py +4 -68
- mlrun/db/base.py +12 -0
- mlrun/db/factory.py +65 -0
- mlrun/db/httpdb.py +175 -20
- mlrun/db/nopdb.py +4 -2
- mlrun/execution.py +4 -2
- mlrun/feature_store/__init__.py +1 -0
- mlrun/feature_store/api.py +1 -2
- mlrun/feature_store/common.py +2 -1
- mlrun/feature_store/feature_set.py +1 -11
- mlrun/feature_store/feature_vector.py +340 -2
- mlrun/feature_store/ingestion.py +5 -10
- mlrun/feature_store/retrieval/base.py +118 -104
- mlrun/feature_store/retrieval/dask_merger.py +17 -10
- mlrun/feature_store/retrieval/job.py +4 -1
- mlrun/feature_store/retrieval/local_merger.py +18 -18
- mlrun/feature_store/retrieval/spark_merger.py +21 -14
- mlrun/feature_store/retrieval/storey_merger.py +22 -16
- mlrun/kfpops.py +3 -9
- mlrun/launcher/base.py +57 -53
- mlrun/launcher/client.py +5 -4
- mlrun/launcher/factory.py +24 -13
- mlrun/launcher/local.py +6 -6
- mlrun/launcher/remote.py +4 -4
- mlrun/lists.py +0 -11
- mlrun/model.py +11 -17
- mlrun/model_monitoring/__init__.py +2 -22
- mlrun/model_monitoring/features_drift_table.py +1 -1
- mlrun/model_monitoring/helpers.py +22 -210
- mlrun/model_monitoring/model_endpoint.py +1 -1
- mlrun/model_monitoring/model_monitoring_batch.py +127 -50
- mlrun/model_monitoring/prometheus.py +219 -0
- mlrun/model_monitoring/stores/__init__.py +16 -11
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +95 -23
- mlrun/model_monitoring/stores/models/mysql.py +47 -29
- mlrun/model_monitoring/stores/models/sqlite.py +47 -29
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +31 -19
- mlrun/model_monitoring/{stream_processing_fs.py → stream_processing.py} +206 -64
- mlrun/model_monitoring/tracking_policy.py +104 -0
- mlrun/package/packager.py +6 -8
- mlrun/package/packagers/default_packager.py +121 -10
- mlrun/package/packagers/numpy_packagers.py +1 -1
- mlrun/platforms/__init__.py +0 -2
- mlrun/platforms/iguazio.py +0 -56
- mlrun/projects/pipelines.py +53 -159
- mlrun/projects/project.py +10 -37
- mlrun/render.py +1 -1
- mlrun/run.py +8 -124
- mlrun/runtimes/__init__.py +6 -42
- mlrun/runtimes/base.py +29 -1249
- mlrun/runtimes/daskjob.py +2 -198
- mlrun/runtimes/funcdoc.py +0 -9
- mlrun/runtimes/function.py +25 -29
- mlrun/runtimes/kubejob.py +5 -29
- mlrun/runtimes/local.py +1 -1
- mlrun/runtimes/mpijob/__init__.py +2 -2
- mlrun/runtimes/mpijob/abstract.py +10 -1
- mlrun/runtimes/mpijob/v1.py +0 -76
- mlrun/runtimes/mpijob/v1alpha1.py +1 -74
- mlrun/runtimes/nuclio.py +3 -2
- mlrun/runtimes/pod.py +28 -18
- mlrun/runtimes/remotesparkjob.py +1 -15
- mlrun/runtimes/serving.py +14 -6
- mlrun/runtimes/sparkjob/__init__.py +0 -1
- mlrun/runtimes/sparkjob/abstract.py +4 -131
- mlrun/runtimes/utils.py +0 -26
- mlrun/serving/routers.py +7 -7
- mlrun/serving/server.py +11 -8
- mlrun/serving/states.py +7 -1
- mlrun/serving/v2_serving.py +6 -6
- mlrun/utils/helpers.py +23 -42
- mlrun/utils/notifications/notification/__init__.py +4 -0
- mlrun/utils/notifications/notification/webhook.py +61 -0
- mlrun/utils/notifications/notification_pusher.py +5 -25
- mlrun/utils/regex.py +7 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/METADATA +26 -25
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/RECORD +180 -158
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/WHEEL +1 -1
- mlrun/mlutils/data.py +0 -160
- mlrun/mlutils/models.py +0 -78
- mlrun/mlutils/plots.py +0 -902
- mlrun/utils/model_monitoring.py +0 -249
- /mlrun/{api/db/sqldb/session.py → common/db/sql_session.py} +0 -0
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/LICENSE +0 -0
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.4.0rc25.dist-info → mlrun-1.5.0rc2.dist-info}/top_level.txt +0 -0
mlrun/api/db/sqldb/db.py
CHANGED
|
@@ -82,7 +82,6 @@ from mlrun.utils import (
|
|
|
82
82
|
)
|
|
83
83
|
|
|
84
84
|
NULL = None # Avoid flake8 issuing warnings when comparing in filter
|
|
85
|
-
run_time_fmt = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
86
85
|
unversioned_tagged_object_uid_prefix = "unversioned-"
|
|
87
86
|
|
|
88
87
|
conflict_messages = [
|
|
@@ -1175,6 +1174,63 @@ class SQLDB(DBInterface):
|
|
|
1175
1174
|
|
|
1176
1175
|
return results
|
|
1177
1176
|
|
|
1177
|
+
def store_schedule(
|
|
1178
|
+
self,
|
|
1179
|
+
session: Session,
|
|
1180
|
+
project: str,
|
|
1181
|
+
name: str,
|
|
1182
|
+
kind: mlrun.common.schemas.ScheduleKinds = None,
|
|
1183
|
+
scheduled_object: Any = None,
|
|
1184
|
+
cron_trigger: mlrun.common.schemas.ScheduleCronTrigger = None,
|
|
1185
|
+
labels: Dict = None,
|
|
1186
|
+
last_run_uri: str = None,
|
|
1187
|
+
concurrency_limit: int = None,
|
|
1188
|
+
next_run_time: datetime = None,
|
|
1189
|
+
) -> typing.Optional[mlrun.common.schemas.ScheduleRecord]:
|
|
1190
|
+
schedule = self.get_schedule(
|
|
1191
|
+
session=session, project=project, name=name, raise_on_not_found=False
|
|
1192
|
+
)
|
|
1193
|
+
schedule_exist = schedule is not None
|
|
1194
|
+
|
|
1195
|
+
if not schedule_exist:
|
|
1196
|
+
schedule = Schedule(
|
|
1197
|
+
project=project,
|
|
1198
|
+
name=name,
|
|
1199
|
+
kind=kind.value,
|
|
1200
|
+
creation_time=datetime.now(timezone.utc),
|
|
1201
|
+
concurrency_limit=concurrency_limit,
|
|
1202
|
+
next_run_time=next_run_time,
|
|
1203
|
+
scheduled_object=scheduled_object,
|
|
1204
|
+
cron_trigger=cron_trigger,
|
|
1205
|
+
)
|
|
1206
|
+
labels = labels or {}
|
|
1207
|
+
|
|
1208
|
+
self._update_schedule_body(
|
|
1209
|
+
schedule=schedule,
|
|
1210
|
+
scheduled_object=scheduled_object,
|
|
1211
|
+
cron_trigger=cron_trigger,
|
|
1212
|
+
labels=labels,
|
|
1213
|
+
last_run_uri=last_run_uri,
|
|
1214
|
+
concurrency_limit=concurrency_limit,
|
|
1215
|
+
next_run_time=next_run_time,
|
|
1216
|
+
)
|
|
1217
|
+
|
|
1218
|
+
logger.debug(
|
|
1219
|
+
"Storing schedule to db",
|
|
1220
|
+
project=project,
|
|
1221
|
+
name=name,
|
|
1222
|
+
kind=kind,
|
|
1223
|
+
cron_trigger=cron_trigger,
|
|
1224
|
+
labels=labels,
|
|
1225
|
+
concurrency_limit=concurrency_limit,
|
|
1226
|
+
scheduled_object=scheduled_object,
|
|
1227
|
+
)
|
|
1228
|
+
|
|
1229
|
+
self._upsert(session, [schedule])
|
|
1230
|
+
|
|
1231
|
+
if schedule_exist:
|
|
1232
|
+
return schedule
|
|
1233
|
+
|
|
1178
1234
|
def create_schedule(
|
|
1179
1235
|
self,
|
|
1180
1236
|
session: Session,
|
|
@@ -1233,6 +1289,37 @@ class SQLDB(DBInterface):
|
|
|
1233
1289
|
):
|
|
1234
1290
|
schedule = self._get_schedule_record(session, project, name)
|
|
1235
1291
|
|
|
1292
|
+
self._update_schedule_body(
|
|
1293
|
+
schedule=schedule,
|
|
1294
|
+
scheduled_object=scheduled_object,
|
|
1295
|
+
cron_trigger=cron_trigger,
|
|
1296
|
+
labels=labels,
|
|
1297
|
+
last_run_uri=last_run_uri,
|
|
1298
|
+
concurrency_limit=concurrency_limit,
|
|
1299
|
+
next_run_time=next_run_time,
|
|
1300
|
+
)
|
|
1301
|
+
|
|
1302
|
+
logger.debug(
|
|
1303
|
+
"Updating schedule in db",
|
|
1304
|
+
project=project,
|
|
1305
|
+
name=name,
|
|
1306
|
+
cron_trigger=cron_trigger,
|
|
1307
|
+
labels=labels,
|
|
1308
|
+
concurrency_limit=concurrency_limit,
|
|
1309
|
+
next_run_time=next_run_time,
|
|
1310
|
+
)
|
|
1311
|
+
self._upsert(session, [schedule])
|
|
1312
|
+
|
|
1313
|
+
@staticmethod
|
|
1314
|
+
def _update_schedule_body(
|
|
1315
|
+
schedule: mlrun.common.schemas.ScheduleRecord,
|
|
1316
|
+
scheduled_object: Any = None,
|
|
1317
|
+
cron_trigger: mlrun.common.schemas.ScheduleCronTrigger = None,
|
|
1318
|
+
labels: Dict = None,
|
|
1319
|
+
last_run_uri: str = None,
|
|
1320
|
+
concurrency_limit: int = None,
|
|
1321
|
+
next_run_time: datetime = None,
|
|
1322
|
+
):
|
|
1236
1323
|
# explicitly ensure the updated fields are not None, as they can be empty strings/dictionaries etc.
|
|
1237
1324
|
if scheduled_object is not None:
|
|
1238
1325
|
schedule.scheduled_object = scheduled_object
|
|
@@ -1254,17 +1341,6 @@ class SQLDB(DBInterface):
|
|
|
1254
1341
|
# saved in the DB in UTC timezone, therefore we transform next_run_time to UTC as well.
|
|
1255
1342
|
schedule.next_run_time = next_run_time.astimezone(pytz.utc)
|
|
1256
1343
|
|
|
1257
|
-
logger.debug(
|
|
1258
|
-
"Updating schedule in db",
|
|
1259
|
-
project=project,
|
|
1260
|
-
name=name,
|
|
1261
|
-
cron_trigger=cron_trigger,
|
|
1262
|
-
labels=labels,
|
|
1263
|
-
concurrency_limit=concurrency_limit,
|
|
1264
|
-
next_run_time=next_run_time,
|
|
1265
|
-
)
|
|
1266
|
-
self._upsert(session, [schedule])
|
|
1267
|
-
|
|
1268
1344
|
def list_schedules(
|
|
1269
1345
|
self,
|
|
1270
1346
|
session: Session,
|
|
@@ -1287,19 +1363,23 @@ class SQLDB(DBInterface):
|
|
|
1287
1363
|
return schedules
|
|
1288
1364
|
|
|
1289
1365
|
def get_schedule(
|
|
1290
|
-
self, session: Session, project: str, name: str
|
|
1291
|
-
) -> mlrun.common.schemas.ScheduleRecord:
|
|
1366
|
+
self, session: Session, project: str, name: str, raise_on_not_found: bool = True
|
|
1367
|
+
) -> typing.Optional[mlrun.common.schemas.ScheduleRecord]:
|
|
1292
1368
|
logger.debug("Getting schedule from db", project=project, name=name)
|
|
1293
|
-
schedule_record = self._get_schedule_record(
|
|
1369
|
+
schedule_record = self._get_schedule_record(
|
|
1370
|
+
session, project, name, raise_on_not_found
|
|
1371
|
+
)
|
|
1372
|
+
if not schedule_record:
|
|
1373
|
+
return
|
|
1294
1374
|
schedule = self._transform_schedule_record_to_scheme(schedule_record)
|
|
1295
1375
|
return schedule
|
|
1296
1376
|
|
|
1297
1377
|
def _get_schedule_record(
|
|
1298
|
-
self, session: Session, project: str, name: str
|
|
1378
|
+
self, session: Session, project: str, name: str, raise_on_not_found: bool = True
|
|
1299
1379
|
) -> mlrun.common.schemas.ScheduleRecord:
|
|
1300
1380
|
query = self._query(session, Schedule, project=project, name=name)
|
|
1301
1381
|
schedule_record = query.one_or_none()
|
|
1302
|
-
if not schedule_record:
|
|
1382
|
+
if not schedule_record and raise_on_not_found:
|
|
1303
1383
|
raise mlrun.errors.MLRunNotFoundError(
|
|
1304
1384
|
f"Schedule not found: project={project}, name={name}"
|
|
1305
1385
|
)
|
|
@@ -2866,32 +2946,50 @@ class SQLDB(DBInterface):
|
|
|
2866
2946
|
def _try_commit_obj():
|
|
2867
2947
|
try:
|
|
2868
2948
|
session.commit()
|
|
2869
|
-
except SQLAlchemyError as
|
|
2949
|
+
except SQLAlchemyError as sql_err:
|
|
2870
2950
|
session.rollback()
|
|
2871
|
-
|
|
2872
|
-
|
|
2951
|
+
classes = list(set([object_.__class__.__name__ for object_ in objects]))
|
|
2952
|
+
|
|
2953
|
+
# if the database is locked, we raise a retryable error
|
|
2954
|
+
if "database is locked" in str(sql_err):
|
|
2873
2955
|
logger.warning(
|
|
2874
|
-
"Database is locked. Retrying",
|
|
2956
|
+
"Database is locked. Retrying",
|
|
2957
|
+
classes_to_commit=classes,
|
|
2958
|
+
err=str(sql_err),
|
|
2875
2959
|
)
|
|
2876
2960
|
raise mlrun.errors.MLRunRuntimeError(
|
|
2877
2961
|
"Failed committing changes, database is locked"
|
|
2878
|
-
) from
|
|
2962
|
+
) from sql_err
|
|
2963
|
+
|
|
2964
|
+
# the error is not retryable, so we try to identify weather there was a conflict or not
|
|
2965
|
+
# either way - we wrap the error with a fatal error so the retry mechanism will stop
|
|
2879
2966
|
logger.warning(
|
|
2880
|
-
"Failed committing changes to DB",
|
|
2967
|
+
"Failed committing changes to DB",
|
|
2968
|
+
classes=classes,
|
|
2969
|
+
err=err_to_str(sql_err),
|
|
2881
2970
|
)
|
|
2882
2971
|
if not ignore:
|
|
2972
|
+
# get the identifiers of the objects that failed to commit, for logging purposes
|
|
2883
2973
|
identifiers = ",".join(
|
|
2884
2974
|
object_.get_identifier_string() for object_ in objects
|
|
2885
2975
|
)
|
|
2886
|
-
|
|
2976
|
+
|
|
2977
|
+
mlrun_error = mlrun.errors.MLRunRuntimeError(
|
|
2978
|
+
f"Failed committing changes to DB. classes={classes} objects={identifiers}"
|
|
2979
|
+
)
|
|
2980
|
+
|
|
2981
|
+
# check if the error is a conflict error
|
|
2982
|
+
if any([message in str(sql_err) for message in conflict_messages]):
|
|
2983
|
+
mlrun_error = mlrun.errors.MLRunConflictError(
|
|
2984
|
+
f"Conflict - at least one of the objects already exists: {identifiers}"
|
|
2985
|
+
)
|
|
2986
|
+
|
|
2987
|
+
# we want to keep the exception stack trace, but we also want the retry mechanism to stop
|
|
2988
|
+
# so, we raise a new indicative exception from the original sql exception (this keeps
|
|
2989
|
+
# the stack trace intact), and then wrap it with a fatal error (which stops the retry mechanism).
|
|
2990
|
+
# Note - this way, the exception is raised from this code section, and not from the retry function.
|
|
2887
2991
|
try:
|
|
2888
|
-
|
|
2889
|
-
raise mlrun.errors.MLRunConflictError(
|
|
2890
|
-
f"Conflict - {cls} already exists: {identifiers}"
|
|
2891
|
-
) from err
|
|
2892
|
-
raise mlrun.errors.MLRunRuntimeError(
|
|
2893
|
-
f"Failed committing changes to DB. class={cls} objects={identifiers}"
|
|
2894
|
-
) from err
|
|
2992
|
+
raise mlrun_error from sql_err
|
|
2895
2993
|
except (
|
|
2896
2994
|
mlrun.errors.MLRunRuntimeError,
|
|
2897
2995
|
mlrun.errors.MLRunConflictError,
|
|
@@ -38,7 +38,6 @@ from mlrun.api.utils.db.sql_collation import SQLCollationUtil
|
|
|
38
38
|
|
|
39
39
|
Base = declarative_base()
|
|
40
40
|
NULL = None # Avoid flake8 issuing warnings when comparing in filter
|
|
41
|
-
run_time_fmt = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
42
41
|
|
|
43
42
|
|
|
44
43
|
def make_label(table):
|
|
@@ -53,6 +52,9 @@ def make_label(table):
|
|
|
53
52
|
value = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
54
53
|
parent = Column(Integer, ForeignKey(f"{table}.id"))
|
|
55
54
|
|
|
55
|
+
def get_identifier_string(self) -> str:
|
|
56
|
+
return f"{self.parent}/{self.name}/{self.value}"
|
|
57
|
+
|
|
56
58
|
return Label
|
|
57
59
|
|
|
58
60
|
|
|
@@ -86,6 +88,9 @@ def make_tag_v2(table):
|
|
|
86
88
|
obj_id = Column(Integer, ForeignKey(f"{table}.id"))
|
|
87
89
|
obj_name = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
88
90
|
|
|
91
|
+
def get_identifier_string(self) -> str:
|
|
92
|
+
return f"{self.project}/{self.name}"
|
|
93
|
+
|
|
89
94
|
return Tag
|
|
90
95
|
|
|
91
96
|
|
|
@@ -258,6 +263,9 @@ with warnings.catch_warnings():
|
|
|
258
263
|
state = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
259
264
|
timeout = Column(Integer)
|
|
260
265
|
|
|
266
|
+
def get_identifier_string(self) -> str:
|
|
267
|
+
return f"{self.project}/{self.name}"
|
|
268
|
+
|
|
261
269
|
class Schedule(Base, mlrun.utils.db.BaseModel):
|
|
262
270
|
__tablename__ = "schedules_v2"
|
|
263
271
|
__table_args__ = (UniqueConstraint("project", "name", name="_schedules_v2_uc"),)
|
|
@@ -317,6 +325,9 @@ with warnings.catch_warnings():
|
|
|
317
325
|
id = Column(Integer, primary_key=True)
|
|
318
326
|
name = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
319
327
|
|
|
328
|
+
def get_identifier_string(self) -> str:
|
|
329
|
+
return f"{self.name}"
|
|
330
|
+
|
|
320
331
|
class Project(Base, mlrun.utils.db.BaseModel):
|
|
321
332
|
__tablename__ = "projects"
|
|
322
333
|
# For now since we use project name a lot
|
|
@@ -508,6 +519,9 @@ with warnings.catch_warnings():
|
|
|
508
519
|
default=datetime.now(timezone.utc),
|
|
509
520
|
)
|
|
510
521
|
|
|
522
|
+
def get_identifier_string(self) -> str:
|
|
523
|
+
return f"{self.version}"
|
|
524
|
+
|
|
511
525
|
|
|
512
526
|
# Must be after all table definitions
|
|
513
527
|
_tagged = [cls for cls in Base.__subclasses__() if hasattr(cls, "Tag")]
|
|
@@ -39,7 +39,6 @@ from mlrun.api.utils.db.sql_collation import SQLCollationUtil
|
|
|
39
39
|
|
|
40
40
|
Base = declarative_base()
|
|
41
41
|
NULL = None # Avoid flake8 issuing warnings when comparing in filter
|
|
42
|
-
run_time_fmt = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
def make_label(table):
|
|
@@ -54,6 +53,9 @@ def make_label(table):
|
|
|
54
53
|
value = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
55
54
|
parent = Column(Integer, ForeignKey(f"{table}.id"))
|
|
56
55
|
|
|
56
|
+
def get_identifier_string(self) -> str:
|
|
57
|
+
return f"{self.parent}/{self.name}/{self.value}"
|
|
58
|
+
|
|
57
59
|
return Label
|
|
58
60
|
|
|
59
61
|
|
|
@@ -90,6 +92,9 @@ def make_tag_v2(table):
|
|
|
90
92
|
ForeignKey(f"{table}.name"),
|
|
91
93
|
)
|
|
92
94
|
|
|
95
|
+
def get_identifier_string(self) -> str:
|
|
96
|
+
return f"{self.project}/{self.name}"
|
|
97
|
+
|
|
93
98
|
return Tag
|
|
94
99
|
|
|
95
100
|
|
|
@@ -242,6 +247,9 @@ with warnings.catch_warnings():
|
|
|
242
247
|
state = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
243
248
|
timeout = Column(Integer)
|
|
244
249
|
|
|
250
|
+
def get_identifier_string(self) -> str:
|
|
251
|
+
return f"{self.project}/{self.name}"
|
|
252
|
+
|
|
245
253
|
class Schedule(Base, mlrun.utils.db.BaseModel):
|
|
246
254
|
__tablename__ = "schedules_v2"
|
|
247
255
|
__table_args__ = (UniqueConstraint("project", "name", name="_schedules_v2_uc"),)
|
|
@@ -301,6 +309,9 @@ with warnings.catch_warnings():
|
|
|
301
309
|
id = Column(Integer, primary_key=True)
|
|
302
310
|
name = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
303
311
|
|
|
312
|
+
def get_identifier_string(self) -> str:
|
|
313
|
+
return f"{self.name}"
|
|
314
|
+
|
|
304
315
|
class Project(Base, mlrun.utils.db.BaseModel):
|
|
305
316
|
__tablename__ = "projects"
|
|
306
317
|
# For now since we use project name a lot
|
|
@@ -347,7 +358,7 @@ with warnings.catch_warnings():
|
|
|
347
358
|
labels = relationship(Label, cascade="all, delete-orphan")
|
|
348
359
|
|
|
349
360
|
def get_identifier_string(self) -> str:
|
|
350
|
-
return f"{self.
|
|
361
|
+
return f"{self.feature_set_id}/{self.name}"
|
|
351
362
|
|
|
352
363
|
class Entity(Base, mlrun.utils.db.BaseModel):
|
|
353
364
|
__tablename__ = "entities"
|
|
@@ -464,6 +475,9 @@ with warnings.catch_warnings():
|
|
|
464
475
|
version = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
465
476
|
created = Column(TIMESTAMP, default=datetime.now(timezone.utc))
|
|
466
477
|
|
|
478
|
+
def get_identifier_string(self) -> str:
|
|
479
|
+
return f"{self.version}"
|
|
480
|
+
|
|
467
481
|
|
|
468
482
|
# Must be after all table definitions
|
|
469
483
|
_tagged = [cls for cls in Base.__subclasses__() if hasattr(cls, "Tag")]
|
mlrun/api/launcher.py
CHANGED
|
@@ -13,20 +13,40 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
from typing import Dict, List, Optional, Union
|
|
15
15
|
|
|
16
|
+
from dependency_injector import containers, providers
|
|
17
|
+
|
|
16
18
|
import mlrun.api.crud
|
|
17
|
-
import mlrun.
|
|
19
|
+
import mlrun.common.db.sql_session
|
|
18
20
|
import mlrun.common.schemas.schedule
|
|
19
21
|
import mlrun.config
|
|
20
22
|
import mlrun.execution
|
|
21
|
-
import mlrun.launcher.base
|
|
23
|
+
import mlrun.launcher.base as launcher
|
|
24
|
+
import mlrun.launcher.factory
|
|
22
25
|
import mlrun.runtimes
|
|
23
26
|
import mlrun.runtimes.generators
|
|
24
27
|
import mlrun.runtimes.utils
|
|
25
28
|
import mlrun.utils
|
|
26
29
|
import mlrun.utils.regex
|
|
27
30
|
|
|
31
|
+
# must be at the bottom to avoid circular import conflicts and can't use 'from' notation because unit tests mock this
|
|
32
|
+
import mlrun.api.api.utils # isort:skip
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ServerSideLauncher(launcher.BaseLauncher):
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
local: bool = False,
|
|
39
|
+
auth_info: Optional[mlrun.common.schemas.AuthInfo] = None,
|
|
40
|
+
**kwargs,
|
|
41
|
+
):
|
|
42
|
+
super().__init__(**kwargs)
|
|
43
|
+
if local:
|
|
44
|
+
raise mlrun.errors.MLRunInternalServerError(
|
|
45
|
+
"Launch of local run inside the server is not allowed"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
self._auth_info = auth_info
|
|
28
49
|
|
|
29
|
-
class ServerSideLauncher(mlrun.launcher.base.BaseLauncher):
|
|
30
50
|
def launch(
|
|
31
51
|
self,
|
|
32
52
|
runtime: mlrun.runtimes.BaseRuntime,
|
|
@@ -145,15 +165,21 @@ class ServerSideLauncher(mlrun.launcher.base.BaseLauncher):
|
|
|
145
165
|
|
|
146
166
|
return self._wrap_run_result(runtime, result, run, err=last_err)
|
|
147
167
|
|
|
148
|
-
@staticmethod
|
|
149
168
|
def enrich_runtime(
|
|
150
|
-
|
|
169
|
+
self,
|
|
170
|
+
runtime: "mlrun.runtimes.base.BaseRuntime",
|
|
171
|
+
project_name: Optional[str] = "",
|
|
151
172
|
):
|
|
152
173
|
"""
|
|
153
174
|
Enrich the runtime object with the project spec and metadata.
|
|
154
175
|
This is done only on the server side, since it's the source of truth for the project, and we want to keep the
|
|
155
176
|
client side enrichment as minimal as possible.
|
|
156
177
|
"""
|
|
178
|
+
if self._auth_info:
|
|
179
|
+
mlrun.api.api.utils.apply_enrichment_and_validation_on_function(
|
|
180
|
+
runtime, self._auth_info
|
|
181
|
+
)
|
|
182
|
+
|
|
157
183
|
# ensure the runtime has a project before we enrich it with the project's spec
|
|
158
184
|
runtime.metadata.project = (
|
|
159
185
|
project_name
|
|
@@ -175,7 +201,7 @@ class ServerSideLauncher(mlrun.launcher.base.BaseLauncher):
|
|
|
175
201
|
|
|
176
202
|
# If in the api server, we can assume that watch=False, so we save notification
|
|
177
203
|
# configs to the DB, for the run monitor to later pick up and push.
|
|
178
|
-
session = mlrun.
|
|
204
|
+
session = mlrun.common.db.sql_session.create_session()
|
|
179
205
|
mlrun.api.crud.Notifications().store_run_notifications(
|
|
180
206
|
session,
|
|
181
207
|
runobj.spec.notifications,
|
|
@@ -194,3 +220,9 @@ class ServerSideLauncher(mlrun.launcher.base.BaseLauncher):
|
|
|
194
220
|
struct, runtime.metadata.name, runtime.metadata.project, versioned=True
|
|
195
221
|
)
|
|
196
222
|
run.spec.function = runtime._function_uri(hash_key=hash_key)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# Once this file is imported it will set the container server side launcher
|
|
226
|
+
@containers.override(mlrun.launcher.factory.LauncherContainer)
|
|
227
|
+
class ServerSideLauncherContainer(containers.DeclarativeContainer):
|
|
228
|
+
server_side_launcher = providers.Factory(ServerSideLauncher)
|
mlrun/api/main.py
CHANGED
|
@@ -37,6 +37,7 @@ from mlrun.api.api.api import api_router
|
|
|
37
37
|
from mlrun.api.db.session import close_session, create_session
|
|
38
38
|
from mlrun.api.initial_data import init_data
|
|
39
39
|
from mlrun.api.middlewares import init_middlewares
|
|
40
|
+
from mlrun.api.runtime_handlers import get_runtime_handler
|
|
40
41
|
from mlrun.api.utils.periodic import (
|
|
41
42
|
cancel_all_periodic_functions,
|
|
42
43
|
cancel_periodic_function,
|
|
@@ -52,7 +53,7 @@ from mlrun.api.utils.singletons.project_member import (
|
|
|
52
53
|
from mlrun.api.utils.singletons.scheduler import get_scheduler, initialize_scheduler
|
|
53
54
|
from mlrun.config import config
|
|
54
55
|
from mlrun.errors import err_to_str
|
|
55
|
-
from mlrun.runtimes import RuntimeClassMode, RuntimeKinds
|
|
56
|
+
from mlrun.runtimes import RuntimeClassMode, RuntimeKinds
|
|
56
57
|
from mlrun.utils import logger
|
|
57
58
|
|
|
58
59
|
API_PREFIX = "/api"
|
|
@@ -616,7 +617,7 @@ def _push_terminal_run_notifications(db: mlrun.api.db.base.DBInterface, db_sessi
|
|
|
616
617
|
logger.debug(
|
|
617
618
|
"Got terminal runs with configured notifications", runs_amount=len(runs)
|
|
618
619
|
)
|
|
619
|
-
mlrun.utils.notifications.NotificationPusher(unmasked_runs).push(
|
|
620
|
+
mlrun.utils.notifications.NotificationPusher(unmasked_runs).push()
|
|
620
621
|
|
|
621
622
|
_last_notification_push_time = now
|
|
622
623
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2023 MLRun Authors
|
|
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.
|