mlrun 1.3.3rc1__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.3rc1.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.3rc1.dist-info/RECORD +0 -381
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/LICENSE +0 -0
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/WHEEL +0 -0
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/top_level.txt +0 -0
mlrun/kfpops.py
CHANGED
|
@@ -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.
|
|
@@ -18,6 +18,7 @@ import os.path
|
|
|
18
18
|
from copy import deepcopy
|
|
19
19
|
from typing import Dict, List, Union
|
|
20
20
|
|
|
21
|
+
import inflection
|
|
21
22
|
from kfp import dsl
|
|
22
23
|
from kubernetes import client as k8s_client
|
|
23
24
|
|
|
@@ -226,7 +227,7 @@ def mlrun_op(
|
|
|
226
227
|
:param labels: labels to tag the job/run with ({key:val, ..})
|
|
227
228
|
:param inputs: dictionary of input objects + optional paths (if path is
|
|
228
229
|
omitted the path will be the in_path/key.
|
|
229
|
-
:param outputs: dictionary of
|
|
230
|
+
:param outputs: dictionary of output objects + optional paths (if path is
|
|
230
231
|
omitted the path will be the out_path/key.
|
|
231
232
|
:param in_path: default input path/url (prefix) for inputs
|
|
232
233
|
:param out_path: default output path/url (prefix) for artifacts
|
|
@@ -712,6 +713,14 @@ def generate_kfp_dag_and_resolve_project(run, project=None):
|
|
|
712
713
|
record = {
|
|
713
714
|
k: node[k] for k in ["phase", "startedAt", "finishedAt", "type", "id"]
|
|
714
715
|
}
|
|
716
|
+
|
|
717
|
+
# snake case
|
|
718
|
+
# align kfp fields to mlrun snake case convention
|
|
719
|
+
# create snake_case for consistency.
|
|
720
|
+
# retain the camelCase for compatibility
|
|
721
|
+
for key in list(record.keys()):
|
|
722
|
+
record[inflection.underscore(key)] = record[key]
|
|
723
|
+
|
|
715
724
|
record["parent"] = node.get("boundaryID", "")
|
|
716
725
|
record["name"] = name
|
|
717
726
|
record["children"] = node.get("children", [])
|
|
@@ -747,21 +756,9 @@ def format_summary_from_kfp_run(kfp_run, project=None, session=None):
|
|
|
747
756
|
if error:
|
|
748
757
|
dag[step]["error"] = error
|
|
749
758
|
|
|
750
|
-
short_run = {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
for k, v in kfp_run["run"].items()
|
|
754
|
-
if k
|
|
755
|
-
in [
|
|
756
|
-
"id",
|
|
757
|
-
"name",
|
|
758
|
-
"status",
|
|
759
|
-
"error",
|
|
760
|
-
"created_at",
|
|
761
|
-
"scheduled_at",
|
|
762
|
-
"finished_at",
|
|
763
|
-
"description",
|
|
764
|
-
]
|
|
759
|
+
short_run = {
|
|
760
|
+
"graph": dag,
|
|
761
|
+
"run": mlrun.utils.helpers.format_run(kfp_run["run"]),
|
|
765
762
|
}
|
|
766
763
|
short_run["run"]["project"] = project
|
|
767
764
|
short_run["run"]["message"] = message
|
|
@@ -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.
|
mlrun/launcher/base.py
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
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.
|
|
14
|
+
import abc
|
|
15
|
+
import ast
|
|
16
|
+
import copy
|
|
17
|
+
import os
|
|
18
|
+
import uuid
|
|
19
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
20
|
+
|
|
21
|
+
import mlrun.common.schemas
|
|
22
|
+
import mlrun.config
|
|
23
|
+
import mlrun.errors
|
|
24
|
+
import mlrun.kfpops
|
|
25
|
+
import mlrun.lists
|
|
26
|
+
import mlrun.model
|
|
27
|
+
import mlrun.runtimes
|
|
28
|
+
from mlrun.utils import logger
|
|
29
|
+
|
|
30
|
+
run_modes = ["pass"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class BaseLauncher(abc.ABC):
|
|
34
|
+
"""
|
|
35
|
+
Abstract class for managing and running functions in different contexts
|
|
36
|
+
This class is designed to encapsulate the logic of running a function in different contexts
|
|
37
|
+
i.e. running a function locally, remotely or in a server
|
|
38
|
+
Each context will have its own implementation of the abstract methods while the common logic resides in this class
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def save_function(
|
|
42
|
+
self,
|
|
43
|
+
runtime: "mlrun.runtimes.BaseRuntime",
|
|
44
|
+
tag: str = "",
|
|
45
|
+
versioned: bool = False,
|
|
46
|
+
refresh: bool = False,
|
|
47
|
+
) -> str:
|
|
48
|
+
"""
|
|
49
|
+
store the function to the db
|
|
50
|
+
:param runtime: runtime object
|
|
51
|
+
:param tag: function tag to store
|
|
52
|
+
:param versioned: whether we want to version this function object so that it will queryable by its hash key
|
|
53
|
+
:param refresh: refresh function metadata
|
|
54
|
+
|
|
55
|
+
:return: function uri
|
|
56
|
+
"""
|
|
57
|
+
db = runtime._get_db()
|
|
58
|
+
if not db:
|
|
59
|
+
raise mlrun.errors.MLRunPreconditionFailedError(
|
|
60
|
+
"Database connection is not configured"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
if refresh:
|
|
64
|
+
self._refresh_function_metadata(runtime)
|
|
65
|
+
|
|
66
|
+
tag = tag or runtime.metadata.tag
|
|
67
|
+
|
|
68
|
+
obj = runtime.to_dict()
|
|
69
|
+
logger.debug("Saving function", runtime_name=runtime.metadata.name, tag=tag)
|
|
70
|
+
hash_key = db.store_function(
|
|
71
|
+
obj, runtime.metadata.name, runtime.metadata.project, tag, versioned
|
|
72
|
+
)
|
|
73
|
+
hash_key = hash_key if versioned else None
|
|
74
|
+
return "db://" + runtime._function_uri(hash_key=hash_key, tag=tag)
|
|
75
|
+
|
|
76
|
+
@abc.abstractmethod
|
|
77
|
+
def launch(
|
|
78
|
+
self,
|
|
79
|
+
runtime: "mlrun.runtimes.BaseRuntime",
|
|
80
|
+
task: Optional[
|
|
81
|
+
Union["mlrun.run.RunTemplate", "mlrun.run.RunObject", dict]
|
|
82
|
+
] = None,
|
|
83
|
+
handler: Optional[Union[str, Callable]] = None,
|
|
84
|
+
name: Optional[str] = "",
|
|
85
|
+
project: Optional[str] = "",
|
|
86
|
+
params: Optional[dict] = None,
|
|
87
|
+
inputs: Optional[Dict[str, str]] = None,
|
|
88
|
+
out_path: Optional[str] = "",
|
|
89
|
+
workdir: Optional[str] = "",
|
|
90
|
+
artifact_path: Optional[str] = "",
|
|
91
|
+
watch: Optional[bool] = True,
|
|
92
|
+
schedule: Optional[
|
|
93
|
+
Union[str, mlrun.common.schemas.schedule.ScheduleCronTrigger]
|
|
94
|
+
] = None,
|
|
95
|
+
hyperparams: Dict[str, list] = None,
|
|
96
|
+
hyper_param_options: Optional[mlrun.model.HyperParamOptions] = None,
|
|
97
|
+
verbose: Optional[bool] = None,
|
|
98
|
+
scrape_metrics: Optional[bool] = None,
|
|
99
|
+
local_code_path: Optional[str] = None,
|
|
100
|
+
auto_build: Optional[bool] = None,
|
|
101
|
+
param_file_secrets: Optional[Dict[str, str]] = None,
|
|
102
|
+
notifications: Optional[List[mlrun.model.Notification]] = None,
|
|
103
|
+
returns: Optional[List[Union[str, Dict[str, str]]]] = None,
|
|
104
|
+
) -> "mlrun.run.RunObject":
|
|
105
|
+
"""run the function from the server/client[local/remote]"""
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
def _validate_runtime(
|
|
109
|
+
self,
|
|
110
|
+
runtime: "mlrun.runtimes.BaseRuntime",
|
|
111
|
+
run: "mlrun.run.RunObject",
|
|
112
|
+
):
|
|
113
|
+
mlrun.utils.helpers.verify_dict_items_type(
|
|
114
|
+
"Inputs", run.spec.inputs, [str], [str]
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if runtime.spec.mode and runtime.spec.mode not in run_modes:
|
|
118
|
+
raise ValueError(f'run mode can only be {",".join(run_modes)}')
|
|
119
|
+
|
|
120
|
+
self._validate_run_params(run.spec.parameters)
|
|
121
|
+
self._validate_output_path(runtime, run)
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def _validate_output_path(
|
|
125
|
+
runtime: "mlrun.runtimes.BaseRuntime",
|
|
126
|
+
run: "mlrun.run.RunObject",
|
|
127
|
+
):
|
|
128
|
+
if not run.spec.output_path or "://" not in run.spec.output_path:
|
|
129
|
+
message = ""
|
|
130
|
+
if not os.path.isabs(run.spec.output_path):
|
|
131
|
+
message = (
|
|
132
|
+
"artifact/output path is not defined or is local and relative,"
|
|
133
|
+
" artifacts will not be visible in the UI"
|
|
134
|
+
)
|
|
135
|
+
if mlrun.runtimes.RuntimeKinds.requires_absolute_artifacts_path(
|
|
136
|
+
runtime.kind
|
|
137
|
+
):
|
|
138
|
+
raise mlrun.errors.MLRunPreconditionFailedError(
|
|
139
|
+
"artifact path (`artifact_path`) must be absolute for remote tasks"
|
|
140
|
+
)
|
|
141
|
+
elif (
|
|
142
|
+
hasattr(runtime.spec, "volume_mounts")
|
|
143
|
+
and not runtime.spec.volume_mounts
|
|
144
|
+
):
|
|
145
|
+
message = (
|
|
146
|
+
"artifact output path is local while no volume mount is specified. "
|
|
147
|
+
"artifacts would not be visible via UI."
|
|
148
|
+
)
|
|
149
|
+
if message:
|
|
150
|
+
logger.warning(message, output_path=run.spec.output_path)
|
|
151
|
+
|
|
152
|
+
def _validate_run_params(self, parameters: Dict[str, Any]):
|
|
153
|
+
for param_name, param_value in parameters.items():
|
|
154
|
+
|
|
155
|
+
if isinstance(param_value, dict):
|
|
156
|
+
# if the parameter is a dict, we might have some nested parameters,
|
|
157
|
+
# in this case we need to verify them as well recursively
|
|
158
|
+
self._validate_run_params(param_value)
|
|
159
|
+
|
|
160
|
+
# verify that integer parameters don't exceed a int64
|
|
161
|
+
if isinstance(param_value, int) and abs(param_value) >= 2**63:
|
|
162
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
163
|
+
f"parameter {param_name} value {param_value} exceeds int64"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
@staticmethod
|
|
167
|
+
def _create_run_object(task):
|
|
168
|
+
valid_task_types = (dict, mlrun.run.RunTemplate, mlrun.run.RunObject)
|
|
169
|
+
|
|
170
|
+
if not task:
|
|
171
|
+
# if task passed generate default RunObject
|
|
172
|
+
return mlrun.run.RunObject.from_dict(task)
|
|
173
|
+
|
|
174
|
+
# deepcopy user's task, so we don't modify / enrich the user's object
|
|
175
|
+
task = copy.deepcopy(task)
|
|
176
|
+
|
|
177
|
+
if isinstance(task, str):
|
|
178
|
+
task = ast.literal_eval(task)
|
|
179
|
+
|
|
180
|
+
if not isinstance(task, valid_task_types):
|
|
181
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
182
|
+
f"Task is not a valid object, type={type(task)}, expected types={valid_task_types}"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
if isinstance(task, mlrun.run.RunTemplate):
|
|
186
|
+
return mlrun.run.RunObject.from_template(task)
|
|
187
|
+
elif isinstance(task, dict):
|
|
188
|
+
return mlrun.run.RunObject.from_dict(task)
|
|
189
|
+
|
|
190
|
+
# task is already a RunObject
|
|
191
|
+
return task
|
|
192
|
+
|
|
193
|
+
def _enrich_run(
|
|
194
|
+
self,
|
|
195
|
+
runtime,
|
|
196
|
+
run,
|
|
197
|
+
handler=None,
|
|
198
|
+
project_name=None,
|
|
199
|
+
name=None,
|
|
200
|
+
params=None,
|
|
201
|
+
inputs=None,
|
|
202
|
+
returns=None,
|
|
203
|
+
hyperparams=None,
|
|
204
|
+
hyper_param_options=None,
|
|
205
|
+
verbose=None,
|
|
206
|
+
scrape_metrics=None,
|
|
207
|
+
out_path=None,
|
|
208
|
+
artifact_path=None,
|
|
209
|
+
workdir=None,
|
|
210
|
+
notifications: List[mlrun.model.Notification] = None,
|
|
211
|
+
):
|
|
212
|
+
run.spec.handler = (
|
|
213
|
+
handler or run.spec.handler or runtime.spec.default_handler or ""
|
|
214
|
+
)
|
|
215
|
+
# callable handlers are valid for handler and dask runtimes,
|
|
216
|
+
# for other runtimes we need to convert the handler to a string
|
|
217
|
+
if run.spec.handler and runtime.kind not in ["handler", "dask"]:
|
|
218
|
+
run.spec.handler = run.spec.handler_name
|
|
219
|
+
|
|
220
|
+
def_name = runtime.metadata.name
|
|
221
|
+
if run.spec.handler_name:
|
|
222
|
+
short_name = run.spec.handler_name
|
|
223
|
+
for separator in ["#", "::", "."]:
|
|
224
|
+
# drop paths, module or class name from short name
|
|
225
|
+
if separator in short_name:
|
|
226
|
+
short_name = short_name.split(separator)[-1]
|
|
227
|
+
def_name += "-" + short_name
|
|
228
|
+
|
|
229
|
+
run.metadata.name = mlrun.utils.normalize_name(
|
|
230
|
+
name=name or run.metadata.name or def_name,
|
|
231
|
+
# if name or runspec.metadata.name are set then it means that is user defined name and we want to warn the
|
|
232
|
+
# user that the passed name needs to be set without underscore, if its not user defined but rather enriched
|
|
233
|
+
# from the handler(function) name then we replace the underscore without warning the user.
|
|
234
|
+
# most of the time handlers will have `_` in the handler name (python convention is to separate function
|
|
235
|
+
# words with `_`), therefore we don't want to be noisy when normalizing the run name
|
|
236
|
+
verbose=bool(name or run.metadata.name),
|
|
237
|
+
)
|
|
238
|
+
mlrun.utils.verify_field_regex(
|
|
239
|
+
"run.metadata.name", run.metadata.name, mlrun.utils.regex.run_name
|
|
240
|
+
)
|
|
241
|
+
run.metadata.project = (
|
|
242
|
+
project_name
|
|
243
|
+
or run.metadata.project
|
|
244
|
+
or runtime.metadata.project
|
|
245
|
+
or mlrun.mlconf.default_project
|
|
246
|
+
)
|
|
247
|
+
run.spec.parameters = params or run.spec.parameters
|
|
248
|
+
run.spec.inputs = inputs or run.spec.inputs
|
|
249
|
+
run.spec.returns = returns or run.spec.returns
|
|
250
|
+
run.spec.hyperparams = hyperparams or run.spec.hyperparams
|
|
251
|
+
run.spec.hyper_param_options = (
|
|
252
|
+
hyper_param_options or run.spec.hyper_param_options
|
|
253
|
+
)
|
|
254
|
+
run.spec.verbose = verbose or run.spec.verbose
|
|
255
|
+
if scrape_metrics is None:
|
|
256
|
+
if run.spec.scrape_metrics is None:
|
|
257
|
+
scrape_metrics = mlrun.mlconf.scrape_metrics
|
|
258
|
+
else:
|
|
259
|
+
scrape_metrics = run.spec.scrape_metrics
|
|
260
|
+
run.spec.scrape_metrics = scrape_metrics
|
|
261
|
+
run.spec.input_path = workdir or run.spec.input_path or runtime.spec.workdir
|
|
262
|
+
if runtime.spec.allow_empty_resources:
|
|
263
|
+
run.spec.allow_empty_resources = runtime.spec.allow_empty_resources
|
|
264
|
+
|
|
265
|
+
spec = run.spec
|
|
266
|
+
if spec.secret_sources:
|
|
267
|
+
runtime._secrets = mlrun.secrets.SecretsStore.from_list(spec.secret_sources)
|
|
268
|
+
|
|
269
|
+
# update run metadata (uid, labels) and store in DB
|
|
270
|
+
meta = run.metadata
|
|
271
|
+
meta.uid = meta.uid or uuid.uuid4().hex
|
|
272
|
+
|
|
273
|
+
run.spec.output_path = out_path or artifact_path or run.spec.output_path
|
|
274
|
+
|
|
275
|
+
if not run.spec.output_path:
|
|
276
|
+
if run.metadata.project:
|
|
277
|
+
if (
|
|
278
|
+
mlrun.pipeline_context.project
|
|
279
|
+
and run.metadata.project
|
|
280
|
+
== mlrun.pipeline_context.project.metadata.name
|
|
281
|
+
):
|
|
282
|
+
run.spec.output_path = (
|
|
283
|
+
mlrun.pipeline_context.project.spec.artifact_path
|
|
284
|
+
or mlrun.pipeline_context.workflow_artifact_path
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
# get_db might be None when no rundb is set on runtime
|
|
288
|
+
if not run.spec.output_path and runtime._get_db():
|
|
289
|
+
try:
|
|
290
|
+
# not passing or loading the DB before the enrichment on purpose, because we want to enrich the
|
|
291
|
+
# spec first as get_db() depends on it
|
|
292
|
+
project = runtime._get_db().get_project(run.metadata.project)
|
|
293
|
+
# this is mainly for tests, so we won't need to mock get_project for so many tests
|
|
294
|
+
# in normal use cases if no project is found we will get an error
|
|
295
|
+
if project:
|
|
296
|
+
run.spec.output_path = project.spec.artifact_path
|
|
297
|
+
except mlrun.errors.MLRunNotFoundError:
|
|
298
|
+
logger.warning(
|
|
299
|
+
f"project {project_name} is not saved in DB yet, "
|
|
300
|
+
f"enriching output path with default artifact path: {mlrun.mlconf.artifact_path}"
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
if not run.spec.output_path:
|
|
304
|
+
run.spec.output_path = mlrun.mlconf.artifact_path
|
|
305
|
+
|
|
306
|
+
if run.spec.output_path:
|
|
307
|
+
run.spec.output_path = run.spec.output_path.replace("{{run.uid}}", meta.uid)
|
|
308
|
+
run.spec.output_path = mlrun.utils.helpers.fill_artifact_path_template(
|
|
309
|
+
run.spec.output_path, run.metadata.project
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
notifications = notifications or run.spec.notifications or []
|
|
313
|
+
mlrun.model.Notification.validate_notification_uniqueness(notifications)
|
|
314
|
+
for notification in notifications:
|
|
315
|
+
notification.validate_notification()
|
|
316
|
+
|
|
317
|
+
run.spec.notifications = notifications
|
|
318
|
+
|
|
319
|
+
return run
|
|
320
|
+
|
|
321
|
+
@staticmethod
|
|
322
|
+
def _run_has_valid_notifications(runobj) -> bool:
|
|
323
|
+
if not runobj.spec.notifications:
|
|
324
|
+
logger.debug(
|
|
325
|
+
"No notifications to push for run", run_uid=runobj.metadata.uid
|
|
326
|
+
)
|
|
327
|
+
return False
|
|
328
|
+
|
|
329
|
+
# TODO: add support for other notifications per run iteration
|
|
330
|
+
if runobj.metadata.iteration and runobj.metadata.iteration > 0:
|
|
331
|
+
logger.debug(
|
|
332
|
+
"Notifications per iteration are not supported, skipping",
|
|
333
|
+
run_uid=runobj.metadata.uid,
|
|
334
|
+
)
|
|
335
|
+
return False
|
|
336
|
+
|
|
337
|
+
return True
|
|
338
|
+
|
|
339
|
+
def _wrap_run_result(
|
|
340
|
+
self,
|
|
341
|
+
runtime: "mlrun.runtimes.BaseRuntime",
|
|
342
|
+
result: dict,
|
|
343
|
+
run: "mlrun.run.RunObject",
|
|
344
|
+
schedule: Optional[mlrun.common.schemas.ScheduleCronTrigger] = None,
|
|
345
|
+
err: Optional[Exception] = None,
|
|
346
|
+
):
|
|
347
|
+
# if the purpose was to schedule (and not to run) nothing to wrap
|
|
348
|
+
if schedule:
|
|
349
|
+
return
|
|
350
|
+
|
|
351
|
+
if result and runtime.kfp and err is None:
|
|
352
|
+
mlrun.kfpops.write_kfpmeta(result)
|
|
353
|
+
|
|
354
|
+
self._log_track_results(runtime, result, run)
|
|
355
|
+
|
|
356
|
+
if result:
|
|
357
|
+
run = mlrun.run.RunObject.from_dict(result)
|
|
358
|
+
logger.info(
|
|
359
|
+
"Run execution finished",
|
|
360
|
+
status=run.status.state,
|
|
361
|
+
name=run.metadata.name,
|
|
362
|
+
)
|
|
363
|
+
if run.status.state in [
|
|
364
|
+
mlrun.runtimes.base.RunStates.error,
|
|
365
|
+
mlrun.runtimes.base.RunStates.aborted,
|
|
366
|
+
]:
|
|
367
|
+
if runtime._is_remote and not runtime.is_child:
|
|
368
|
+
logger.error(
|
|
369
|
+
"Run did not finish successfully",
|
|
370
|
+
state=run.status.state,
|
|
371
|
+
status=run.status.to_dict(),
|
|
372
|
+
)
|
|
373
|
+
raise mlrun.runtimes.utils.RunError(run.error)
|
|
374
|
+
return run
|
|
375
|
+
|
|
376
|
+
return None
|
|
377
|
+
|
|
378
|
+
@staticmethod
|
|
379
|
+
def _refresh_function_metadata(runtime: "mlrun.runtimes.BaseRuntime"):
|
|
380
|
+
pass
|
|
381
|
+
|
|
382
|
+
@staticmethod
|
|
383
|
+
def prepare_image_for_deploy(runtime: "mlrun.runtimes.BaseRuntime"):
|
|
384
|
+
"""Check if the runtime requires to build the image and updates the spec accordingly"""
|
|
385
|
+
pass
|
|
386
|
+
|
|
387
|
+
@staticmethod
|
|
388
|
+
@abc.abstractmethod
|
|
389
|
+
def enrich_runtime(
|
|
390
|
+
runtime: "mlrun.runtimes.base.BaseRuntime",
|
|
391
|
+
project_name: Optional[str] = "",
|
|
392
|
+
):
|
|
393
|
+
pass
|
|
394
|
+
|
|
395
|
+
@staticmethod
|
|
396
|
+
@abc.abstractmethod
|
|
397
|
+
def _store_function(
|
|
398
|
+
runtime: "mlrun.runtimes.BaseRuntime", run: "mlrun.run.RunObject"
|
|
399
|
+
):
|
|
400
|
+
pass
|
|
401
|
+
|
|
402
|
+
@staticmethod
|
|
403
|
+
def _log_track_results(
|
|
404
|
+
runtime: "mlrun.runtimes.BaseRuntime", result: dict, run: "mlrun.run.RunObject"
|
|
405
|
+
):
|
|
406
|
+
pass
|
mlrun/launcher/client.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
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.
|
|
14
|
+
import abc
|
|
15
|
+
import getpass
|
|
16
|
+
import os
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
import IPython
|
|
20
|
+
|
|
21
|
+
import mlrun.errors
|
|
22
|
+
import mlrun.launcher.base
|
|
23
|
+
import mlrun.lists
|
|
24
|
+
import mlrun.model
|
|
25
|
+
import mlrun.runtimes
|
|
26
|
+
from mlrun.utils import logger
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ClientBaseLauncher(mlrun.launcher.base.BaseLauncher, abc.ABC):
|
|
30
|
+
"""
|
|
31
|
+
Abstract class for common code between client launchers
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def enrich_runtime(
|
|
36
|
+
runtime: "mlrun.runtimes.base.BaseRuntime", project_name: Optional[str] = ""
|
|
37
|
+
):
|
|
38
|
+
runtime.try_auto_mount_based_on_config()
|
|
39
|
+
runtime._fill_credentials()
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def prepare_image_for_deploy(runtime: "mlrun.runtimes.BaseRuntime"):
|
|
43
|
+
"""
|
|
44
|
+
Check if the runtime requires to build the image.
|
|
45
|
+
If build is needed, set the image as the base_image for the build.
|
|
46
|
+
If image is not given set the default one.
|
|
47
|
+
"""
|
|
48
|
+
if runtime.kind in mlrun.runtimes.RuntimeKinds.nuclio_runtimes():
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
build = runtime.spec.build
|
|
52
|
+
require_build = (
|
|
53
|
+
build.commands
|
|
54
|
+
or build.requirements
|
|
55
|
+
or (build.source and not build.load_source_on_run)
|
|
56
|
+
)
|
|
57
|
+
image = runtime.spec.image
|
|
58
|
+
# we allow users to not set an image, in that case we'll use the default
|
|
59
|
+
if (
|
|
60
|
+
not image
|
|
61
|
+
and runtime.kind in mlrun.mlconf.function_defaults.image_by_kind.to_dict()
|
|
62
|
+
):
|
|
63
|
+
image = mlrun.mlconf.function_defaults.image_by_kind.to_dict()[runtime.kind]
|
|
64
|
+
|
|
65
|
+
# TODO: need a better way to decide whether a function requires a build
|
|
66
|
+
if require_build and image and not runtime.spec.build.base_image:
|
|
67
|
+
# when the function require build use the image as the base_image for the build
|
|
68
|
+
runtime.spec.build.base_image = image
|
|
69
|
+
runtime.spec.image = ""
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def _store_function(
|
|
73
|
+
runtime: "mlrun.runtimes.BaseRuntime", run: "mlrun.run.RunObject"
|
|
74
|
+
):
|
|
75
|
+
run.metadata.labels["kind"] = runtime.kind
|
|
76
|
+
if "owner" not in run.metadata.labels:
|
|
77
|
+
run.metadata.labels["owner"] = (
|
|
78
|
+
os.environ.get("V3IO_USERNAME") or getpass.getuser()
|
|
79
|
+
)
|
|
80
|
+
if run.spec.output_path:
|
|
81
|
+
run.spec.output_path = run.spec.output_path.replace(
|
|
82
|
+
"{{run.user}}", run.metadata.labels["owner"]
|
|
83
|
+
)
|
|
84
|
+
db = runtime._get_db()
|
|
85
|
+
if db and runtime.kind != "handler":
|
|
86
|
+
struct = runtime.to_dict()
|
|
87
|
+
hash_key = db.store_function(
|
|
88
|
+
struct, runtime.metadata.name, runtime.metadata.project, versioned=True
|
|
89
|
+
)
|
|
90
|
+
run.spec.function = runtime._function_uri(hash_key=hash_key)
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def _refresh_function_metadata(runtime: "mlrun.runtimes.BaseRuntime"):
|
|
94
|
+
try:
|
|
95
|
+
meta = runtime.metadata
|
|
96
|
+
db = runtime._get_db()
|
|
97
|
+
db_func = db.get_function(meta.name, meta.project, meta.tag)
|
|
98
|
+
if db_func and "status" in db_func:
|
|
99
|
+
runtime.status = db_func["status"]
|
|
100
|
+
if (
|
|
101
|
+
runtime.status.state
|
|
102
|
+
and runtime.status.state == "ready"
|
|
103
|
+
and runtime.kind
|
|
104
|
+
# We don't want to override the nuclio image here because the build happens in nuclio
|
|
105
|
+
# TODO: have a better way to check if nuclio function deploy started
|
|
106
|
+
and not hasattr(runtime.status, "nuclio_name")
|
|
107
|
+
):
|
|
108
|
+
runtime.spec.image = mlrun.utils.get_in(
|
|
109
|
+
db_func, "spec.image", runtime.spec.image
|
|
110
|
+
)
|
|
111
|
+
except mlrun.errors.MLRunNotFoundError:
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def _log_track_results(
|
|
116
|
+
runtime: "mlrun.runtimes.BaseRuntime", result: dict, run: "mlrun.run.RunObject"
|
|
117
|
+
):
|
|
118
|
+
"""
|
|
119
|
+
log commands to track results
|
|
120
|
+
in jupyter, displays a table widget with the result
|
|
121
|
+
else, logs CLI commands to track results and a link to the results in UI
|
|
122
|
+
|
|
123
|
+
:param: runtime: runtime object
|
|
124
|
+
:param result: run result dict
|
|
125
|
+
:param run: run object
|
|
126
|
+
"""
|
|
127
|
+
uid = run.metadata.uid
|
|
128
|
+
project = run.metadata.project
|
|
129
|
+
|
|
130
|
+
# show ipython/jupyter result table widget
|
|
131
|
+
results_tbl = mlrun.lists.RunList()
|
|
132
|
+
if result:
|
|
133
|
+
results_tbl.append(result)
|
|
134
|
+
else:
|
|
135
|
+
logger.info("no returned result (job may still be in progress)")
|
|
136
|
+
results_tbl.append(run.to_dict())
|
|
137
|
+
|
|
138
|
+
if mlrun.utils.is_ipython and mlrun.config.config.ipython_widget:
|
|
139
|
+
results_tbl.show()
|
|
140
|
+
print()
|
|
141
|
+
ui_url = mlrun.utils.get_ui_url(project, uid)
|
|
142
|
+
if ui_url:
|
|
143
|
+
ui_url = f' or <a href="{ui_url}" target="_blank">click here</a> to open in UI'
|
|
144
|
+
IPython.display.display(
|
|
145
|
+
IPython.display.HTML(
|
|
146
|
+
f"<b> > to track results use the .show() or .logs() methods {ui_url}</b>"
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
elif not runtime.is_child:
|
|
150
|
+
# TODO: Log sdk commands to track results instead of CLI commands
|
|
151
|
+
project_flag = f"-p {project}" if project else ""
|
|
152
|
+
info_cmd = f"mlrun get run {uid} {project_flag}"
|
|
153
|
+
logs_cmd = f"mlrun logs {uid} {project_flag}"
|
|
154
|
+
logger.info(
|
|
155
|
+
"To track results use the CLI", info_cmd=info_cmd, logs_cmd=logs_cmd
|
|
156
|
+
)
|
|
157
|
+
ui_url = mlrun.utils.get_ui_url(project, uid)
|
|
158
|
+
if ui_url:
|
|
159
|
+
logger.info("Or click for UI", ui_url=ui_url)
|
|
@@ -0,0 +1,50 @@
|
|
|
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.
|
|
14
|
+
import mlrun.config
|
|
15
|
+
import mlrun.errors
|
|
16
|
+
import mlrun.launcher.base
|
|
17
|
+
import mlrun.launcher.local
|
|
18
|
+
import mlrun.launcher.remote
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LauncherFactory(object):
|
|
22
|
+
@staticmethod
|
|
23
|
+
def create_launcher(
|
|
24
|
+
is_remote: bool, local: bool = False
|
|
25
|
+
) -> mlrun.launcher.base.BaseLauncher:
|
|
26
|
+
"""
|
|
27
|
+
Creates the appropriate launcher for the specified run.
|
|
28
|
+
ServerSideLauncher - if running as API.
|
|
29
|
+
ClientRemoteLauncher - if the run is remote and local was not specified.
|
|
30
|
+
ClientLocalLauncher - if the run is not remote or local was specified.
|
|
31
|
+
|
|
32
|
+
:param is_remote: Whether the runtime requires remote execution.
|
|
33
|
+
:param local: Run the function locally vs on the Runtime/Cluster
|
|
34
|
+
|
|
35
|
+
:return: The appropriate launcher for the specified run.
|
|
36
|
+
"""
|
|
37
|
+
if mlrun.config.is_running_as_api():
|
|
38
|
+
if local:
|
|
39
|
+
raise mlrun.errors.MLRunInternalServerError(
|
|
40
|
+
"Launch of local run inside the server is not allowed"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
from mlrun.api.launcher import ServerSideLauncher
|
|
44
|
+
|
|
45
|
+
return ServerSideLauncher()
|
|
46
|
+
|
|
47
|
+
if is_remote and not local:
|
|
48
|
+
return mlrun.launcher.remote.ClientRemoteLauncher()
|
|
49
|
+
|
|
50
|
+
return mlrun.launcher.local.ClientLocalLauncher(local)
|