mage-ai 0.9.67__py3-none-any.whl → 0.9.69__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 mage-ai might be problematic. Click here for more details.
- mage_ai/api/monitors/BaseMonitor.py +1 -2
- mage_ai/api/policies/PipelinePolicy.py +2 -0
- mage_ai/api/resources/BlockLayoutItemResource.py +2 -2
- mage_ai/api/resources/BlockResource.py +4 -3
- mage_ai/api/resources/CacheItemResource.py +1 -1
- mage_ai/api/resources/GitBranchResource.py +3 -5
- mage_ai/api/resources/PageBlockLayoutResource.py +2 -2
- mage_ai/api/resources/PipelineResource.py +13 -0
- mage_ai/api/resources/PipelineRunResource.py +10 -1
- mage_ai/api/resources/SeedResource.py +2 -1
- mage_ai/api/resources/SessionResource.py +13 -1
- mage_ai/authentication/permissions/constants.py +2 -0
- mage_ai/authentication/permissions/seed.py +32 -21
- mage_ai/authentication/providers/active_directory.py +4 -3
- mage_ai/authentication/providers/okta.py +22 -83
- mage_ai/cache/tag.py +3 -0
- mage_ai/cluster_manager/manage.py +4 -1
- mage_ai/data_preparation/executors/k8s_block_executor.py +8 -1
- mage_ai/data_preparation/executors/k8s_pipeline_executor.py +12 -1
- mage_ai/data_preparation/executors/streaming_pipeline_executor.py +77 -7
- mage_ai/data_preparation/logging/gcs_logger_manager.py +7 -4
- mage_ai/data_preparation/models/block/__init__.py +28 -71
- mage_ai/data_preparation/models/block/block_factory.py +77 -0
- mage_ai/data_preparation/models/block/data_integration/mixins.py +16 -5
- mage_ai/data_preparation/models/block/dbt/block.py +5 -7
- mage_ai/data_preparation/models/block/dynamic/child.py +3 -0
- mage_ai/data_preparation/models/block/dynamic/variables.py +2 -2
- mage_ai/data_preparation/models/block/extension/utils.py +1 -0
- mage_ai/data_preparation/models/block/global_data_product/__init__.py +9 -3
- mage_ai/data_preparation/models/block/integration/__init__.py +13 -9
- mage_ai/data_preparation/models/block/platform/mixins.py +1 -1
- mage_ai/data_preparation/models/block/sql/__init__.py +1 -1
- mage_ai/data_preparation/models/pipeline.py +102 -19
- mage_ai/data_preparation/models/utils.py +6 -0
- mage_ai/data_preparation/models/variable.py +18 -4
- mage_ai/data_preparation/repo_manager.py +3 -2
- mage_ai/data_preparation/shared/utils.py +1 -1
- mage_ai/data_preparation/storage/gcs_storage.py +1 -1
- mage_ai/data_preparation/templates/constants.py +7 -0
- mage_ai/data_preparation/templates/data_exporters/mysql.py +2 -2
- mage_ai/data_preparation/templates/data_exporters/oracledb.py +27 -0
- mage_ai/data_preparation/templates/repo/metadata.yaml +1 -0
- mage_ai/io/bigquery.py +131 -58
- mage_ai/io/export_utils.py +3 -0
- mage_ai/io/mysql.py +38 -6
- mage_ai/io/oracledb.py +138 -3
- mage_ai/io/snowflake.py +152 -29
- mage_ai/io/sql.py +4 -0
- mage_ai/orchestration/db/__init__.py +2 -2
- mage_ai/orchestration/db/models/oauth.py +4 -4
- mage_ai/orchestration/db/models/schedules.py +10 -3
- mage_ai/orchestration/job_manager.py +6 -0
- mage_ai/orchestration/notification/sender.py +8 -0
- mage_ai/orchestration/pipeline_scheduler_original.py +26 -7
- mage_ai/orchestration/queue/celery_queue.py +8 -1
- mage_ai/orchestration/queue/process_queue.py +67 -4
- mage_ai/orchestration/queue/queue.py +8 -0
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +2 -2
- mage_ai/server/{frontend_dist_base_path_template/_next/static/khKiaJtwrslgMmp4YSa1f → frontend_dist/_next/static/_krrrgup_C-dPOpX36S8I}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/1557-df144fbd8b2208c3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/3548-fa0792ddb88f4646.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/4241-ccd0126f5750cc35.js → frontend_dist/_next/static/chunks/4241-4499461184ba0d23.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5627-237a3de578538022.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/7966-5c1786fb7e7a48f5.js → frontend_dist/_next/static/chunks/7966-f07b2913f7326b50.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-d9c89527266296f7.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-8bbfa0c19b5e4cb3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-852d403c7bda21b3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-597b74828bf105db.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipeline-runs-a66b4c7641ae03eb.js → pipeline-runs-3edc6270c5b0e962.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-90abafc7ed61c582.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-1bdfda8edc9cf4a8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-79a4cf66a623e667.js → frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-7d38b2f7c3e918a1.js → frontend_dist/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-9cba3211434a8966.js +1 -0
- mage_ai/server/frontend_dist/block-layout.html +2 -2
- mage_ai/server/frontend_dist/compute.html +2 -2
- mage_ai/server/frontend_dist/files.html +2 -2
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-data-products.html +2 -2
- mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/index.html +2 -2
- mage_ai/server/frontend_dist/manage/files.html +2 -2
- mage_ai/server/frontend_dist/manage/settings.html +2 -2
- mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist/manage/users.html +2 -2
- mage_ai/server/frontend_dist/manage.html +2 -2
- mage_ai/server/frontend_dist/oauth.html +3 -3
- mage_ai/server/frontend_dist/overview.html +2 -2
- mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist/pipelines.html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist/settings.html +2 -2
- mage_ai/server/frontend_dist/sign-in.html +5 -5
- mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist/templates.html +2 -2
- mage_ai/server/frontend_dist/terminal.html +2 -2
- mage_ai/server/frontend_dist/test.html +2 -2
- mage_ai/server/frontend_dist/triggers.html +2 -2
- mage_ai/server/frontend_dist/version-control.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
- mage_ai/server/{frontend_dist/_next/static/vPsMu6Fi2zrHaf2fRXKRO → frontend_dist_base_path_template/_next/static/KLL5mirre9d7_ZeEpaw3s}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-df144fbd8b2208c3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-fa0792ddb88f4646.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/4241-ccd0126f5750cc35.js → frontend_dist_base_path_template/_next/static/chunks/4241-4499461184ba0d23.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5627-237a3de578538022.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/7966-5c1786fb7e7a48f5.js → frontend_dist_base_path_template/_next/static/chunks/7966-f07b2913f7326b50.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-d9c89527266296f7.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-8bbfa0c19b5e4cb3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-852d403c7bda21b3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-597b74828bf105db.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipeline-runs-a66b4c7641ae03eb.js → pipeline-runs-3edc6270c5b0e962.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-90abafc7ed61c582.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-1bdfda8edc9cf4a8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-79a4cf66a623e667.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/sign-in-7d38b2f7c3e918a1.js → frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-9cba3211434a8966.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/oauth.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/sign-in.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
- mage_ai/server/scheduler_manager.py +7 -0
- mage_ai/server/server.py +12 -5
- mage_ai/server/websocket_server.py +1 -0
- mage_ai/services/k8s/job_manager.py +8 -0
- mage_ai/services/slack/slack.py +10 -1
- mage_ai/services/spark/spark.py +9 -2
- mage_ai/settings/backends.py +8 -8
- mage_ai/settings/keys/auth.py +2 -0
- mage_ai/settings/models/configuration_option.py +10 -9
- mage_ai/settings/server.py +1 -1
- mage_ai/shared/files.py +19 -1
- mage_ai/shared/path_fixer.py +3 -0
- mage_ai/streaming/sources/base.py +5 -0
- mage_ai/streaming/sources/influxdb.py +2 -0
- mage_ai/streaming/sources/kafka.py +2 -1
- mage_ai/streaming/sources/mongodb.py +4 -0
- mage_ai/tests/api/endpoints/mixins.py +10 -9
- mage_ai/tests/api/endpoints/test_seeds.py +24 -0
- mage_ai/tests/api/operations/test_sessions.py +53 -2
- mage_ai/tests/authentication/providers/test_okta.py +43 -0
- mage_ai/tests/data_preparation/models/block/dbt/test_block.py +2 -2
- mage_ai/tests/data_preparation/models/block/dbt/test_block_sql.py +1 -1
- mage_ai/tests/data_preparation/models/block/dbt/test_block_yaml.py +1 -1
- mage_ai/tests/data_preparation/models/test_block.py +2 -1
- mage_ai/tests/orchestration/db/models/test_oauth.py +3 -3
- mage_ai/tests/orchestration/queue/test_process_queue.py +1 -0
- mage_ai/tests/orchestration/test_pipeline_scheduler.py +2 -0
- mage_ai/tests/server/test_server.py +8 -4
- mage_ai/tests/settings/models/test_configuration_option.py +2 -2
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/METADATA +6 -6
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/RECORD +263 -259
- mage_ai/server/frontend_dist/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/181-e61915415a976861.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3548-13563a1ff815f922.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-d3a5fd3119fdb1e4.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-42789d698d28a92f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-d05040edba41b2ac.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-36377e679da2cd91.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1b688d61f8efe07a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-ed3331d22d5cff7d.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d94e48bad89ba1e0.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-f508c2f261297724.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-6826000cdffc36b8.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-dde29a463495cebb.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-ab98a7b3a678669e.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/181-e61915415a976861.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-13563a1ff815f922.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-d3a5fd3119fdb1e4.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-42789d698d28a92f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-d05040edba41b2ac.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-36377e679da2cd91.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1b688d61f8efe07a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-ed3331d22d5cff7d.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d94e48bad89ba1e0.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-f508c2f261297724.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-6826000cdffc36b8.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-dde29a463495cebb.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-ab98a7b3a678669e.js +0 -1
- /mage_ai/server/frontend_dist/_next/static/{vPsMu6Fi2zrHaf2fRXKRO → _krrrgup_C-dPOpX36S8I}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{khKiaJtwrslgMmp4YSa1f → KLL5mirre9d7_ZeEpaw3s}/_ssgManifest.js +0 -0
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/WHEEL +0 -0
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/top_level.txt +0 -0
|
@@ -24,8 +24,6 @@ class BaseMonitor:
|
|
|
24
24
|
if self.error.type:
|
|
25
25
|
data['type'] = self.error.type
|
|
26
26
|
|
|
27
|
-
loop = asyncio.get_event_loop()
|
|
28
|
-
|
|
29
27
|
kwargs = dict(
|
|
30
28
|
resource=self.resource,
|
|
31
29
|
**extract(
|
|
@@ -48,6 +46,7 @@ class BaseMonitor:
|
|
|
48
46
|
),
|
|
49
47
|
)
|
|
50
48
|
|
|
49
|
+
loop = asyncio.get_event_loop()
|
|
51
50
|
if loop is not None:
|
|
52
51
|
loop.create_task(
|
|
53
52
|
UsageStatisticLogger().error(
|
|
@@ -6,7 +6,7 @@ import urllib.parse
|
|
|
6
6
|
|
|
7
7
|
from mage_ai.api.errors import ApiError
|
|
8
8
|
from mage_ai.api.resources.GenericResource import GenericResource
|
|
9
|
-
from mage_ai.data_preparation.models.block import
|
|
9
|
+
from mage_ai.data_preparation.models.block.block_factory import BlockFactory
|
|
10
10
|
from mage_ai.data_preparation.models.constants import BlockType
|
|
11
11
|
from mage_ai.data_preparation.models.widget.constants import ChartType
|
|
12
12
|
from mage_ai.data_preparation.variable_manager import get_global_variables
|
|
@@ -73,7 +73,7 @@ class BlockLayoutItemResource(GenericResource):
|
|
|
73
73
|
data_source_type = data_source_config.get('type')
|
|
74
74
|
pipeline_uuid = data_source_config.get('pipeline_uuid')
|
|
75
75
|
|
|
76
|
-
block =
|
|
76
|
+
block = BlockFactory.get_block(
|
|
77
77
|
block_config.get('name') or file_path or uuid,
|
|
78
78
|
block_uuid,
|
|
79
79
|
block_type,
|
|
@@ -12,6 +12,7 @@ from mage_ai.cache.block_action_object.constants import (
|
|
|
12
12
|
OBJECT_TYPE_MAGE_TEMPLATE,
|
|
13
13
|
)
|
|
14
14
|
from mage_ai.data_preparation.models.block import Block
|
|
15
|
+
from mage_ai.data_preparation.models.block.block_factory import BlockFactory
|
|
15
16
|
from mage_ai.data_preparation.models.block.utils import clean_name
|
|
16
17
|
from mage_ai.data_preparation.models.constants import (
|
|
17
18
|
FILE_EXTENSION_TO_BLOCK_LANGUAGE,
|
|
@@ -163,7 +164,7 @@ class BlockResource(GenericResource):
|
|
|
163
164
|
if payload.get('type') == BlockType.DBT and language == BlockLanguage.SQL and content:
|
|
164
165
|
from mage_ai.data_preparation.models.block.dbt import DBTBlock
|
|
165
166
|
|
|
166
|
-
dbt_block = DBTBlock(
|
|
167
|
+
dbt_block = DBTBlock.create(
|
|
167
168
|
name,
|
|
168
169
|
clean_name(name),
|
|
169
170
|
BlockType.DBT,
|
|
@@ -323,7 +324,7 @@ class BlockResource(GenericResource):
|
|
|
323
324
|
if BlockType.DBT == block_type:
|
|
324
325
|
from mage_ai.data_preparation.models.block.dbt import DBTBlock
|
|
325
326
|
|
|
326
|
-
block = DBTBlock(
|
|
327
|
+
block = DBTBlock.create(
|
|
327
328
|
block_uuid,
|
|
328
329
|
block_uuid,
|
|
329
330
|
block_type,
|
|
@@ -331,7 +332,7 @@ class BlockResource(GenericResource):
|
|
|
331
332
|
language=language,
|
|
332
333
|
)
|
|
333
334
|
else:
|
|
334
|
-
block =
|
|
335
|
+
block = BlockFactory.get_block(block_uuid, block_uuid, block_type, language=language)
|
|
335
336
|
|
|
336
337
|
if not block.exists():
|
|
337
338
|
error.update(ApiError.RESOURCE_NOT_FOUND)
|
|
@@ -152,14 +152,10 @@ class GitBranchResource(GenericResource):
|
|
|
152
152
|
)
|
|
153
153
|
http_access_token = git_manager.get_access_token()
|
|
154
154
|
|
|
155
|
+
config_overwrite = None
|
|
155
156
|
token = None
|
|
156
157
|
if access_token:
|
|
157
158
|
token = access_token.token
|
|
158
|
-
elif http_access_token:
|
|
159
|
-
token = http_access_token
|
|
160
|
-
|
|
161
|
-
config_overwrite = None
|
|
162
|
-
if token:
|
|
163
159
|
user_from_api = api.get_user(token, provider=provider)
|
|
164
160
|
# Default to mage user email if no email is returned from API
|
|
165
161
|
email = user_from_api.get(
|
|
@@ -169,6 +165,8 @@ class GitBranchResource(GenericResource):
|
|
|
169
165
|
username=user_from_api.get('username'),
|
|
170
166
|
email=email,
|
|
171
167
|
)
|
|
168
|
+
elif http_access_token:
|
|
169
|
+
token = http_access_token
|
|
172
170
|
|
|
173
171
|
# Recreate git manager with updated config
|
|
174
172
|
git_manager = self.get_git_manager(
|
|
@@ -3,7 +3,7 @@ import urllib.parse
|
|
|
3
3
|
|
|
4
4
|
from mage_ai.api.errors import ApiError
|
|
5
5
|
from mage_ai.api.resources.GenericResource import GenericResource
|
|
6
|
-
from mage_ai.data_preparation.models.block import
|
|
6
|
+
from mage_ai.data_preparation.models.block.block_factory import BlockFactory
|
|
7
7
|
from mage_ai.presenters.block_layout.page import PageBlockLayout
|
|
8
8
|
from mage_ai.shared.hash import extract, ignore_keys, merge_dict
|
|
9
9
|
from mage_ai.shared.utils import clean_name
|
|
@@ -52,7 +52,7 @@ class PageBlockLayoutResource(GenericResource):
|
|
|
52
52
|
if len(parts) >= 2:
|
|
53
53
|
block_uuid_use = os.path.join(*parts[1:])
|
|
54
54
|
|
|
55
|
-
block =
|
|
55
|
+
block = BlockFactory.get_block(
|
|
56
56
|
block_uuid_use,
|
|
57
57
|
block_uuid_use,
|
|
58
58
|
block_type,
|
|
@@ -362,6 +362,8 @@ class PipelineResource(BaseResource):
|
|
|
362
362
|
clone_pipeline_uuid = payload.get('clone_pipeline_uuid')
|
|
363
363
|
template_uuid = payload.get('custom_template_uuid')
|
|
364
364
|
name = payload.get('name')
|
|
365
|
+
description = payload.get('description')
|
|
366
|
+
tags = payload.get('tags')
|
|
365
367
|
pipeline_type = payload.get('type')
|
|
366
368
|
llm_payload = payload.get('llm')
|
|
367
369
|
pipeline = None
|
|
@@ -375,8 +377,10 @@ class PipelineResource(BaseResource):
|
|
|
375
377
|
else:
|
|
376
378
|
pipeline = Pipeline.create(
|
|
377
379
|
name,
|
|
380
|
+
description=description,
|
|
378
381
|
pipeline_type=pipeline_type,
|
|
379
382
|
repo_path=get_repo_path(),
|
|
383
|
+
tags=tags,
|
|
380
384
|
)
|
|
381
385
|
|
|
382
386
|
if llm_payload:
|
|
@@ -451,6 +455,15 @@ class PipelineResource(BaseResource):
|
|
|
451
455
|
cache = await PipelineCache.initialize_cache()
|
|
452
456
|
cache.add_model(resource.model)
|
|
453
457
|
|
|
458
|
+
tags = resource.model.tags
|
|
459
|
+
if tags:
|
|
460
|
+
from mage_ai.cache.tag import TagCache
|
|
461
|
+
|
|
462
|
+
cache = await TagCache.initialize_cache()
|
|
463
|
+
|
|
464
|
+
for tag_uuid in tags:
|
|
465
|
+
cache.add_pipeline(tag_uuid, resource.model)
|
|
466
|
+
|
|
454
467
|
self.on_create_callback = _on_create_callback
|
|
455
468
|
|
|
456
469
|
return self(pipeline, user, **kwargs)
|
|
@@ -12,7 +12,7 @@ from mage_ai.data_preparation.models.triggers import (
|
|
|
12
12
|
ScheduleStatus,
|
|
13
13
|
ScheduleType,
|
|
14
14
|
)
|
|
15
|
-
from mage_ai.orchestration.db import safe_db_query
|
|
15
|
+
from mage_ai.orchestration.db import db_connection, safe_db_query
|
|
16
16
|
from mage_ai.orchestration.db.models.schedules import (
|
|
17
17
|
BlockRun,
|
|
18
18
|
PipelineRun,
|
|
@@ -241,6 +241,15 @@ class PipelineRunResource(DatabaseResource):
|
|
|
241
241
|
has_next = results_size > limit
|
|
242
242
|
final_end_idx = results_size - 1 if has_next else results_size
|
|
243
243
|
|
|
244
|
+
# Expire pipeline runs that are in progress so that the latest status is returned
|
|
245
|
+
# the next time they are fetched.
|
|
246
|
+
for run in results:
|
|
247
|
+
if run.status in (
|
|
248
|
+
PipelineRun.PipelineRunStatus.RUNNING,
|
|
249
|
+
PipelineRun.PipelineRunStatus.INITIAL,
|
|
250
|
+
):
|
|
251
|
+
db_connection.session.expire(run)
|
|
252
|
+
|
|
244
253
|
result_set = self.build_result_set(
|
|
245
254
|
results[0:final_end_idx],
|
|
246
255
|
user,
|
|
@@ -6,6 +6,7 @@ class SeedResource(GenericResource):
|
|
|
6
6
|
@classmethod
|
|
7
7
|
async def create(self, payload, user, **kwargs):
|
|
8
8
|
if payload.get('roles') and payload.get('permissions'):
|
|
9
|
-
|
|
9
|
+
policy_names = payload.get('policy_names')
|
|
10
|
+
await bootstrap_permissions(policy_names=policy_names)
|
|
10
11
|
|
|
11
12
|
return self({}, user, **kwargs)
|
|
@@ -11,9 +11,10 @@ from mage_ai.orchestration.db.models.oauth import Role, User
|
|
|
11
11
|
from mage_ai.settings import (
|
|
12
12
|
AUTHENTICATION_MODE,
|
|
13
13
|
OAUTH_DEFAULT_ACCESS,
|
|
14
|
+
get_bool_value,
|
|
14
15
|
get_settings_value,
|
|
15
16
|
)
|
|
16
|
-
from mage_ai.settings.keys import LDAP_DEFAULT_ACCESS
|
|
17
|
+
from mage_ai.settings.keys import LDAP_DEFAULT_ACCESS, UPDATE_ROLES_ON_LOGIN
|
|
17
18
|
from mage_ai.usage_statistics.logger import UsageStatisticLogger
|
|
18
19
|
|
|
19
20
|
|
|
@@ -29,6 +30,9 @@ class SessionResource(BaseResource):
|
|
|
29
30
|
|
|
30
31
|
oauth_client = kwargs.get('oauth_client')
|
|
31
32
|
|
|
33
|
+
update_roles_on_login = get_bool_value(
|
|
34
|
+
get_settings_value(UPDATE_ROLES_ON_LOGIN, default='False'))
|
|
35
|
+
|
|
32
36
|
# Oauth sign in
|
|
33
37
|
if token and provider:
|
|
34
38
|
roles = []
|
|
@@ -57,6 +61,9 @@ class SessionResource(BaseResource):
|
|
|
57
61
|
email=email,
|
|
58
62
|
roles_new=roles,
|
|
59
63
|
)
|
|
64
|
+
elif update_roles_on_login and roles:
|
|
65
|
+
user.update(roles_new=roles)
|
|
66
|
+
|
|
60
67
|
oauth_token = generate_access_token(user, oauth_client)
|
|
61
68
|
return self(oauth_token, user, **kwargs)
|
|
62
69
|
|
|
@@ -109,6 +116,11 @@ class SessionResource(BaseResource):
|
|
|
109
116
|
roles_new=roles,
|
|
110
117
|
username=email,
|
|
111
118
|
)
|
|
119
|
+
elif update_roles_on_login:
|
|
120
|
+
role_names = conn.get_user_roles(user_attributes)
|
|
121
|
+
if role_names:
|
|
122
|
+
roles = Role.query.filter(Role.name.in_(role_names)).all()
|
|
123
|
+
user.update(roles_new=roles)
|
|
112
124
|
|
|
113
125
|
oauth_token = generate_access_token(user, kwargs['oauth_client'])
|
|
114
126
|
return self(oauth_token, user, **kwargs)
|
|
@@ -27,6 +27,7 @@ class EntityName(str, Enum):
|
|
|
27
27
|
CustomTemplate = 'CustomTemplate'
|
|
28
28
|
DataProvider = 'DataProvider'
|
|
29
29
|
Database = 'Database'
|
|
30
|
+
Download = 'Download'
|
|
30
31
|
EventMatcher = 'EventMatcher'
|
|
31
32
|
EventRule = 'EventRule'
|
|
32
33
|
ExecutionState = 'ExecutionState'
|
|
@@ -68,6 +69,7 @@ class EntityName(str, Enum):
|
|
|
68
69
|
Scheduler = 'Scheduler'
|
|
69
70
|
SearchResult = 'SearchResult'
|
|
70
71
|
Secret = 'Secret'
|
|
72
|
+
Seed = 'Seed'
|
|
71
73
|
Session = 'Session'
|
|
72
74
|
SparkApplication = 'SparkApplication'
|
|
73
75
|
SparkEnvironment = 'SparkEnvironment'
|
|
@@ -171,13 +171,17 @@ async def action_rules(policy_class):
|
|
|
171
171
|
if scope not in operations_mapping:
|
|
172
172
|
operations_mapping[scope] = {}
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
if not isinstance(config2, list):
|
|
175
|
+
config2 = [config2]
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
for c in config2:
|
|
178
|
+
condition = c.get('condition')
|
|
179
|
+
key = await get_key(policy_class, condition)
|
|
180
|
+
|
|
181
|
+
if key not in operations_mapping[scope]:
|
|
182
|
+
operations_mapping[scope][key] = []
|
|
179
183
|
|
|
180
|
-
|
|
184
|
+
operations_mapping[scope][key].append(operation)
|
|
181
185
|
|
|
182
186
|
return operations_mapping
|
|
183
187
|
|
|
@@ -202,34 +206,40 @@ async def attribute_rules(policy_class, rules):
|
|
|
202
206
|
if config2 is None:
|
|
203
207
|
continue
|
|
204
208
|
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
if not isinstance(config2, list):
|
|
210
|
+
config2 = [config2]
|
|
211
|
+
|
|
212
|
+
for c in config2:
|
|
213
|
+
condition = c.get('condition')
|
|
214
|
+
key = await get_key(policy_class, condition)
|
|
207
215
|
|
|
208
|
-
|
|
209
|
-
|
|
216
|
+
if key not in mapping[scope]:
|
|
217
|
+
mapping[scope][key] = {}
|
|
210
218
|
|
|
211
|
-
|
|
212
|
-
|
|
219
|
+
if operation not in mapping[scope][key]:
|
|
220
|
+
mapping[scope][key][operation] = []
|
|
213
221
|
|
|
214
|
-
|
|
222
|
+
mapping[scope][key][operation].append(attribute)
|
|
215
223
|
|
|
216
224
|
return mapping
|
|
217
225
|
|
|
218
226
|
|
|
219
|
-
async def bootstrap_permissions():
|
|
227
|
+
async def bootstrap_permissions(policy_names: str = None):
|
|
220
228
|
action_rules_mapping = {}
|
|
221
229
|
query_rules_mapping = {}
|
|
222
230
|
read_rules_mapping = {}
|
|
223
231
|
write_rules_mapping = {}
|
|
224
232
|
|
|
225
|
-
policy_names
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
'
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
+
if policy_names is None:
|
|
234
|
+
policy_names = []
|
|
235
|
+
for n in os.listdir(policies.__path__[0]):
|
|
236
|
+
if n.endswith('Policy.py') and n not in [
|
|
237
|
+
'AsyncBasePolicy.py',
|
|
238
|
+
'BasePolicy.py',
|
|
239
|
+
'SeedPolicy.py',
|
|
240
|
+
'UserPolicy.py',
|
|
241
|
+
]:
|
|
242
|
+
policy_names.append(n.replace('Policy.py', ''))
|
|
233
243
|
|
|
234
244
|
for policy_name in policy_names:
|
|
235
245
|
policy_class = getattr(
|
|
@@ -238,6 +248,7 @@ async def bootstrap_permissions():
|
|
|
238
248
|
)
|
|
239
249
|
|
|
240
250
|
model_name = policy_class.model_name()
|
|
251
|
+
print(f'Processing {model_name}...')
|
|
241
252
|
action_rules_mapping[model_name] = await action_rules(policy_class)
|
|
242
253
|
query_rules_mapping[model_name] = await attribute_rules(
|
|
243
254
|
policy_class,
|
|
@@ -34,10 +34,11 @@ class ADProvider(SsoProvider, OauthProvider):
|
|
|
34
34
|
self.client_secret = get_settings_value(ACTIVE_DIRECTORY_CLIENT_SECRET)
|
|
35
35
|
self.__validate()
|
|
36
36
|
|
|
37
|
-
self.roles_mapping =
|
|
38
|
-
|
|
37
|
+
self.roles_mapping = {}
|
|
38
|
+
roles_mapping = get_settings_value(ACTIVE_DIRECTORY_ROLES_MAPPING)
|
|
39
|
+
if roles_mapping:
|
|
39
40
|
try:
|
|
40
|
-
self.roles_mapping = json.loads(
|
|
41
|
+
self.roles_mapping = json.loads(roles_mapping)
|
|
41
42
|
except Exception:
|
|
42
43
|
logger.exception('Failed to parse roles mapping.')
|
|
43
44
|
|
|
@@ -1,104 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
import uuid
|
|
3
|
-
from typing import Awaitable, Dict
|
|
4
|
-
|
|
5
|
-
import aiohttp
|
|
6
|
-
from aiohttp import BasicAuth
|
|
1
|
+
from urllib.parse import unquote, urlparse
|
|
7
2
|
|
|
8
3
|
from mage_ai.authentication.oauth.constants import ProviderName
|
|
9
|
-
from mage_ai.authentication.providers.
|
|
10
|
-
from mage_ai.authentication.providers.sso import SsoProvider
|
|
11
|
-
from mage_ai.authentication.providers.utils import get_base_url
|
|
4
|
+
from mage_ai.authentication.providers.oidc import OidcProvider
|
|
12
5
|
from mage_ai.settings import get_settings_value
|
|
13
6
|
from mage_ai.settings.keys import OKTA_CLIENT_ID, OKTA_CLIENT_SECRET, OKTA_DOMAIN_URL
|
|
14
7
|
|
|
15
8
|
|
|
16
|
-
class OktaProvider(
|
|
9
|
+
class OktaProvider(
|
|
10
|
+
OidcProvider
|
|
11
|
+
): # Okta configuration uses OIDC so we can just subclass the OidcProvider
|
|
17
12
|
provider = ProviderName.OKTA
|
|
18
13
|
|
|
19
14
|
def __init__(self):
|
|
20
15
|
self.hostname = get_settings_value(OKTA_DOMAIN_URL)
|
|
21
16
|
self.client_id = get_settings_value(OKTA_CLIENT_ID)
|
|
22
17
|
self.client_secret = get_settings_value(OKTA_CLIENT_SECRET)
|
|
18
|
+
self.parsed_url = urlparse(unquote(self.hostname))
|
|
19
|
+
if not self.parsed_url.scheme:
|
|
20
|
+
self.parsed_url = urlparse(unquote(f'https://{self.hostname}'))
|
|
23
21
|
self.__validate()
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
self.discovery_url = (
|
|
24
|
+
f'https://{self.parsed_url.netloc}/.well-known/openid-configuration'
|
|
25
|
+
)
|
|
26
|
+
self.discover()
|
|
27
27
|
|
|
28
28
|
def __validate(self):
|
|
29
|
-
if not self.
|
|
30
|
-
raise
|
|
29
|
+
if not self.parsed_url.netloc:
|
|
30
|
+
raise ValueError(
|
|
31
31
|
'Okta hostname is empty. '
|
|
32
|
-
'Make sure the OKTA_DOMAIN_URL environment variable is set.'
|
|
32
|
+
'Make sure the OKTA_DOMAIN_URL environment variable is set.'
|
|
33
|
+
)
|
|
33
34
|
if not self.client_id:
|
|
34
|
-
raise
|
|
35
|
+
raise ValueError(
|
|
35
36
|
'Okta client id is empty. '
|
|
36
|
-
'Make sure the OKTA_CLIENT_ID environment variable is set.'
|
|
37
|
+
'Make sure the OKTA_CLIENT_ID environment variable is set.'
|
|
38
|
+
)
|
|
37
39
|
if not self.client_secret:
|
|
38
|
-
raise
|
|
40
|
+
raise ValueError(
|
|
39
41
|
'Okta client secret is empty. '
|
|
40
|
-
'Make sure the OKTA_CLIENT_SECRET environment variable is set.'
|
|
41
|
-
|
|
42
|
-
def get_auth_url_response(self, redirect_uri: str = None, **kwargs) -> Dict:
|
|
43
|
-
base_url = get_base_url(redirect_uri)
|
|
44
|
-
redirect_uri_query = dict(
|
|
45
|
-
provider=self.provider,
|
|
46
|
-
redirect_uri=redirect_uri,
|
|
47
|
-
)
|
|
48
|
-
query = dict(
|
|
49
|
-
client_id=self.client_id,
|
|
50
|
-
redirect_uri=urllib.parse.quote_plus(
|
|
51
|
-
f'{base_url}/oauth',
|
|
52
|
-
),
|
|
53
|
-
response_mode='query',
|
|
54
|
-
response_type='code',
|
|
55
|
-
scope='openid email profile',
|
|
56
|
-
state=uuid.uuid4().hex,
|
|
57
|
-
)
|
|
58
|
-
query_strings = []
|
|
59
|
-
for k, v in query.items():
|
|
60
|
-
query_strings.append(f'{k}={v}')
|
|
61
|
-
|
|
62
|
-
return dict(
|
|
63
|
-
url=f"{self.hostname}/oauth2/default/v1/authorize?{'&'.join(query_strings)}",
|
|
64
|
-
redirect_query_params=redirect_uri_query,
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
async def get_access_token_response(self, code: str, **kwargs) -> Awaitable[Dict]:
|
|
68
|
-
base_url = get_base_url(kwargs.get('redirect_uri'))
|
|
69
|
-
data = dict()
|
|
70
|
-
async with aiohttp.ClientSession() as session:
|
|
71
|
-
async with session.post(
|
|
72
|
-
f'{self.hostname}/oauth2/default/v1/token',
|
|
73
|
-
headers={
|
|
74
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
75
|
-
},
|
|
76
|
-
data=dict(
|
|
77
|
-
grant_type='authorization_code',
|
|
78
|
-
code=code,
|
|
79
|
-
redirect_uri=f'{base_url}/oauth',
|
|
80
|
-
),
|
|
81
|
-
auth=BasicAuth(self.client_id, self.client_secret),
|
|
82
|
-
timeout=20,
|
|
83
|
-
) as response:
|
|
84
|
-
data = await response.json()
|
|
85
|
-
|
|
86
|
-
return data
|
|
87
|
-
|
|
88
|
-
async def get_user_info(self, access_token: str = None, **kwargs) -> Awaitable[Dict]:
|
|
89
|
-
if access_token is None:
|
|
90
|
-
raise Exception('Access token is required to fetch user info.')
|
|
91
|
-
async with aiohttp.ClientSession() as session:
|
|
92
|
-
async with session.get(
|
|
93
|
-
f'{self.hostname}/oauth2/default/v1/userinfo',
|
|
94
|
-
headers={
|
|
95
|
-
'Authorization': f'Bearer {access_token}'
|
|
96
|
-
},
|
|
97
|
-
timeout=10,
|
|
98
|
-
) as response:
|
|
99
|
-
userinfo_resp = await response.json()
|
|
100
|
-
|
|
101
|
-
return dict(
|
|
102
|
-
email=userinfo_resp.get('email'),
|
|
103
|
-
username=userinfo_resp.get('sub'),
|
|
104
|
-
)
|
|
42
|
+
'Make sure the OKTA_CLIENT_SECRET environment variable is set.'
|
|
43
|
+
)
|
mage_ai/cache/tag.py
CHANGED
|
@@ -144,6 +144,9 @@ class TagCache(BaseCache):
|
|
|
144
144
|
|
|
145
145
|
mapping[key][KEY_FOR_PIPELINES] = pipelines_dict
|
|
146
146
|
|
|
147
|
+
if not pipelines_dict and mapping[key].keys() == set([KEY_FOR_PIPELINES]):
|
|
148
|
+
mapping.pop(key, None)
|
|
149
|
+
|
|
147
150
|
self.set(self.cache_key, mapping)
|
|
148
151
|
|
|
149
152
|
async def initialize_cache_for_all_objects(self) -> None:
|
|
@@ -70,11 +70,14 @@ def get_workspaces(cluster_type: ClusterType, **kwargs) -> List[Workspace]:
|
|
|
70
70
|
repo_path = get_repo_path()
|
|
71
71
|
projects_folder = os.path.join(repo_path, 'projects')
|
|
72
72
|
if is_main_project:
|
|
73
|
+
# sort by file last modified time
|
|
73
74
|
projects = [
|
|
74
|
-
f
|
|
75
|
+
f
|
|
75
76
|
for f in os.scandir(projects_folder)
|
|
76
77
|
if not f.is_dir() and f.name.endswith('.yaml')
|
|
77
78
|
]
|
|
79
|
+
projects.sort(key=lambda f: os.path.getmtime(f.path), reverse=True)
|
|
80
|
+
projects = [os.path.splitext(f.name)[0] for f in projects]
|
|
78
81
|
else:
|
|
79
82
|
instances = get_instances(cluster_type, **kwargs)
|
|
80
83
|
projects = [instance.get('name') for instance in instances]
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from typing import Dict
|
|
2
2
|
|
|
3
|
+
from jinja2 import Template
|
|
4
|
+
|
|
3
5
|
from mage_ai.data_preparation.executors.block_executor import BlockExecutor
|
|
6
|
+
from mage_ai.data_preparation.shared.utils import get_template_vars
|
|
4
7
|
from mage_ai.services.k8s.config import K8sExecutorConfig
|
|
5
8
|
from mage_ai.services.k8s.constants import DEFAULT_NAMESPACE
|
|
6
9
|
from mage_ai.services.k8s.job_manager import JobManager as K8sJobManager
|
|
@@ -29,9 +32,13 @@ class K8sBlockExecutor(BlockExecutor):
|
|
|
29
32
|
job_name_prefix = self.executor_config.job_name_prefix
|
|
30
33
|
|
|
31
34
|
if self.executor_config.namespace:
|
|
32
|
-
namespace = self.executor_config.namespace
|
|
35
|
+
namespace = Template(self.executor_config.namespace).render(
|
|
36
|
+
variables=lambda x: global_vars.get(x) if global_vars else None,
|
|
37
|
+
**get_template_vars()
|
|
38
|
+
)
|
|
33
39
|
else:
|
|
34
40
|
namespace = DEFAULT_NAMESPACE
|
|
41
|
+
|
|
35
42
|
job_manager = K8sJobManager(
|
|
36
43
|
job_name=f'mage-{job_name_prefix}-block-{block_run_id}',
|
|
37
44
|
logger=self.logger,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import traceback
|
|
2
2
|
from typing import Dict
|
|
3
3
|
|
|
4
|
+
from jinja2 import Template
|
|
5
|
+
|
|
4
6
|
from mage_ai.data_preparation.executors.pipeline_executor import PipelineExecutor
|
|
5
7
|
from mage_ai.data_preparation.models.pipeline import Pipeline
|
|
8
|
+
from mage_ai.data_preparation.shared.utils import get_template_vars
|
|
6
9
|
from mage_ai.services.k8s.config import K8sExecutorConfig
|
|
7
10
|
from mage_ai.services.k8s.constants import DEFAULT_NAMESPACE
|
|
8
11
|
from mage_ai.services.k8s.job_manager import JobManager as K8sJobManager
|
|
@@ -39,6 +42,7 @@ class K8sPipelineExecutor(PipelineExecutor):
|
|
|
39
42
|
) -> None:
|
|
40
43
|
job_manager = self.get_job_manager(
|
|
41
44
|
pipeline_run_id=pipeline_run_id,
|
|
45
|
+
global_vars=global_vars,
|
|
42
46
|
**kwargs,
|
|
43
47
|
)
|
|
44
48
|
cmd = self._run_commands(
|
|
@@ -54,15 +58,22 @@ class K8sPipelineExecutor(PipelineExecutor):
|
|
|
54
58
|
def get_job_manager(
|
|
55
59
|
self,
|
|
56
60
|
pipeline_run_id: int = None,
|
|
61
|
+
global_vars: Dict = None,
|
|
57
62
|
**kwargs,
|
|
58
63
|
) -> K8sJobManager:
|
|
64
|
+
if global_vars is None:
|
|
65
|
+
global_vars = dict()
|
|
59
66
|
if not self.executor_config.job_name_prefix:
|
|
60
67
|
job_name_prefix = 'data-prep'
|
|
61
68
|
else:
|
|
62
69
|
job_name_prefix = self.executor_config.job_name_prefix
|
|
63
70
|
|
|
64
71
|
if self.executor_config.namespace:
|
|
65
|
-
|
|
72
|
+
|
|
73
|
+
namespace = Template(self.executor_config.namespace).render(
|
|
74
|
+
variables=lambda x: global_vars.get(x) if global_vars else None,
|
|
75
|
+
**get_template_vars()
|
|
76
|
+
)
|
|
66
77
|
else:
|
|
67
78
|
namespace = DEFAULT_NAMESPACE
|
|
68
79
|
|