mlrun 1.3.3__py3-none-any.whl → 1.4.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.
- mlrun/__init__.py +3 -3
- mlrun/__main__.py +79 -37
- mlrun/api/__init__.py +1 -1
- mlrun/api/api/__init__.py +1 -1
- mlrun/api/api/api.py +4 -4
- mlrun/api/api/deps.py +10 -21
- mlrun/api/api/endpoints/__init__.py +1 -1
- mlrun/api/api/endpoints/artifacts.py +64 -36
- mlrun/api/api/endpoints/auth.py +4 -4
- mlrun/api/api/endpoints/background_tasks.py +11 -11
- mlrun/api/api/endpoints/client_spec.py +5 -5
- mlrun/api/api/endpoints/clusterization_spec.py +6 -4
- mlrun/api/api/endpoints/feature_store.py +124 -115
- mlrun/api/api/endpoints/files.py +22 -14
- mlrun/api/api/endpoints/frontend_spec.py +28 -21
- mlrun/api/api/endpoints/functions.py +142 -87
- mlrun/api/api/endpoints/grafana_proxy.py +89 -442
- mlrun/api/api/endpoints/healthz.py +20 -7
- mlrun/api/api/endpoints/hub.py +320 -0
- mlrun/api/api/endpoints/internal/__init__.py +1 -1
- mlrun/api/api/endpoints/internal/config.py +1 -1
- mlrun/api/api/endpoints/internal/memory_reports.py +9 -9
- mlrun/api/api/endpoints/logs.py +11 -11
- mlrun/api/api/endpoints/model_endpoints.py +74 -70
- mlrun/api/api/endpoints/operations.py +13 -9
- mlrun/api/api/endpoints/pipelines.py +93 -88
- mlrun/api/api/endpoints/projects.py +35 -35
- mlrun/api/api/endpoints/runs.py +69 -27
- mlrun/api/api/endpoints/runtime_resources.py +28 -28
- mlrun/api/api/endpoints/schedules.py +98 -41
- mlrun/api/api/endpoints/secrets.py +37 -32
- mlrun/api/api/endpoints/submit.py +12 -12
- mlrun/api/api/endpoints/tags.py +20 -22
- mlrun/api/api/utils.py +251 -42
- mlrun/api/constants.py +1 -1
- mlrun/api/crud/__init__.py +18 -15
- mlrun/api/crud/artifacts.py +10 -10
- mlrun/api/crud/client_spec.py +4 -4
- mlrun/api/crud/clusterization_spec.py +3 -3
- mlrun/api/crud/feature_store.py +54 -46
- mlrun/api/crud/functions.py +3 -3
- mlrun/api/crud/hub.py +312 -0
- mlrun/api/crud/logs.py +11 -9
- mlrun/api/crud/model_monitoring/__init__.py +3 -3
- mlrun/api/crud/model_monitoring/grafana.py +435 -0
- mlrun/api/crud/model_monitoring/model_endpoints.py +352 -129
- mlrun/api/crud/notifications.py +149 -0
- mlrun/api/crud/pipelines.py +67 -52
- mlrun/api/crud/projects.py +51 -23
- mlrun/api/crud/runs.py +7 -5
- mlrun/api/crud/runtime_resources.py +13 -13
- mlrun/api/{db/filedb → crud/runtimes}/__init__.py +1 -1
- mlrun/api/crud/runtimes/nuclio/__init__.py +14 -0
- mlrun/api/crud/runtimes/nuclio/function.py +505 -0
- mlrun/api/crud/runtimes/nuclio/helpers.py +310 -0
- mlrun/api/crud/secrets.py +88 -46
- mlrun/api/crud/tags.py +5 -5
- mlrun/api/db/__init__.py +1 -1
- mlrun/api/db/base.py +102 -54
- mlrun/api/db/init_db.py +2 -3
- mlrun/api/db/session.py +4 -12
- mlrun/api/db/sqldb/__init__.py +1 -1
- mlrun/api/db/sqldb/db.py +439 -196
- mlrun/api/db/sqldb/helpers.py +1 -1
- mlrun/api/db/sqldb/models/__init__.py +3 -3
- mlrun/api/db/sqldb/models/models_mysql.py +82 -64
- mlrun/api/db/sqldb/models/models_sqlite.py +76 -64
- mlrun/api/db/sqldb/session.py +27 -20
- mlrun/api/initial_data.py +82 -24
- mlrun/api/launcher.py +196 -0
- mlrun/api/main.py +91 -22
- mlrun/api/middlewares.py +6 -5
- mlrun/api/migrations_mysql/env.py +1 -1
- mlrun/api/migrations_mysql/versions/28383af526f3_market_place_to_hub.py +40 -0
- mlrun/api/migrations_mysql/versions/32bae1b0e29c_increase_timestamp_fields_precision.py +1 -1
- mlrun/api/migrations_mysql/versions/4903aef6a91d_tag_foreign_key_and_cascades.py +1 -1
- mlrun/api/migrations_mysql/versions/5f1351c88a19_adding_background_tasks_table.py +1 -1
- mlrun/api/migrations_mysql/versions/88e656800d6a_add_requested_logs_column_and_index_to_.py +1 -1
- mlrun/api/migrations_mysql/versions/9d16de5f03a7_adding_data_versions_table.py +1 -1
- mlrun/api/migrations_mysql/versions/b86f5b53f3d7_adding_name_and_updated_to_runs_table.py +1 -1
- mlrun/api/migrations_mysql/versions/c4af40b0bf61_init.py +1 -1
- mlrun/api/migrations_mysql/versions/c905d15bd91d_notifications.py +72 -0
- mlrun/api/migrations_mysql/versions/ee041e8fdaa0_adding_next_run_time_column_to_schedule_.py +1 -1
- mlrun/api/migrations_sqlite/env.py +1 -1
- mlrun/api/migrations_sqlite/versions/11f8dd2dc9fe_init.py +1 -1
- mlrun/api/migrations_sqlite/versions/1c954f8cb32d_schedule_last_run_uri.py +1 -1
- mlrun/api/migrations_sqlite/versions/2b6d23c715aa_adding_feature_sets.py +1 -1
- mlrun/api/migrations_sqlite/versions/4acd9430b093_market_place_to_hub.py +77 -0
- mlrun/api/migrations_sqlite/versions/6401142f2d7c_adding_next_run_time_column_to_schedule_.py +1 -1
- mlrun/api/migrations_sqlite/versions/64d90a1a69bc_adding_background_tasks_table.py +1 -1
- mlrun/api/migrations_sqlite/versions/803438ecd005_add_requested_logs_column_to_runs.py +1 -1
- mlrun/api/migrations_sqlite/versions/863114f0c659_refactoring_feature_set.py +1 -1
- mlrun/api/migrations_sqlite/versions/959ae00528ad_notifications.py +63 -0
- mlrun/api/migrations_sqlite/versions/accf9fc83d38_adding_data_versions_table.py +1 -1
- mlrun/api/migrations_sqlite/versions/b68e8e897a28_schedule_labels.py +1 -1
- mlrun/api/migrations_sqlite/versions/bcd0c1f9720c_adding_project_labels.py +1 -1
- mlrun/api/migrations_sqlite/versions/cf21882f938e_schedule_id.py +1 -1
- mlrun/api/migrations_sqlite/versions/d781f58f607f_tag_object_name_string.py +1 -1
- mlrun/api/migrations_sqlite/versions/deac06871ace_adding_marketplace_sources_table.py +1 -1
- mlrun/api/migrations_sqlite/versions/e1dd5983c06b_schedule_concurrency_limit.py +1 -1
- mlrun/api/migrations_sqlite/versions/e5594ed3ab53_adding_name_and_updated_to_runs_table.py +1 -1
- mlrun/api/migrations_sqlite/versions/f4249b4ba6fa_adding_feature_vectors.py +1 -1
- mlrun/api/migrations_sqlite/versions/f7b5a1a03629_adding_feature_labels.py +1 -1
- mlrun/api/schemas/__init__.py +216 -138
- mlrun/api/utils/__init__.py +1 -1
- mlrun/api/utils/asyncio.py +1 -1
- mlrun/api/utils/auth/__init__.py +1 -1
- mlrun/api/utils/auth/providers/__init__.py +1 -1
- mlrun/api/utils/auth/providers/base.py +7 -7
- mlrun/api/utils/auth/providers/nop.py +6 -7
- mlrun/api/utils/auth/providers/opa.py +17 -17
- mlrun/api/utils/auth/verifier.py +36 -34
- mlrun/api/utils/background_tasks.py +24 -24
- mlrun/{builder.py → api/utils/builder.py} +216 -123
- mlrun/api/utils/clients/__init__.py +1 -1
- mlrun/api/utils/clients/chief.py +19 -4
- mlrun/api/utils/clients/iguazio.py +106 -60
- mlrun/api/utils/clients/log_collector.py +1 -1
- mlrun/api/utils/clients/nuclio.py +23 -23
- mlrun/api/utils/clients/protocols/grpc.py +2 -2
- mlrun/api/utils/db/__init__.py +1 -1
- mlrun/api/utils/db/alembic.py +1 -1
- mlrun/api/utils/db/backup.py +1 -1
- mlrun/api/utils/db/mysql.py +24 -25
- mlrun/api/utils/db/sql_collation.py +1 -1
- mlrun/api/utils/db/sqlite_migration.py +2 -2
- mlrun/api/utils/events/__init__.py +14 -0
- mlrun/api/utils/events/base.py +57 -0
- mlrun/api/utils/events/events_factory.py +41 -0
- mlrun/api/utils/events/iguazio.py +217 -0
- mlrun/api/utils/events/nop.py +55 -0
- mlrun/api/utils/helpers.py +16 -13
- mlrun/api/utils/memory_reports.py +1 -1
- mlrun/api/utils/periodic.py +6 -3
- mlrun/api/utils/projects/__init__.py +1 -1
- mlrun/api/utils/projects/follower.py +33 -33
- mlrun/api/utils/projects/leader.py +36 -34
- mlrun/api/utils/projects/member.py +27 -27
- mlrun/api/utils/projects/remotes/__init__.py +1 -1
- mlrun/api/utils/projects/remotes/follower.py +13 -13
- mlrun/api/utils/projects/remotes/leader.py +10 -10
- mlrun/api/utils/projects/remotes/nop_follower.py +27 -21
- mlrun/api/utils/projects/remotes/nop_leader.py +17 -16
- mlrun/api/utils/scheduler.py +140 -51
- mlrun/api/utils/singletons/__init__.py +1 -1
- mlrun/api/utils/singletons/db.py +9 -15
- mlrun/api/utils/singletons/k8s.py +677 -5
- mlrun/api/utils/singletons/logs_dir.py +1 -1
- mlrun/api/utils/singletons/project_member.py +1 -1
- mlrun/api/utils/singletons/scheduler.py +1 -1
- mlrun/artifacts/__init__.py +2 -2
- mlrun/artifacts/base.py +8 -2
- mlrun/artifacts/dataset.py +5 -3
- mlrun/artifacts/manager.py +7 -1
- mlrun/artifacts/model.py +15 -4
- mlrun/artifacts/plots.py +1 -1
- mlrun/common/__init__.py +1 -1
- mlrun/common/constants.py +15 -0
- mlrun/common/model_monitoring.py +209 -0
- mlrun/common/schemas/__init__.py +167 -0
- mlrun/{api → common}/schemas/artifact.py +13 -14
- mlrun/{api → common}/schemas/auth.py +10 -8
- mlrun/{api → common}/schemas/background_task.py +3 -3
- mlrun/{api → common}/schemas/client_spec.py +1 -1
- mlrun/{api → common}/schemas/clusterization_spec.py +3 -3
- mlrun/{api → common}/schemas/constants.py +21 -8
- mlrun/common/schemas/events.py +36 -0
- mlrun/{api → common}/schemas/feature_store.py +2 -1
- mlrun/{api → common}/schemas/frontend_spec.py +7 -6
- mlrun/{api → common}/schemas/function.py +5 -5
- mlrun/{api → common}/schemas/http.py +3 -3
- mlrun/common/schemas/hub.py +134 -0
- mlrun/{api → common}/schemas/k8s.py +3 -3
- mlrun/{api → common}/schemas/memory_reports.py +1 -1
- mlrun/common/schemas/model_endpoints.py +342 -0
- mlrun/common/schemas/notification.py +57 -0
- mlrun/{api → common}/schemas/object.py +6 -6
- mlrun/{api → common}/schemas/pipeline.py +3 -3
- mlrun/{api → common}/schemas/project.py +6 -5
- mlrun/common/schemas/regex.py +24 -0
- mlrun/common/schemas/runs.py +30 -0
- mlrun/{api → common}/schemas/runtime_resource.py +3 -3
- mlrun/{api → common}/schemas/schedule.py +19 -7
- mlrun/{api → common}/schemas/secret.py +3 -3
- mlrun/{api → common}/schemas/tag.py +2 -2
- mlrun/common/types.py +25 -0
- mlrun/config.py +152 -20
- mlrun/data_types/__init__.py +7 -2
- mlrun/data_types/data_types.py +4 -2
- mlrun/data_types/infer.py +1 -1
- mlrun/data_types/spark.py +10 -3
- mlrun/datastore/__init__.py +10 -3
- mlrun/datastore/azure_blob.py +1 -1
- mlrun/datastore/base.py +185 -53
- mlrun/datastore/datastore.py +1 -1
- mlrun/datastore/filestore.py +1 -1
- mlrun/datastore/google_cloud_storage.py +1 -1
- mlrun/datastore/inmem.py +4 -1
- mlrun/datastore/redis.py +1 -1
- mlrun/datastore/s3.py +1 -1
- mlrun/datastore/sources.py +192 -70
- mlrun/datastore/spark_udf.py +44 -0
- mlrun/datastore/store_resources.py +4 -4
- mlrun/datastore/targets.py +115 -45
- mlrun/datastore/utils.py +127 -5
- mlrun/datastore/v3io.py +1 -1
- mlrun/datastore/wasbfs/__init__.py +1 -1
- mlrun/datastore/wasbfs/fs.py +1 -1
- mlrun/db/__init__.py +7 -5
- mlrun/db/base.py +112 -68
- mlrun/db/httpdb.py +445 -277
- mlrun/db/nopdb.py +491 -0
- mlrun/db/sqldb.py +112 -65
- mlrun/errors.py +6 -1
- mlrun/execution.py +44 -22
- mlrun/feature_store/__init__.py +1 -1
- mlrun/feature_store/api.py +143 -95
- mlrun/feature_store/common.py +16 -20
- mlrun/feature_store/feature_set.py +42 -12
- mlrun/feature_store/feature_vector.py +32 -21
- mlrun/feature_store/ingestion.py +9 -12
- mlrun/feature_store/retrieval/__init__.py +3 -2
- mlrun/feature_store/retrieval/base.py +388 -66
- mlrun/feature_store/retrieval/dask_merger.py +63 -151
- mlrun/feature_store/retrieval/job.py +30 -12
- mlrun/feature_store/retrieval/local_merger.py +40 -133
- mlrun/feature_store/retrieval/spark_merger.py +129 -127
- mlrun/feature_store/retrieval/storey_merger.py +173 -0
- mlrun/feature_store/steps.py +132 -15
- mlrun/features.py +8 -3
- mlrun/frameworks/__init__.py +1 -1
- mlrun/frameworks/_common/__init__.py +1 -1
- mlrun/frameworks/_common/artifacts_library.py +1 -1
- mlrun/frameworks/_common/mlrun_interface.py +1 -1
- mlrun/frameworks/_common/model_handler.py +1 -1
- mlrun/frameworks/_common/plan.py +1 -1
- mlrun/frameworks/_common/producer.py +1 -1
- mlrun/frameworks/_common/utils.py +1 -1
- mlrun/frameworks/_dl_common/__init__.py +1 -1
- mlrun/frameworks/_dl_common/loggers/__init__.py +1 -1
- mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +1 -1
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +1 -1
- mlrun/frameworks/_dl_common/model_handler.py +1 -1
- mlrun/frameworks/_dl_common/utils.py +1 -1
- mlrun/frameworks/_ml_common/__init__.py +1 -1
- mlrun/frameworks/_ml_common/artifacts_library.py +1 -1
- mlrun/frameworks/_ml_common/loggers/__init__.py +1 -1
- mlrun/frameworks/_ml_common/loggers/logger.py +1 -1
- mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
- mlrun/frameworks/_ml_common/model_handler.py +1 -1
- mlrun/frameworks/_ml_common/pkl_model_server.py +13 -1
- mlrun/frameworks/_ml_common/plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/__init__.py +1 -1
- mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +1 -6
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +1 -1
- mlrun/frameworks/_ml_common/producer.py +1 -1
- mlrun/frameworks/_ml_common/utils.py +1 -1
- mlrun/frameworks/auto_mlrun/__init__.py +1 -1
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +1 -1
- mlrun/frameworks/huggingface/__init__.py +1 -1
- mlrun/frameworks/huggingface/model_server.py +1 -1
- mlrun/frameworks/lgbm/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/callback.py +1 -1
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +1 -1
- mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -1
- mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -1
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +1 -1
- mlrun/frameworks/lgbm/mlrun_interfaces/model_mlrun_interface.py +1 -1
- mlrun/frameworks/lgbm/model_handler.py +1 -1
- mlrun/frameworks/lgbm/model_server.py +1 -1
- mlrun/frameworks/lgbm/utils.py +1 -1
- mlrun/frameworks/onnx/__init__.py +1 -1
- mlrun/frameworks/onnx/dataset.py +1 -1
- mlrun/frameworks/onnx/mlrun_interface.py +1 -1
- mlrun/frameworks/onnx/model_handler.py +1 -1
- mlrun/frameworks/onnx/model_server.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +1 -1
- mlrun/frameworks/pytorch/__init__.py +1 -1
- mlrun/frameworks/pytorch/callbacks/__init__.py +1 -1
- mlrun/frameworks/pytorch/callbacks/callback.py +1 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +1 -1
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +1 -1
- mlrun/frameworks/pytorch/callbacks_handler.py +1 -1
- mlrun/frameworks/pytorch/mlrun_interface.py +1 -1
- mlrun/frameworks/pytorch/model_handler.py +1 -1
- mlrun/frameworks/pytorch/model_server.py +1 -1
- mlrun/frameworks/pytorch/utils.py +1 -1
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/sklearn/estimator.py +1 -1
- mlrun/frameworks/sklearn/metric.py +1 -1
- mlrun/frameworks/sklearn/metrics_library.py +1 -1
- mlrun/frameworks/sklearn/mlrun_interface.py +1 -1
- mlrun/frameworks/sklearn/model_handler.py +1 -1
- mlrun/frameworks/sklearn/utils.py +1 -1
- mlrun/frameworks/tf_keras/__init__.py +1 -1
- mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -1
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/mlrun_interface.py +1 -1
- mlrun/frameworks/tf_keras/model_handler.py +1 -1
- mlrun/frameworks/tf_keras/model_server.py +1 -1
- mlrun/frameworks/tf_keras/utils.py +1 -1
- mlrun/frameworks/xgboost/__init__.py +1 -1
- mlrun/frameworks/xgboost/mlrun_interface.py +1 -1
- mlrun/frameworks/xgboost/model_handler.py +1 -1
- mlrun/frameworks/xgboost/utils.py +1 -1
- mlrun/k8s_utils.py +14 -765
- mlrun/kfpops.py +14 -17
- mlrun/launcher/__init__.py +13 -0
- mlrun/launcher/base.py +406 -0
- mlrun/launcher/client.py +159 -0
- mlrun/launcher/factory.py +50 -0
- mlrun/launcher/local.py +276 -0
- mlrun/launcher/remote.py +178 -0
- mlrun/lists.py +10 -2
- mlrun/mlutils/__init__.py +1 -1
- mlrun/mlutils/data.py +1 -1
- mlrun/mlutils/models.py +1 -1
- mlrun/mlutils/plots.py +1 -1
- mlrun/model.py +252 -14
- mlrun/model_monitoring/__init__.py +41 -0
- mlrun/model_monitoring/features_drift_table.py +1 -1
- mlrun/model_monitoring/helpers.py +123 -38
- mlrun/model_monitoring/model_endpoint.py +144 -0
- mlrun/model_monitoring/model_monitoring_batch.py +310 -259
- mlrun/model_monitoring/stores/__init__.py +106 -0
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +448 -0
- mlrun/model_monitoring/stores/model_endpoint_store.py +147 -0
- mlrun/model_monitoring/stores/models/__init__.py +23 -0
- mlrun/model_monitoring/stores/models/base.py +18 -0
- mlrun/model_monitoring/stores/models/mysql.py +100 -0
- mlrun/model_monitoring/stores/models/sqlite.py +98 -0
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +370 -0
- mlrun/model_monitoring/stream_processing_fs.py +239 -271
- mlrun/package/__init__.py +163 -0
- mlrun/package/context_handler.py +325 -0
- mlrun/package/errors.py +47 -0
- mlrun/package/packager.py +298 -0
- mlrun/{runtimes/package → package/packagers}/__init__.py +3 -1
- mlrun/package/packagers/default_packager.py +422 -0
- mlrun/package/packagers/numpy_packagers.py +612 -0
- mlrun/package/packagers/pandas_packagers.py +968 -0
- mlrun/package/packagers/python_standard_library_packagers.py +616 -0
- mlrun/package/packagers_manager.py +786 -0
- mlrun/package/utils/__init__.py +53 -0
- mlrun/package/utils/_archiver.py +226 -0
- mlrun/package/utils/_formatter.py +211 -0
- mlrun/package/utils/_pickler.py +234 -0
- mlrun/package/utils/_supported_format.py +71 -0
- mlrun/package/utils/log_hint_utils.py +93 -0
- mlrun/package/utils/type_hint_utils.py +298 -0
- mlrun/platforms/__init__.py +1 -1
- mlrun/platforms/iguazio.py +34 -2
- mlrun/platforms/other.py +1 -1
- mlrun/projects/__init__.py +1 -1
- mlrun/projects/operations.py +14 -9
- mlrun/projects/pipelines.py +31 -13
- mlrun/projects/project.py +762 -238
- mlrun/render.py +49 -19
- mlrun/run.py +57 -326
- mlrun/runtimes/__init__.py +3 -9
- mlrun/runtimes/base.py +247 -784
- mlrun/runtimes/constants.py +1 -1
- mlrun/runtimes/daskjob.py +45 -41
- mlrun/runtimes/funcdoc.py +43 -7
- mlrun/runtimes/function.py +66 -656
- mlrun/runtimes/function_reference.py +1 -1
- mlrun/runtimes/generators.py +1 -1
- mlrun/runtimes/kubejob.py +99 -116
- mlrun/runtimes/local.py +59 -66
- mlrun/runtimes/mpijob/__init__.py +1 -1
- mlrun/runtimes/mpijob/abstract.py +13 -15
- mlrun/runtimes/mpijob/v1.py +3 -1
- mlrun/runtimes/mpijob/v1alpha1.py +1 -1
- mlrun/runtimes/nuclio.py +1 -1
- mlrun/runtimes/pod.py +51 -26
- mlrun/runtimes/remotesparkjob.py +3 -1
- mlrun/runtimes/serving.py +12 -4
- mlrun/runtimes/sparkjob/__init__.py +1 -2
- mlrun/runtimes/sparkjob/abstract.py +44 -31
- mlrun/runtimes/sparkjob/spark3job.py +11 -9
- mlrun/runtimes/utils.py +61 -42
- mlrun/secrets.py +16 -18
- mlrun/serving/__init__.py +3 -2
- mlrun/serving/merger.py +1 -1
- mlrun/serving/remote.py +1 -1
- mlrun/serving/routers.py +39 -42
- mlrun/serving/server.py +23 -13
- mlrun/serving/serving_wrapper.py +1 -1
- mlrun/serving/states.py +172 -39
- mlrun/serving/utils.py +1 -1
- mlrun/serving/v1_serving.py +1 -1
- mlrun/serving/v2_serving.py +29 -21
- mlrun/utils/__init__.py +1 -2
- mlrun/utils/async_http.py +8 -1
- mlrun/utils/azure_vault.py +1 -1
- mlrun/utils/clones.py +2 -2
- mlrun/utils/condition_evaluator.py +65 -0
- mlrun/utils/db.py +52 -0
- mlrun/utils/helpers.py +188 -13
- mlrun/utils/http.py +89 -54
- mlrun/utils/logger.py +48 -8
- mlrun/utils/model_monitoring.py +132 -100
- mlrun/utils/notifications/__init__.py +1 -1
- mlrun/utils/notifications/notification/__init__.py +8 -6
- mlrun/utils/notifications/notification/base.py +20 -14
- mlrun/utils/notifications/notification/console.py +7 -4
- mlrun/utils/notifications/notification/git.py +36 -19
- mlrun/utils/notifications/notification/ipython.py +10 -8
- mlrun/utils/notifications/notification/slack.py +18 -13
- mlrun/utils/notifications/notification_pusher.py +377 -56
- mlrun/utils/regex.py +6 -1
- mlrun/utils/singleton.py +1 -1
- mlrun/utils/v3io_clients.py +1 -1
- mlrun/utils/vault.py +270 -269
- mlrun/utils/version/__init__.py +1 -1
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +1 -1
- {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/METADATA +16 -10
- mlrun-1.4.0.dist-info/RECORD +434 -0
- mlrun/api/api/endpoints/marketplace.py +0 -257
- mlrun/api/crud/marketplace.py +0 -221
- mlrun/api/crud/model_monitoring/model_endpoint_store.py +0 -847
- mlrun/api/db/filedb/db.py +0 -518
- mlrun/api/schemas/marketplace.py +0 -128
- mlrun/api/schemas/model_endpoints.py +0 -185
- mlrun/db/filedb.py +0 -891
- mlrun/feature_store/retrieval/online.py +0 -92
- mlrun/model_monitoring/constants.py +0 -67
- mlrun/runtimes/package/context_handler.py +0 -711
- mlrun/runtimes/sparkjob/spark2job.py +0 -59
- mlrun-1.3.3.dist-info/RECORD +0 -381
- {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/LICENSE +0 -0
- {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/WHEEL +0 -0
- {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2023 Iguazio
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -13,83 +13,54 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
15
|
import asyncio
|
|
16
|
-
import
|
|
16
|
+
import warnings
|
|
17
17
|
from http import HTTPStatus
|
|
18
|
-
from typing import
|
|
18
|
+
from typing import List, Union
|
|
19
19
|
|
|
20
|
-
import numpy as np
|
|
21
|
-
import pandas as pd
|
|
22
20
|
from fastapi import APIRouter, Depends, Request, Response
|
|
23
21
|
from fastapi.concurrency import run_in_threadpool
|
|
24
22
|
from sqlalchemy.orm import Session
|
|
25
23
|
|
|
26
24
|
import mlrun.api.crud
|
|
27
|
-
import mlrun.api.
|
|
25
|
+
import mlrun.api.crud.model_monitoring.grafana
|
|
28
26
|
import mlrun.api.utils.auth.verifier
|
|
27
|
+
import mlrun.common.model_monitoring
|
|
28
|
+
import mlrun.common.schemas
|
|
29
29
|
from mlrun.api.api import deps
|
|
30
|
-
from mlrun.api.schemas import (
|
|
31
|
-
GrafanaColumn,
|
|
32
|
-
GrafanaDataPoint,
|
|
33
|
-
GrafanaNumberColumn,
|
|
34
|
-
GrafanaTable,
|
|
35
|
-
GrafanaTimeSeriesTarget,
|
|
36
|
-
ProjectsFormat,
|
|
37
|
-
)
|
|
38
|
-
from mlrun.api.utils.singletons.project_member import get_project_member
|
|
39
|
-
from mlrun.errors import MLRunBadRequestError
|
|
40
|
-
from mlrun.utils import config, logger
|
|
41
|
-
from mlrun.utils.model_monitoring import parse_model_endpoint_store_prefix
|
|
42
|
-
from mlrun.utils.v3io_clients import get_frames_client
|
|
43
30
|
|
|
44
|
-
router = APIRouter()
|
|
31
|
+
router = APIRouter(prefix="/grafana-proxy/model-endpoints")
|
|
32
|
+
|
|
33
|
+
NAME_TO_SEARCH_FUNCTION_DICTIONARY = {
|
|
34
|
+
"list_projects": mlrun.api.crud.model_monitoring.grafana.grafana_list_projects,
|
|
35
|
+
}
|
|
36
|
+
NAME_TO_QUERY_FUNCTION_DICTIONARY = {
|
|
37
|
+
"list_endpoints": mlrun.api.crud.model_monitoring.grafana.grafana_list_endpoints,
|
|
38
|
+
"individual_feature_analysis": mlrun.api.crud.model_monitoring.grafana.grafana_individual_feature_analysis,
|
|
39
|
+
"overall_feature_analysis": mlrun.api.crud.model_monitoring.grafana.grafana_overall_feature_analysis,
|
|
40
|
+
"incoming_features": mlrun.api.crud.model_monitoring.grafana.grafana_incoming_features,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
SUPPORTED_QUERY_FUNCTIONS = set(NAME_TO_QUERY_FUNCTION_DICTIONARY.keys())
|
|
44
|
+
SUPPORTED_SEARCH_FUNCTIONS = set(NAME_TO_SEARCH_FUNCTION_DICTIONARY)
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
@router.get("
|
|
47
|
+
@router.get("", status_code=HTTPStatus.OK.value)
|
|
48
48
|
def grafana_proxy_model_endpoints_check_connection(
|
|
49
|
-
auth_info: mlrun.
|
|
49
|
+
auth_info: mlrun.common.schemas.AuthInfo = Depends(deps.authenticate_request),
|
|
50
50
|
):
|
|
51
51
|
"""
|
|
52
52
|
Root of grafana proxy for the model-endpoints API, used for validating the model-endpoints data source
|
|
53
53
|
connectivity.
|
|
54
54
|
"""
|
|
55
|
-
mlrun.
|
|
55
|
+
if not mlrun.mlconf.is_ce_mode():
|
|
56
|
+
mlrun.api.crud.ModelEndpoints().get_access_key(auth_info)
|
|
56
57
|
return Response(status_code=HTTPStatus.OK.value)
|
|
57
58
|
|
|
58
59
|
|
|
59
|
-
@router.post(
|
|
60
|
-
"/grafana-proxy/model-endpoints/query",
|
|
61
|
-
response_model=List[Union[GrafanaTable, GrafanaTimeSeriesTarget]],
|
|
62
|
-
)
|
|
63
|
-
async def grafana_proxy_model_endpoints_query(
|
|
64
|
-
request: Request,
|
|
65
|
-
auth_info: mlrun.api.schemas.AuthInfo = Depends(deps.authenticate_request),
|
|
66
|
-
) -> List[Union[GrafanaTable, GrafanaTimeSeriesTarget]]:
|
|
67
|
-
"""
|
|
68
|
-
Query route for model-endpoints grafana proxy API, used for creating an interface between grafana queries and
|
|
69
|
-
model-endpoints logic.
|
|
70
|
-
|
|
71
|
-
This implementation requires passing target_endpoint query parameter in order to dispatch different
|
|
72
|
-
model-endpoint monitoring functions.
|
|
73
|
-
"""
|
|
74
|
-
body = await request.json()
|
|
75
|
-
query_parameters = _parse_query_parameters(body)
|
|
76
|
-
_validate_query_parameters(query_parameters, SUPPORTED_QUERY_FUNCTIONS)
|
|
77
|
-
query_parameters = _drop_grafana_escape_chars(query_parameters)
|
|
78
|
-
|
|
79
|
-
# At this point everything is validated and we can access everything that is needed without performing all previous
|
|
80
|
-
# checks again.
|
|
81
|
-
target_endpoint = query_parameters["target_endpoint"]
|
|
82
|
-
function = NAME_TO_QUERY_FUNCTION_DICTIONARY[target_endpoint]
|
|
83
|
-
if asyncio.iscoroutinefunction(function):
|
|
84
|
-
return await function(body, query_parameters, auth_info)
|
|
85
|
-
result = await run_in_threadpool(function, body, query_parameters, auth_info)
|
|
86
|
-
return result
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
@router.post("/grafana-proxy/model-endpoints/search", response_model=List[str])
|
|
60
|
+
@router.post("/search", response_model=List[str])
|
|
90
61
|
async def grafana_proxy_model_endpoints_search(
|
|
91
62
|
request: Request,
|
|
92
|
-
auth_info: mlrun.
|
|
63
|
+
auth_info: mlrun.common.schemas.AuthInfo = Depends(deps.authenticate_request),
|
|
93
64
|
db_session: Session = Depends(deps.get_db_session),
|
|
94
65
|
) -> List[str]:
|
|
95
66
|
"""
|
|
@@ -98,411 +69,87 @@ async def grafana_proxy_model_endpoints_search(
|
|
|
98
69
|
|
|
99
70
|
This implementation requires passing target_endpoint query parameter in order to dispatch different
|
|
100
71
|
model-endpoint monitoring functions.
|
|
72
|
+
|
|
73
|
+
:param request: An api request with the required target and parameters.
|
|
74
|
+
:param auth_info: The auth info of the request.
|
|
75
|
+
:param db_session: A session that manages the current dialog with the database.
|
|
76
|
+
|
|
77
|
+
:return: List of results. e.g. list of available project names.
|
|
101
78
|
"""
|
|
102
|
-
mlrun.
|
|
79
|
+
if not mlrun.mlconf.is_ce_mode():
|
|
80
|
+
mlrun.api.crud.ModelEndpoints().get_access_key(auth_info)
|
|
103
81
|
body = await request.json()
|
|
104
|
-
query_parameters =
|
|
105
|
-
|
|
106
|
-
|
|
82
|
+
query_parameters = mlrun.api.crud.model_monitoring.grafana.parse_search_parameters(
|
|
83
|
+
body
|
|
84
|
+
)
|
|
85
|
+
mlrun.api.crud.model_monitoring.grafana.validate_query_parameters(
|
|
86
|
+
query_parameters, SUPPORTED_SEARCH_FUNCTIONS
|
|
87
|
+
)
|
|
107
88
|
|
|
108
89
|
# At this point everything is validated and we can access everything that is needed without performing all previous
|
|
109
90
|
# checks again.
|
|
110
91
|
target_endpoint = query_parameters["target_endpoint"]
|
|
111
92
|
function = NAME_TO_SEARCH_FUNCTION_DICTIONARY[target_endpoint]
|
|
112
|
-
if asyncio.iscoroutinefunction(function):
|
|
113
|
-
return await function(db_session, auth_info)
|
|
114
|
-
result = await run_in_threadpool(function, db_session, auth_info)
|
|
115
|
-
return result
|
|
116
93
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
db_session, format_=ProjectsFormat.name_only, leader_session=auth_info.session
|
|
123
|
-
)
|
|
124
|
-
return projects_output.projects
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
async def grafana_list_endpoints(
|
|
128
|
-
body: Dict[str, Any],
|
|
129
|
-
query_parameters: Dict[str, str],
|
|
130
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
131
|
-
) -> List[GrafanaTable]:
|
|
132
|
-
project = query_parameters.get("project")
|
|
133
|
-
|
|
134
|
-
# Filters
|
|
135
|
-
model = query_parameters.get("model", None)
|
|
136
|
-
function = query_parameters.get("function", None)
|
|
137
|
-
labels = query_parameters.get("labels", "")
|
|
138
|
-
labels = labels.split(",") if labels else []
|
|
139
|
-
|
|
140
|
-
# Metrics to include
|
|
141
|
-
metrics = query_parameters.get("metrics", "")
|
|
142
|
-
metrics = metrics.split(",") if metrics else []
|
|
143
|
-
|
|
144
|
-
# Time range for metrics
|
|
145
|
-
start = body.get("rangeRaw", {}).get("start", "now-1h")
|
|
146
|
-
end = body.get("rangeRaw", {}).get("end", "now")
|
|
147
|
-
|
|
148
|
-
if project:
|
|
149
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_permissions(
|
|
150
|
-
project,
|
|
151
|
-
mlrun.api.schemas.AuthorizationAction.read,
|
|
152
|
-
auth_info,
|
|
94
|
+
if asyncio.iscoroutinefunction(function):
|
|
95
|
+
result = await function(db_session, auth_info, query_parameters)
|
|
96
|
+
else:
|
|
97
|
+
result = await run_in_threadpool(
|
|
98
|
+
function, db_session, auth_info, query_parameters
|
|
153
99
|
)
|
|
154
|
-
|
|
155
|
-
mlrun.api.crud.ModelEndpoints().list_model_endpoints,
|
|
156
|
-
auth_info=auth_info,
|
|
157
|
-
project=project,
|
|
158
|
-
model=model,
|
|
159
|
-
function=function,
|
|
160
|
-
labels=labels,
|
|
161
|
-
metrics=metrics,
|
|
162
|
-
start=start,
|
|
163
|
-
end=end,
|
|
164
|
-
)
|
|
165
|
-
allowed_endpoints = await mlrun.api.utils.auth.verifier.AuthVerifier().filter_project_resources_by_permissions(
|
|
166
|
-
mlrun.api.schemas.AuthorizationResourceTypes.model_endpoint,
|
|
167
|
-
endpoint_list.endpoints,
|
|
168
|
-
lambda _endpoint: (
|
|
169
|
-
_endpoint.metadata.project,
|
|
170
|
-
_endpoint.metadata.uid,
|
|
171
|
-
),
|
|
172
|
-
auth_info,
|
|
173
|
-
)
|
|
174
|
-
endpoint_list.endpoints = allowed_endpoints
|
|
175
|
-
|
|
176
|
-
columns = [
|
|
177
|
-
GrafanaColumn(text="endpoint_id", type="string"),
|
|
178
|
-
GrafanaColumn(text="endpoint_function", type="string"),
|
|
179
|
-
GrafanaColumn(text="endpoint_model", type="string"),
|
|
180
|
-
GrafanaColumn(text="endpoint_model_class", type="string"),
|
|
181
|
-
GrafanaColumn(text="first_request", type="time"),
|
|
182
|
-
GrafanaColumn(text="last_request", type="time"),
|
|
183
|
-
GrafanaColumn(text="accuracy", type="number"),
|
|
184
|
-
GrafanaColumn(text="error_count", type="number"),
|
|
185
|
-
GrafanaColumn(text="drift_status", type="number"),
|
|
186
|
-
]
|
|
187
|
-
|
|
188
|
-
metric_columns = []
|
|
189
|
-
|
|
190
|
-
found_metrics = set()
|
|
191
|
-
for endpoint in endpoint_list.endpoints:
|
|
192
|
-
if endpoint.status.metrics is not None:
|
|
193
|
-
for key in endpoint.status.metrics.keys():
|
|
194
|
-
if key not in found_metrics:
|
|
195
|
-
found_metrics.add(key)
|
|
196
|
-
metric_columns.append(GrafanaColumn(text=key, type="number"))
|
|
197
|
-
|
|
198
|
-
columns = columns + metric_columns
|
|
199
|
-
table = GrafanaTable(columns=columns)
|
|
200
|
-
|
|
201
|
-
for endpoint in endpoint_list.endpoints:
|
|
202
|
-
row = [
|
|
203
|
-
endpoint.metadata.uid,
|
|
204
|
-
endpoint.spec.function_uri,
|
|
205
|
-
endpoint.spec.model,
|
|
206
|
-
endpoint.spec.model_class,
|
|
207
|
-
endpoint.status.first_request,
|
|
208
|
-
endpoint.status.last_request,
|
|
209
|
-
endpoint.status.accuracy,
|
|
210
|
-
endpoint.status.error_count,
|
|
211
|
-
endpoint.status.drift_status,
|
|
212
|
-
]
|
|
213
|
-
|
|
214
|
-
if endpoint.status.metrics is not None and metric_columns:
|
|
215
|
-
for metric_column in metric_columns:
|
|
216
|
-
row.append(endpoint.status.metrics[metric_column.text])
|
|
217
|
-
|
|
218
|
-
table.add_row(*row)
|
|
219
|
-
|
|
220
|
-
return [table]
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
async def grafana_individual_feature_analysis(
|
|
224
|
-
body: Dict[str, Any],
|
|
225
|
-
query_parameters: Dict[str, str],
|
|
226
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
227
|
-
):
|
|
228
|
-
endpoint_id = query_parameters.get("endpoint_id")
|
|
229
|
-
project = query_parameters.get("project")
|
|
230
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
231
|
-
mlrun.api.schemas.AuthorizationResourceTypes.model_endpoint,
|
|
232
|
-
project,
|
|
233
|
-
endpoint_id,
|
|
234
|
-
mlrun.api.schemas.AuthorizationAction.read,
|
|
235
|
-
auth_info,
|
|
236
|
-
)
|
|
237
|
-
|
|
238
|
-
endpoint = await run_in_threadpool(
|
|
239
|
-
mlrun.api.crud.ModelEndpoints().get_model_endpoint,
|
|
240
|
-
auth_info=auth_info,
|
|
241
|
-
project=project,
|
|
242
|
-
endpoint_id=endpoint_id,
|
|
243
|
-
feature_analysis=True,
|
|
244
|
-
)
|
|
100
|
+
return result
|
|
245
101
|
|
|
246
|
-
# Load JSON data from KV, make sure not to fail if a field is missing
|
|
247
|
-
feature_stats = endpoint.status.feature_stats or {}
|
|
248
|
-
current_stats = endpoint.status.current_stats or {}
|
|
249
|
-
drift_measures = endpoint.status.drift_measures or {}
|
|
250
102
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
GrafanaColumn(text="expected_min", type="number"),
|
|
258
|
-
GrafanaColumn(text="expected_mean", type="number"),
|
|
259
|
-
GrafanaColumn(text="expected_max", type="number"),
|
|
260
|
-
GrafanaColumn(text="tvd", type="number"),
|
|
261
|
-
GrafanaColumn(text="hellinger", type="number"),
|
|
262
|
-
GrafanaColumn(text="kld", type="number"),
|
|
103
|
+
@router.post(
|
|
104
|
+
"/query",
|
|
105
|
+
response_model=List[
|
|
106
|
+
Union[
|
|
107
|
+
mlrun.common.schemas.GrafanaTable,
|
|
108
|
+
mlrun.common.schemas.GrafanaTimeSeriesTarget,
|
|
263
109
|
]
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
base_stat.get("max"),
|
|
278
|
-
drift_measure.get("tvd"),
|
|
279
|
-
drift_measure.get("hellinger"),
|
|
280
|
-
drift_measure.get("kld"),
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
return [table]
|
|
284
|
-
|
|
110
|
+
],
|
|
111
|
+
)
|
|
112
|
+
async def grafana_proxy_model_endpoints_query(
|
|
113
|
+
request: Request,
|
|
114
|
+
auth_info: mlrun.common.schemas.AuthInfo = Depends(deps.authenticate_request),
|
|
115
|
+
) -> List[
|
|
116
|
+
Union[
|
|
117
|
+
mlrun.common.schemas.GrafanaTable, mlrun.common.schemas.GrafanaTimeSeriesTarget
|
|
118
|
+
]
|
|
119
|
+
]:
|
|
120
|
+
"""
|
|
121
|
+
Query route for model-endpoints grafana proxy API, used for creating an interface between grafana queries and
|
|
122
|
+
model-endpoints logic.
|
|
285
123
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
290
|
-
):
|
|
291
|
-
endpoint_id = query_parameters.get("endpoint_id")
|
|
292
|
-
project = query_parameters.get("project")
|
|
293
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
294
|
-
mlrun.api.schemas.AuthorizationResourceTypes.model_endpoint,
|
|
295
|
-
project,
|
|
296
|
-
endpoint_id,
|
|
297
|
-
mlrun.api.schemas.AuthorizationAction.read,
|
|
298
|
-
auth_info,
|
|
299
|
-
)
|
|
300
|
-
endpoint = await run_in_threadpool(
|
|
301
|
-
mlrun.api.crud.ModelEndpoints().get_model_endpoint,
|
|
302
|
-
auth_info=auth_info,
|
|
303
|
-
project=project,
|
|
304
|
-
endpoint_id=endpoint_id,
|
|
305
|
-
feature_analysis=True,
|
|
306
|
-
)
|
|
124
|
+
This implementation requires passing target_endpoint query parameter in order to dispatch different
|
|
125
|
+
model-endpoint monitoring functions.
|
|
126
|
+
"""
|
|
307
127
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
GrafanaNumberColumn(text="hellinger_mean"),
|
|
314
|
-
GrafanaNumberColumn(text="kld_sum"),
|
|
315
|
-
GrafanaNumberColumn(text="kld_mean"),
|
|
316
|
-
]
|
|
128
|
+
warnings.warn(
|
|
129
|
+
"This api is deprecated in 1.3.1 and will be removed in 1.5.0. "
|
|
130
|
+
"Please update grafana model monitoring dashboards that use a different data source",
|
|
131
|
+
# TODO: remove in 1.5.0
|
|
132
|
+
FutureWarning,
|
|
317
133
|
)
|
|
318
134
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
endpoint.status.drift_measures.get("tvd_mean"),
|
|
323
|
-
endpoint.status.drift_measures.get("hellinger_sum"),
|
|
324
|
-
endpoint.status.drift_measures.get("hellinger_mean"),
|
|
325
|
-
endpoint.status.drift_measures.get("kld_sum"),
|
|
326
|
-
endpoint.status.drift_measures.get("kld_mean"),
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
return [table]
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
async def grafana_incoming_features(
|
|
333
|
-
body: Dict[str, Any],
|
|
334
|
-
query_parameters: Dict[str, str],
|
|
335
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
336
|
-
):
|
|
337
|
-
endpoint_id = query_parameters.get("endpoint_id")
|
|
338
|
-
project = query_parameters.get("project")
|
|
339
|
-
start = body.get("rangeRaw", {}).get("from", "now-1h")
|
|
340
|
-
end = body.get("rangeRaw", {}).get("to", "now")
|
|
341
|
-
|
|
342
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
343
|
-
mlrun.api.schemas.AuthorizationResourceTypes.model_endpoint,
|
|
344
|
-
project,
|
|
345
|
-
endpoint_id,
|
|
346
|
-
mlrun.api.schemas.AuthorizationAction.read,
|
|
347
|
-
auth_info,
|
|
135
|
+
body = await request.json()
|
|
136
|
+
query_parameters = mlrun.api.crud.model_monitoring.grafana.parse_query_parameters(
|
|
137
|
+
body
|
|
348
138
|
)
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
mlrun.api.crud.ModelEndpoints().get_model_endpoint,
|
|
352
|
-
auth_info=auth_info,
|
|
353
|
-
project=project,
|
|
354
|
-
endpoint_id=endpoint_id,
|
|
139
|
+
mlrun.api.crud.model_monitoring.grafana.validate_query_parameters(
|
|
140
|
+
query_parameters, SUPPORTED_QUERY_FUNCTIONS
|
|
355
141
|
)
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
feature_names = endpoint.spec.feature_names
|
|
360
|
-
|
|
361
|
-
if not feature_names:
|
|
362
|
-
logger.warn(
|
|
363
|
-
"'feature_names' is either missing or not initialized in endpoint record",
|
|
364
|
-
endpoint_id=endpoint.metadata.uid,
|
|
142
|
+
query_parameters = (
|
|
143
|
+
mlrun.api.crud.model_monitoring.grafana.drop_grafana_escape_chars(
|
|
144
|
+
query_parameters
|
|
365
145
|
)
|
|
366
|
-
return time_series
|
|
367
|
-
|
|
368
|
-
path = config.model_endpoint_monitoring.store_prefixes.default.format(
|
|
369
|
-
project=project, kind=mlrun.api.schemas.ModelMonitoringStoreKinds.EVENTS
|
|
370
|
-
)
|
|
371
|
-
_, container, path = parse_model_endpoint_store_prefix(path)
|
|
372
|
-
|
|
373
|
-
client = get_frames_client(
|
|
374
|
-
token=auth_info.data_session,
|
|
375
|
-
address=config.v3io_framesd,
|
|
376
|
-
container=container,
|
|
377
146
|
)
|
|
378
147
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
)
|
|
388
|
-
|
|
389
|
-
data.drop(["endpoint_id"], axis=1, inplace=True, errors="ignore")
|
|
390
|
-
data.index = data.index.astype(np.int64) // 10**6
|
|
391
|
-
|
|
392
|
-
for feature, indexed_values in data.to_dict().items():
|
|
393
|
-
target = GrafanaTimeSeriesTarget(target=feature)
|
|
394
|
-
for index, value in indexed_values.items():
|
|
395
|
-
data_point = GrafanaDataPoint(value=float(value), timestamp=index)
|
|
396
|
-
target.add_data_point(data_point)
|
|
397
|
-
time_series.append(target)
|
|
398
|
-
|
|
399
|
-
return time_series
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
def _parse_query_parameters(request_body: Dict[str, Any]) -> Dict[str, str]:
|
|
403
|
-
"""
|
|
404
|
-
This function searches for the target field in Grafana's SimpleJson json. Once located, the target string is
|
|
405
|
-
parsed by splitting on semi-colons (;). Each part in the resulting list is then split by an equal sign (=) to be
|
|
406
|
-
read as key-value pairs.
|
|
407
|
-
"""
|
|
408
|
-
|
|
409
|
-
# Try to get the target
|
|
410
|
-
targets = request_body.get("targets", [])
|
|
411
|
-
|
|
412
|
-
if len(targets) > 1:
|
|
413
|
-
logger.warn(
|
|
414
|
-
f"The 'targets' list contains more then one element ({len(targets)}), all targets except the first one are "
|
|
415
|
-
f"ignored."
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
target_obj = targets[0] if targets else {}
|
|
419
|
-
target_query = target_obj.get("target") if target_obj else ""
|
|
420
|
-
|
|
421
|
-
if not target_query:
|
|
422
|
-
raise MLRunBadRequestError(f"Target missing in request body:\n {request_body}")
|
|
423
|
-
|
|
424
|
-
parameters = _parse_parameters(target_query)
|
|
425
|
-
|
|
426
|
-
return parameters
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
def _parse_search_parameters(request_body: Dict[str, Any]) -> Dict[str, str]:
|
|
430
|
-
"""
|
|
431
|
-
This function searches for the target field in Grafana's SimpleJson json. Once located, the target string is
|
|
432
|
-
parsed by splitting on semi-colons (;). Each part in the resulting list is then split by an equal sign (=) to be
|
|
433
|
-
read as key-value pairs.
|
|
434
|
-
"""
|
|
435
|
-
|
|
436
|
-
# Try to get the target
|
|
437
|
-
target = request_body.get("target")
|
|
438
|
-
|
|
439
|
-
if not target:
|
|
440
|
-
raise MLRunBadRequestError(f"Target missing in request body:\n {request_body}")
|
|
441
|
-
|
|
442
|
-
parameters = _parse_parameters(target)
|
|
443
|
-
|
|
444
|
-
return parameters
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
def _parse_parameters(target_query):
|
|
448
|
-
parameters = {}
|
|
449
|
-
for query in filter(lambda q: q, target_query.split(";")):
|
|
450
|
-
query_parts = query.split("=")
|
|
451
|
-
if len(query_parts) < 2:
|
|
452
|
-
raise MLRunBadRequestError(
|
|
453
|
-
f"Query must contain both query key and query value. Expected query_key=query_value, found {query} "
|
|
454
|
-
f"instead."
|
|
455
|
-
)
|
|
456
|
-
parameters[query_parts[0]] = query_parts[1]
|
|
457
|
-
return parameters
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
def _drop_grafana_escape_chars(query_parameters: Dict[str, str]):
|
|
461
|
-
query_parameters = dict(query_parameters)
|
|
462
|
-
endpoint_id = query_parameters.get("endpoint_id")
|
|
463
|
-
if endpoint_id is not None:
|
|
464
|
-
query_parameters["endpoint_id"] = endpoint_id.replace("\\", "")
|
|
465
|
-
return query_parameters
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
def _validate_query_parameters(
|
|
469
|
-
query_parameters: Dict[str, str], supported_endpoints: Optional[Set[str]] = None
|
|
470
|
-
):
|
|
471
|
-
"""Validates the parameters sent via Grafana's SimpleJson query"""
|
|
472
|
-
if "target_endpoint" not in query_parameters:
|
|
473
|
-
raise MLRunBadRequestError(
|
|
474
|
-
f"Expected 'target_endpoint' field in query, found {query_parameters} instead"
|
|
475
|
-
)
|
|
476
|
-
|
|
477
|
-
if (
|
|
478
|
-
supported_endpoints is not None
|
|
479
|
-
and query_parameters["target_endpoint"] not in supported_endpoints
|
|
480
|
-
):
|
|
481
|
-
raise MLRunBadRequestError(
|
|
482
|
-
f"{query_parameters['target_endpoint']} unsupported in query parameters: {query_parameters}. "
|
|
483
|
-
f"Currently supports: {','.join(supported_endpoints)}"
|
|
484
|
-
)
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
def _json_loads_or_default(string: Optional[str], default: Any):
|
|
488
|
-
if string is None:
|
|
489
|
-
return default
|
|
490
|
-
obj = json.loads(string)
|
|
491
|
-
if not obj:
|
|
492
|
-
return default
|
|
493
|
-
return obj
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
NAME_TO_QUERY_FUNCTION_DICTIONARY = {
|
|
497
|
-
"list_endpoints": grafana_list_endpoints,
|
|
498
|
-
"individual_feature_analysis": grafana_individual_feature_analysis,
|
|
499
|
-
"overall_feature_analysis": grafana_overall_feature_analysis,
|
|
500
|
-
"incoming_features": grafana_incoming_features,
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
NAME_TO_SEARCH_FUNCTION_DICTIONARY = {
|
|
504
|
-
"list_projects": grafana_list_projects,
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
SUPPORTED_QUERY_FUNCTIONS = set(NAME_TO_QUERY_FUNCTION_DICTIONARY.keys())
|
|
508
|
-
SUPPORTED_SEARCH_FUNCTIONS = set(NAME_TO_SEARCH_FUNCTION_DICTIONARY)
|
|
148
|
+
# At this point everything is validated and we can access everything that is needed without performing all previous
|
|
149
|
+
# checks again.
|
|
150
|
+
target_endpoint = query_parameters["target_endpoint"]
|
|
151
|
+
function = NAME_TO_QUERY_FUNCTION_DICTIONARY[target_endpoint]
|
|
152
|
+
if asyncio.iscoroutinefunction(function):
|
|
153
|
+
return await function(body, query_parameters, auth_info)
|
|
154
|
+
result = await run_in_threadpool(function, body, query_parameters, auth_info)
|
|
155
|
+
return result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2023 Iguazio
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -12,20 +12,33 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
|
+
import http
|
|
16
|
+
|
|
15
17
|
from fastapi import APIRouter
|
|
16
18
|
|
|
17
|
-
import mlrun.
|
|
18
|
-
|
|
19
|
+
import mlrun.common.schemas
|
|
20
|
+
from mlrun.config import config as mlconfig
|
|
19
21
|
|
|
20
22
|
router = APIRouter()
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
@router.get(
|
|
24
26
|
"/healthz",
|
|
25
|
-
|
|
27
|
+
status_code=http.HTTPStatus.OK.value,
|
|
26
28
|
)
|
|
27
29
|
def health():
|
|
28
30
|
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
|
|
31
|
+
# offline is the initial state
|
|
32
|
+
# waiting for chief is set for workers waiting for chief to be ready and then clusterize against it
|
|
33
|
+
if mlconfig.httpdb.state in [
|
|
34
|
+
mlrun.common.schemas.APIStates.offline,
|
|
35
|
+
mlrun.common.schemas.APIStates.waiting_for_chief,
|
|
36
|
+
]:
|
|
37
|
+
raise mlrun.errors.MLRunServiceUnavailableError()
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
# for old `align_mlrun.sh` scripts expecting `version` in the response
|
|
41
|
+
# TODO: remove on mlrun >= 1.6.0
|
|
42
|
+
"version": mlconfig.version,
|
|
43
|
+
"status": "ok",
|
|
44
|
+
}
|