mage-ai 0.9.65__py3-none-any.whl → 0.9.67__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 +38 -16
- mage_ai/api/policies/BackfillPolicy.py +1 -0
- mage_ai/api/resources/OauthResource.py +13 -5
- mage_ai/api/resources/SessionResource.py +6 -4
- mage_ai/authentication/ldap.py +19 -9
- mage_ai/authentication/oauth/constants.py +8 -14
- mage_ai/authentication/oauth/utils.py +18 -6
- mage_ai/authentication/providers/active_directory.py +21 -16
- mage_ai/authentication/providers/azure_devops.py +18 -0
- mage_ai/authentication/providers/bitbucket.py +10 -9
- mage_ai/authentication/providers/constants.py +2 -0
- mage_ai/authentication/providers/ghe.py +5 -9
- mage_ai/authentication/providers/gitlab.py +6 -9
- mage_ai/authentication/providers/google.py +9 -6
- mage_ai/authentication/providers/oidc.py +6 -4
- mage_ai/authentication/providers/okta.py +9 -6
- mage_ai/cluster_manager/kubernetes/workload_manager.py +10 -0
- mage_ai/cluster_manager/workspace/base.py +6 -1
- mage_ai/cluster_manager/workspace/kubernetes.py +3 -0
- mage_ai/data_preparation/decorators.py +15 -0
- mage_ai/data_preparation/executors/streaming_pipeline_executor.py +22 -12
- mage_ai/data_preparation/git/__init__.py +10 -1
- mage_ai/data_preparation/git/api.py +3 -0
- mage_ai/data_preparation/git/clients/azure_devops.py +106 -0
- mage_ai/data_preparation/git/clients/base.py +6 -0
- mage_ai/data_preparation/git/clients/gitlab.py +3 -2
- mage_ai/data_preparation/git/utils.py +31 -29
- mage_ai/data_preparation/models/block/__init__.py +27 -18
- mage_ai/data_preparation/models/block/dbt/block_sql.py +164 -0
- mage_ai/data_preparation/models/block/dynamic/variables.py +1 -2
- mage_ai/data_preparation/models/pipeline.py +3 -3
- mage_ai/data_preparation/models/triggers/__init__.py +6 -1
- mage_ai/data_preparation/preferences.py +42 -37
- mage_ai/data_preparation/repo_manager.py +21 -0
- mage_ai/data_preparation/storage/gcs_storage.py +27 -2
- mage_ai/data_preparation/storage/local_storage.py +18 -3
- mage_ai/data_preparation/storage/s3_storage.py +7 -2
- mage_ai/data_preparation/templates/data_loaders/streaming/generic_python.py +23 -0
- mage_ai/data_preparation/templates/main/metadata.yaml +6 -0
- mage_ai/data_preparation/templates/template.py +6 -2
- mage_ai/data_preparation/variable_manager.py +2 -1
- mage_ai/io/base.py +3 -0
- mage_ai/io/bigquery.py +2 -0
- mage_ai/io/export_utils.py +14 -9
- mage_ai/io/mssql.py +104 -25
- mage_ai/io/mysql.py +10 -9
- mage_ai/io/oracledb.py +14 -2
- mage_ai/io/postgres.py +3 -0
- mage_ai/io/sql.py +14 -6
- mage_ai/io/trino.py +10 -8
- mage_ai/orchestration/db/migrations/versions/90d978a8aef8_update_unique_constraint_for_secret.py +11 -5
- mage_ai/orchestration/db/models/schedules.py +25 -1
- mage_ai/orchestration/db/models/schedules_project_platform.py +24 -1
- mage_ai/orchestration/job_manager.py +6 -1
- mage_ai/orchestration/pipeline_scheduler_original.py +16 -10
- mage_ai/server/constants.py +1 -1
- mage_ai/server/file_observer.py +10 -0
- mage_ai/server/frontend_dist/404.html +2 -2
- mage_ai/server/frontend_dist/_next/static/chunks/{1557-a754b04510d50b80.js → 1557-01f0843dc6ac4971.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9440-4069842b90d4b801.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/oauth-30e34ee15d410331.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{edit-8d32ac7e8f023779.js → edit-36377e679da2cd91.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-3f5c14076ddde20e.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-fe08120d9a6fb1b0.js → triggers-f508c2f261297724.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-bcdb4ad41dd4c7d5.js → frontend_dist/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{sign-in-19b36600d908b711.js → sign-in-7d38b2f7c3e918a1.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{webpack-ac7fdc472bedf682.js → webpack-d079359c241db804.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/{ZMrJfDouIX5AMb_RteRbL → vPsMu6Fi2zrHaf2fRXKRO}/_buildManifest.js +1 -1
- 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 +2 -2
- 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 +2 -2
- 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_base_path_template/_next/static/chunks/{1557-a754b04510d50b80.js → 1557-01f0843dc6ac4971.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-4069842b90d4b801.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/oauth-30e34ee15d410331.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{edit-8d32ac7e8f023779.js → edit-36377e679da2cd91.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-3f5c14076ddde20e.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-fe08120d9a6fb1b0.js → triggers-f508c2f261297724.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines-bcdb4ad41dd4c7d5.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{sign-in-19b36600d908b711.js → sign-in-7d38b2f7c3e918a1.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-481689d9989710cd.js → webpack-68c003fb6a175cd7.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/{QYwFH4sievaq5XyUjRriy → khKiaJtwrslgMmp4YSa1f}/_buildManifest.js +1 -1
- 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 +2 -2
- 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 +2 -2
- 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/server.py +117 -87
- mage_ai/server/utils/output_display.py +6 -1
- mage_ai/services/aws/s3/s3.py +8 -2
- mage_ai/services/slack/slack.py +8 -8
- mage_ai/settings/__init__.py +36 -186
- mage_ai/settings/backends.py +95 -0
- mage_ai/settings/keys/__init__.py +1 -0
- mage_ai/settings/keys/auth.py +76 -0
- mage_ai/settings/server.py +187 -0
- mage_ai/shared/io.py +2 -2
- mage_ai/shared/logger.py +12 -6
- mage_ai/streaming/sources/base_python.py +30 -0
- mage_ai/streaming/sources/source_factory.py +25 -0
- mage_ai/tests/api/endpoints/test_oauths.py +13 -5
- mage_ai/tests/api/operations/test_operations.py +2 -2
- mage_ai/tests/api/operations/test_sessions.py +83 -48
- mage_ai/tests/authentication/oauth/test_utils.py +56 -6
- mage_ai/tests/authentication/providers/test_active_directory.py +9 -15
- mage_ai/tests/data_preparation/models/test_block.py +39 -2
- mage_ai/tests/orchestration/db/models/test_schedules.py +33 -1
- {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/METADATA +2 -1
- {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/RECORD +225 -217
- {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/WHEEL +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9440-2bcbdc765ed82062.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-2ae1d919333f01fe.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-64851458dde54ad9.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/oauth-abe5ba687cb93509.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-22e49726eeed16ae.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c74507dce89b41a2.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-cf656cbe37ecaacc.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-690206d30d8b412b.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-2bcbdc765ed82062.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-2ae1d919333f01fe.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-64851458dde54ad9.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/oauth-abe5ba687cb93509.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-22e49726eeed16ae.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c74507dce89b41a2.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-cf656cbe37ecaacc.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-690206d30d8b412b.js +0 -1
- mage_ai/settings/sso.py +0 -27
- /mage_ai/server/frontend_dist/_next/static/{ZMrJfDouIX5AMb_RteRbL → vPsMu6Fi2zrHaf2fRXKRO}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{QYwFH4sievaq5XyUjRriy → khKiaJtwrslgMmp4YSa1f}/_ssgManifest.js +0 -0
- {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/top_level.txt +0 -0
mage_ai/server/server.py
CHANGED
|
@@ -17,6 +17,7 @@ from tornado import autoreload
|
|
|
17
17
|
from tornado.ioloop import PeriodicCallback
|
|
18
18
|
from tornado.log import enable_pretty_logging
|
|
19
19
|
from tornado.options import options
|
|
20
|
+
from watchdog.observers import Observer
|
|
20
21
|
|
|
21
22
|
from mage_ai.authentication.passwords import create_bcrypt_hash, generate_salt
|
|
22
23
|
from mage_ai.cache.block import BlockCache
|
|
@@ -37,6 +38,7 @@ from mage_ai.data_preparation.repo_manager import (
|
|
|
37
38
|
get_project_uuid,
|
|
38
39
|
init_project_uuid,
|
|
39
40
|
init_repo,
|
|
41
|
+
update_settings_on_metadata_change,
|
|
40
42
|
)
|
|
41
43
|
from mage_ai.data_preparation.shared.constants import MANAGE_ENV_VAR
|
|
42
44
|
from mage_ai.orchestration.constants import Entity
|
|
@@ -63,6 +65,7 @@ from mage_ai.server.api.v1 import (
|
|
|
63
65
|
)
|
|
64
66
|
from mage_ai.server.constants import DATA_PREP_SERVER_PORT
|
|
65
67
|
from mage_ai.server.docs_server import run_docs_server
|
|
68
|
+
from mage_ai.server.file_observer import MetadataEventHandler
|
|
66
69
|
from mage_ai.server.kernel_output_parser import parse_output_message
|
|
67
70
|
from mage_ai.server.kernels import DEFAULT_KERNEL_NAME
|
|
68
71
|
from mage_ai.server.logger import Logger
|
|
@@ -85,7 +88,6 @@ from mage_ai.settings import (
|
|
|
85
88
|
AUTHENTICATION_MODE,
|
|
86
89
|
DISABLE_AUTO_BROWSER_OPEN,
|
|
87
90
|
ENABLE_PROMETHEUS,
|
|
88
|
-
LDAP_ADMIN_USERNAME,
|
|
89
91
|
OAUTH2_APPLICATION_CLIENT_ID,
|
|
90
92
|
OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
91
93
|
REDIS_URL,
|
|
@@ -97,11 +99,14 @@ from mage_ai.settings import (
|
|
|
97
99
|
SERVER_VERBOSITY,
|
|
98
100
|
SHELL_COMMAND,
|
|
99
101
|
USE_UNIQUE_TERMINAL,
|
|
102
|
+
get_settings_value,
|
|
100
103
|
)
|
|
104
|
+
from mage_ai.settings.keys import LDAP_ADMIN_USERNAME
|
|
101
105
|
from mage_ai.settings.repo import (
|
|
102
106
|
DEFAULT_MAGE_DATA_DIR,
|
|
103
107
|
MAGE_CLUSTER_TYPE_ENV_VAR,
|
|
104
108
|
MAGE_PROJECT_TYPE_ENV_VAR,
|
|
109
|
+
get_metadata_path,
|
|
105
110
|
get_repo_name,
|
|
106
111
|
get_variables_dir,
|
|
107
112
|
set_repo_path,
|
|
@@ -220,7 +225,11 @@ def replace_base_path(base_path: str) -> str:
|
|
|
220
225
|
return dst
|
|
221
226
|
|
|
222
227
|
|
|
223
|
-
def make_app(
|
|
228
|
+
def make_app(
|
|
229
|
+
template_dir: str = None,
|
|
230
|
+
update_routes: bool = False,
|
|
231
|
+
status_only: bool = False,
|
|
232
|
+
):
|
|
224
233
|
shell_command = SHELL_COMMAND
|
|
225
234
|
if shell_command is None:
|
|
226
235
|
shell_command = 'bash'
|
|
@@ -233,7 +242,20 @@ def make_app(template_dir: str = None, update_routes: bool = False):
|
|
|
233
242
|
|
|
234
243
|
if template_dir is None:
|
|
235
244
|
template_dir = os.path.join(os.path.dirname(__file__), EXPORTS_FOLDER)
|
|
236
|
-
|
|
245
|
+
|
|
246
|
+
routes_base = [
|
|
247
|
+
# API v1 routes
|
|
248
|
+
(
|
|
249
|
+
r'/api/status(?:es)?',
|
|
250
|
+
ApiListHandler,
|
|
251
|
+
{
|
|
252
|
+
'resource': 'statuses',
|
|
253
|
+
'bypass_oauth_check': True,
|
|
254
|
+
'is_health_check': True,
|
|
255
|
+
},
|
|
256
|
+
),
|
|
257
|
+
]
|
|
258
|
+
routes_full = routes_base + [
|
|
237
259
|
(r'/?', MainPageHandler),
|
|
238
260
|
(r'/files', MainPageHandler),
|
|
239
261
|
(r'/overview', MainPageHandler),
|
|
@@ -310,17 +332,6 @@ def make_app(template_dir: str = None, update_routes: bool = False):
|
|
|
310
332
|
r'/api/downloads/(?P<token>[\w/%.-]+)',
|
|
311
333
|
ApiResourceDownloadHandler
|
|
312
334
|
),
|
|
313
|
-
|
|
314
|
-
# API v1 routes
|
|
315
|
-
(
|
|
316
|
-
r'/api/status(?:es)?',
|
|
317
|
-
ApiListHandler,
|
|
318
|
-
{
|
|
319
|
-
'resource': 'statuses',
|
|
320
|
-
'bypass_oauth_check': True,
|
|
321
|
-
'is_health_check': True,
|
|
322
|
-
},
|
|
323
|
-
),
|
|
324
335
|
(
|
|
325
336
|
r'/api/(?P<resource>\w+)/(?P<pk>[\w\-\%2f\.]+)' \
|
|
326
337
|
r'/(?P<child>\w+)/(?P<child_pk>[\w\-\%2f\.]+)',
|
|
@@ -346,6 +357,11 @@ def make_app(template_dir: str = None, update_routes: bool = False):
|
|
|
346
357
|
(r'/version-control', MainPageHandler),
|
|
347
358
|
]
|
|
348
359
|
|
|
360
|
+
if status_only:
|
|
361
|
+
routes = routes_base
|
|
362
|
+
else:
|
|
363
|
+
routes = routes_full
|
|
364
|
+
|
|
349
365
|
if ENABLE_PROMETHEUS or OTEL_EXPORTER_OTLP_ENDPOINT:
|
|
350
366
|
from opentelemetry.instrumentation.tornado import TornadoInstrumentor
|
|
351
367
|
TornadoInstrumentor().instrument()
|
|
@@ -455,7 +471,7 @@ def initialize_user_authentication(project_type: ProjectType) -> Oauth2Applicati
|
|
|
455
471
|
if AUTHENTICATION_MODE.lower() == 'ldap':
|
|
456
472
|
user = User.create(
|
|
457
473
|
roles_new=[default_owner_role],
|
|
458
|
-
username=LDAP_ADMIN_USERNAME,
|
|
474
|
+
username=get_settings_value(LDAP_ADMIN_USERNAME, 'admin'),
|
|
459
475
|
)
|
|
460
476
|
else:
|
|
461
477
|
password_salt = generate_salt()
|
|
@@ -493,8 +509,10 @@ async def main(
|
|
|
493
509
|
port: Union[str, None] = None,
|
|
494
510
|
project: Union[str, None] = None,
|
|
495
511
|
project_type: ProjectType = ProjectType.STANDALONE,
|
|
512
|
+
status_only: bool = False,
|
|
496
513
|
):
|
|
497
|
-
|
|
514
|
+
if not status_only:
|
|
515
|
+
switch_active_kernel(DEFAULT_KERNEL_NAME)
|
|
498
516
|
|
|
499
517
|
# Update base path if environment variable is set
|
|
500
518
|
update_routes = False
|
|
@@ -515,6 +533,7 @@ async def main(
|
|
|
515
533
|
app = make_app(
|
|
516
534
|
template_dir=template_dir,
|
|
517
535
|
update_routes=update_routes,
|
|
536
|
+
status_only=status_only,
|
|
518
537
|
)
|
|
519
538
|
|
|
520
539
|
port = int(port)
|
|
@@ -539,7 +558,7 @@ async def main(
|
|
|
539
558
|
if update_routes:
|
|
540
559
|
url = f'{url}/{ROUTES_BASE_PATH}'
|
|
541
560
|
|
|
542
|
-
if not DISABLE_AUTO_BROWSER_OPEN:
|
|
561
|
+
if not DISABLE_AUTO_BROWSER_OPEN and not status_only:
|
|
543
562
|
webbrowser.open_new_tab(url)
|
|
544
563
|
logger.info(f'Mage is running at {url} and serving project {project}')
|
|
545
564
|
|
|
@@ -569,72 +588,70 @@ async def main(
|
|
|
569
588
|
except Exception:
|
|
570
589
|
logger.exception('Failed to set up git repo')
|
|
571
590
|
|
|
572
|
-
if
|
|
573
|
-
|
|
591
|
+
if not status_only:
|
|
592
|
+
# Initialize web server related settings and cache
|
|
593
|
+
if REQUIRE_USER_AUTHENTICATION:
|
|
594
|
+
initialize_user_authentication(project_type)
|
|
574
595
|
|
|
575
|
-
|
|
576
|
-
|
|
596
|
+
if REQUIRE_USER_PERMISSIONS:
|
|
597
|
+
logger.info('User permissions requirement is enabled.')
|
|
577
598
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
599
|
+
try:
|
|
600
|
+
logger.info('Initializing block cache.')
|
|
601
|
+
logger.info('Initializing pipeline cache.')
|
|
602
|
+
await BlockCache.initialize_cache(replace=True, caches=[PipelineCache])
|
|
603
|
+
except Exception as err:
|
|
604
|
+
print(f'[ERROR] PipelineCache.initialize_cache: {err}.')
|
|
605
|
+
if is_debug():
|
|
606
|
+
raise err
|
|
586
607
|
|
|
587
|
-
|
|
588
|
-
|
|
608
|
+
logger.info('Initializing tag cache.')
|
|
609
|
+
await TagCache.initialize_cache(replace=True)
|
|
589
610
|
|
|
590
|
-
|
|
591
|
-
|
|
611
|
+
logger.info('Initializing block action object cache.')
|
|
612
|
+
await BlockActionObjectCache.initialize_cache(replace=True)
|
|
592
613
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
614
|
+
project_model = Project(root_project=True)
|
|
615
|
+
if project_model:
|
|
616
|
+
if project_model.spark_config and \
|
|
617
|
+
project_model.is_feature_enabled(FeatureUUID.COMPUTE_MANAGEMENT):
|
|
597
618
|
|
|
598
|
-
|
|
619
|
+
Application.clear_cache()
|
|
599
620
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
logger.info('Initializing file cache.')
|
|
613
|
-
file_cache = FileCache.initialize_cache_with_settings(replace=True)
|
|
614
|
-
count = len(file_cache._temp_data) if file_cache._temp_data else 0
|
|
615
|
-
logger.info(
|
|
616
|
-
f'{count} files cached in {file_cache.file_path}.',
|
|
617
|
-
)
|
|
618
|
-
except Exception as err:
|
|
619
|
-
print(f'[ERROR] FileCache.initialize_cache_with_settings: {err}.')
|
|
620
|
-
if is_debug():
|
|
621
|
-
raise err
|
|
621
|
+
if project_model.is_feature_enabled(FeatureUUID.DBT_V2):
|
|
622
|
+
try:
|
|
623
|
+
logger.info('Initializing dbt cache.')
|
|
624
|
+
dbt_cache = await DBTCache.initialize_cache_async(
|
|
625
|
+
replace=True,
|
|
626
|
+
root_project=True,
|
|
627
|
+
)
|
|
628
|
+
logger.info(f'dbt cached in {dbt_cache.file_path}')
|
|
629
|
+
except Exception as err:
|
|
630
|
+
print(f'[ERROR] DBTCache.initialize_cache: {err}.')
|
|
631
|
+
if is_debug():
|
|
632
|
+
raise err
|
|
622
633
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
634
|
+
if project_model.is_feature_enabled(FeatureUUID.COMMAND_CENTER):
|
|
635
|
+
try:
|
|
636
|
+
logger.info('Initializing file cache.')
|
|
637
|
+
file_cache = FileCache.initialize_cache_with_settings(replace=True)
|
|
638
|
+
count = len(file_cache._temp_data) if file_cache._temp_data else 0
|
|
639
|
+
logger.info(
|
|
640
|
+
f'{count} files cached in {file_cache.file_path}.',
|
|
641
|
+
)
|
|
642
|
+
except Exception as err:
|
|
643
|
+
print(f'[ERROR] FileCache.initialize_cache_with_settings: {err}.')
|
|
644
|
+
if is_debug():
|
|
645
|
+
raise err
|
|
646
|
+
|
|
647
|
+
try:
|
|
648
|
+
from mage_ai.services.ssh.aws.emr.models import create_tunnel
|
|
649
|
+
|
|
650
|
+
tunnel = create_tunnel(clean_up_on_failure=True)
|
|
651
|
+
if tunnel:
|
|
652
|
+
print(f'SSH tunnel active: {tunnel.is_active()}')
|
|
653
|
+
except Exception as err:
|
|
654
|
+
print(f'[WARNING] SSH tunnel failed to create and connect: {err}')
|
|
638
655
|
|
|
639
656
|
if ProjectType.MAIN == project_type:
|
|
640
657
|
# Check scheduler status periodically
|
|
@@ -643,6 +660,19 @@ async def main(
|
|
|
643
660
|
60_000,
|
|
644
661
|
)
|
|
645
662
|
auto_termination_callback.start()
|
|
663
|
+
else:
|
|
664
|
+
# Check scheduler status periodically
|
|
665
|
+
periodic_callback = PeriodicCallback(
|
|
666
|
+
check_scheduler_status,
|
|
667
|
+
SCHEDULER_AUTO_RESTART_INTERVAL,
|
|
668
|
+
)
|
|
669
|
+
periodic_callback.start()
|
|
670
|
+
|
|
671
|
+
update_settings_on_metadata_change()
|
|
672
|
+
observer = Observer()
|
|
673
|
+
event_handler = MetadataEventHandler()
|
|
674
|
+
observer.schedule(event_handler, path=get_metadata_path(root_project=True))
|
|
675
|
+
observer.start()
|
|
646
676
|
|
|
647
677
|
get_messages(
|
|
648
678
|
lambda content: WebSocketServer.send_message(
|
|
@@ -699,7 +729,7 @@ def start_server(
|
|
|
699
729
|
run_docs_server()
|
|
700
730
|
else:
|
|
701
731
|
set_db_schema()
|
|
702
|
-
|
|
732
|
+
run_web_server_with_status_only = False
|
|
703
733
|
project_type = get_project_type()
|
|
704
734
|
if manage or project_type == ProjectType.MAIN:
|
|
705
735
|
os.environ[MANAGE_ENV_VAR] = '1'
|
|
@@ -713,8 +743,8 @@ def start_server(
|
|
|
713
743
|
scheduler_manager.start_scheduler()
|
|
714
744
|
elif instance_type == InstanceType.SCHEDULER:
|
|
715
745
|
# Start a subprocess for scheduler
|
|
716
|
-
scheduler_manager.start_scheduler(
|
|
717
|
-
|
|
746
|
+
scheduler_manager.start_scheduler()
|
|
747
|
+
run_web_server_with_status_only = True
|
|
718
748
|
elif instance_type == InstanceType.WEB_SERVER:
|
|
719
749
|
# run migrations to enable user authentication
|
|
720
750
|
try:
|
|
@@ -722,16 +752,16 @@ def start_server(
|
|
|
722
752
|
except Exception:
|
|
723
753
|
traceback.print_exc()
|
|
724
754
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
)
|
|
755
|
+
# Start web server
|
|
756
|
+
asyncio.run(
|
|
757
|
+
main(
|
|
758
|
+
host=host,
|
|
759
|
+
port=port,
|
|
760
|
+
project=project,
|
|
761
|
+
project_type=project_type,
|
|
762
|
+
status_only=run_web_server_with_status_only,
|
|
734
763
|
)
|
|
764
|
+
)
|
|
735
765
|
|
|
736
766
|
|
|
737
767
|
if __name__ == '__main__':
|
|
@@ -223,7 +223,12 @@ def __custom_output():
|
|
|
223
223
|
):
|
|
224
224
|
_sample = _internal_output_return.iloc[:{DATAFRAME_SAMPLE_COUNT_PREVIEW}]
|
|
225
225
|
_columns = _sample.columns.tolist()[:{DATAFRAME_ANALYSIS_MAX_COLUMNS}]
|
|
226
|
-
|
|
226
|
+
for col in _columns:
|
|
227
|
+
try:
|
|
228
|
+
_sample[col] = _sample[col].fillna('')
|
|
229
|
+
except Exception:
|
|
230
|
+
pass
|
|
231
|
+
_rows = simplejson.loads(_sample[_columns].to_json(
|
|
227
232
|
date_format='iso',
|
|
228
233
|
default_handler=str,
|
|
229
234
|
orient='split',
|
mage_ai/services/aws/s3/s3.py
CHANGED
|
@@ -45,11 +45,17 @@ class Client:
|
|
|
45
45
|
},
|
|
46
46
|
)
|
|
47
47
|
|
|
48
|
-
def listdir(
|
|
48
|
+
def listdir(
|
|
49
|
+
self,
|
|
50
|
+
prefix: str,
|
|
51
|
+
delimiter: str = '/',
|
|
52
|
+
suffix: str = None,
|
|
53
|
+
max_results: int = None,
|
|
54
|
+
):
|
|
49
55
|
keys = []
|
|
50
56
|
response = self.client.list_objects_v2(
|
|
51
57
|
Bucket=self.bucket,
|
|
52
|
-
MaxKeys=MAX_KEYS,
|
|
58
|
+
MaxKeys=max_results or MAX_KEYS,
|
|
53
59
|
Prefix=prefix,
|
|
54
60
|
Delimiter=delimiter,
|
|
55
61
|
)
|
mage_ai/services/slack/slack.py
CHANGED
|
@@ -6,18 +6,18 @@ from mage_ai.services.slack.config import SlackConfig
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def send_slack_message(config: SlackConfig, message: str, title: str = None) -> None:
|
|
9
|
-
message = message.replace(
|
|
9
|
+
message = message.replace('\\n', '\n')
|
|
10
10
|
payload = {
|
|
11
|
-
|
|
11
|
+
'blocks': [
|
|
12
12
|
{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
'type': 'header',
|
|
14
|
+
'text': {
|
|
15
|
+
'type': 'plain_text',
|
|
16
|
+
'text': title if title else 'Mage Notification',
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
|
-
{
|
|
20
|
-
{
|
|
19
|
+
{'type': 'divider'},
|
|
20
|
+
{'type': 'section', 'text': {'type': 'mrkdwn', 'text': message}},
|
|
21
21
|
]
|
|
22
22
|
}
|
|
23
23
|
|
mage_ai/settings/__init__.py
CHANGED
|
@@ -1,199 +1,49 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
# If you add a new environment variable, make sure to check if it should be added to
|
|
6
|
-
# the `MAGE_SETTINGS_ENVIRONMENT_VARIABLES` list at the bottom of this file. Also, update
|
|
7
|
-
# the environment variable documentation at docs/development/variables/environment-variables.mdx
|
|
8
|
-
|
|
9
|
-
DEBUG = os.getenv('DEBUG', False)
|
|
10
|
-
HIDE_ENV_VAR_VALUES = int(os.getenv('HIDE_ENV_VAR_VALUES', 1) or 1) == 1
|
|
11
|
-
QUERY_API_KEY = 'api_key'
|
|
12
|
-
|
|
13
|
-
"""
|
|
14
|
-
import secrets
|
|
15
|
-
secrets.token_urlsafe()
|
|
16
|
-
|
|
17
|
-
Make sure this value is the same in mage_ai/frontend/api/constants.ts
|
|
18
|
-
"""
|
|
19
|
-
OAUTH2_APPLICATION_CLIENT_ID = 'zkWlN0PkIKSN0C11CfUHUj84OT5XOJ6tDZ6bDRO2'
|
|
20
|
-
|
|
21
|
-
# valid values: 0, 1, 2
|
|
22
|
-
try:
|
|
23
|
-
DISABLE_NOTEBOOK_EDIT_ACCESS = int(os.getenv('DISABLE_NOTEBOOK_EDIT_ACCESS', 0))
|
|
24
|
-
except ValueError:
|
|
25
|
-
DISABLE_NOTEBOOK_EDIT_ACCESS = 1 if os.getenv('DISABLE_NOTEBOOK_EDIT_ACCESS') else 0
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def is_disable_pipeline_edit_access(
|
|
29
|
-
disable_notebook_edit_access_override: int = None,
|
|
30
|
-
) -> bool:
|
|
31
|
-
value = DISABLE_NOTEBOOK_EDIT_ACCESS
|
|
32
|
-
if disable_notebook_edit_access_override is not None:
|
|
33
|
-
value = disable_notebook_edit_access_override
|
|
34
|
-
return value >= 1
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def get_bool_value(value: str) -> bool:
|
|
38
|
-
"""
|
|
39
|
-
Converts a string environment variable to a bool value. Returns True if the value
|
|
40
|
-
is 'true', '1', or 't' (case insensitive). Otherwise, False
|
|
41
|
-
"""
|
|
42
|
-
if value is None:
|
|
43
|
-
return False
|
|
44
|
-
|
|
45
|
-
return value.lower() in ('true', '1', 't')
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# ------------------------- DISABLE TERMINAL ----------------------
|
|
49
|
-
|
|
50
|
-
DISABLE_TERMINAL = os.getenv('DISABLE_TERMINAL', '0').lower() in ('true', '1', 't')
|
|
51
|
-
|
|
52
|
-
# ----------------- Authentication settings ----------------
|
|
53
|
-
REQUIRE_USER_AUTHENTICATION = get_bool_value(
|
|
54
|
-
os.getenv('REQUIRE_USER_AUTHENTICATION', 'False')
|
|
55
|
-
)
|
|
56
|
-
REQUIRE_USER_PERMISSIONS = REQUIRE_USER_AUTHENTICATION and get_bool_value(
|
|
57
|
-
os.getenv('REQUIRE_USER_PERMISSIONS', 'False')
|
|
1
|
+
from mage_ai.settings.backends import (
|
|
2
|
+
AWSSecretsManagerBackend,
|
|
3
|
+
BackendType,
|
|
4
|
+
SettingsBackend,
|
|
58
5
|
)
|
|
59
|
-
|
|
60
|
-
try:
|
|
61
|
-
MAGE_ACCESS_TOKEN_EXPIRY_TIME = int(
|
|
62
|
-
os.getenv('MAGE_ACCESS_TOKEN_EXPIRY_TIME', '2592000')
|
|
63
|
-
)
|
|
64
|
-
except ValueError:
|
|
65
|
-
MAGE_ACCESS_TOKEN_EXPIRY_TIME = 2592000
|
|
6
|
+
from mage_ai.settings.server import * # noqa: F401, F403
|
|
66
7
|
|
|
67
|
-
# Default access level to give to users created when authenticated through OAuth
|
|
68
|
-
# for the first time. value should be the name of a Mage role (e.g. Viewer, Editor, Admin)
|
|
69
|
-
OAUTH_DEFAULT_ACCESS = os.getenv('OAUTH_DEFAULT_ACCESS')
|
|
70
|
-
LDAP_SERVER = os.getenv('LDAP_SERVER', 'ldaps://127.0.0.1:1636')
|
|
71
|
-
LDAP_BIND_DN = os.getenv('LDAP_BIND_DN', 'cd=admin,dc=example,dc=org')
|
|
72
|
-
LDAP_BIND_PASSWORD = os.getenv('LDAP_BIND_PASSWORD', 'admin_password')
|
|
73
|
-
LDAP_BASE_DN = os.getenv('LDAP_BASE_DN', 'dc=example,dc=org')
|
|
74
|
-
LDAP_AUTHENTICATION_FILTER = os.getenv(
|
|
75
|
-
'LDAP_AUTHENTICATION_FILTER',
|
|
76
|
-
'(&(|(objectClass=Pers)(objectClass=gro))(cn={username}))',
|
|
77
|
-
)
|
|
78
|
-
LDAP_AUTHORIZATION_FILTER = os.getenv(
|
|
79
|
-
'LDAP_AUTHORIZATION_FILTER',
|
|
80
|
-
'(&(objectClass=groupOfNames)(cn=group)(member={user_dn}))',
|
|
81
|
-
)
|
|
82
|
-
LDAP_ADMIN_USERNAME = os.getenv('LDAP_ADMIN_USERNAME', 'admin')
|
|
83
|
-
# Default access level to give to users created when authenticated through LDAP
|
|
84
|
-
# for the first time. value should be the name of a Mage role (e.g. Viewer, Editor, Admin)
|
|
85
|
-
LDAP_DEFAULT_ACCESS = os.getenv('LDAP_DEFAULT_ACCESS', None)
|
|
86
|
-
LDAP_GROUP_FIELD = os.getenv('LDAP_GROUP_FIELD', 'memberOf')
|
|
87
|
-
LDAP_ROLES_MAPPING = os.getenv('LDAP_ROLES_MAPPING', None)
|
|
88
|
-
|
|
89
|
-
ACTIVE_DIRECTORY_DIRECTORY_ID = os.getenv('ACTIVE_DIRECTORY_DIRECTORY_ID', None)
|
|
90
8
|
|
|
91
|
-
|
|
9
|
+
class Settings():
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.settings_backend = SettingsBackend()
|
|
92
12
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
SERVER_LOGGING_FORMAT = os.getenv('SERVER_LOGGING_FORMAT')
|
|
13
|
+
def set_settings_backend(self, backend_type: str = None, **kwargs):
|
|
14
|
+
"""
|
|
15
|
+
Factory function to create a settings backend of the specified type.
|
|
97
16
|
|
|
98
|
-
|
|
17
|
+
Args:
|
|
18
|
+
type (str): Type of the settings backend to create
|
|
19
|
+
kwargs (Dict): Additional keyword arguments to pass to the settings backend constructor
|
|
99
20
|
|
|
100
|
-
|
|
101
|
-
|
|
21
|
+
Returns:
|
|
22
|
+
SettingsBackend: A settings backend instance of the specified type
|
|
23
|
+
"""
|
|
24
|
+
if backend_type == BackendType.AWS_SECRETS_MANAGER:
|
|
25
|
+
self.settings_backend = AWSSecretsManagerBackend(**kwargs)
|
|
26
|
+
else:
|
|
27
|
+
self.settings_backend = SettingsBackend(**kwargs)
|
|
102
28
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
29
|
+
def get_value(self, key: str, default: str = None) -> str:
|
|
30
|
+
"""
|
|
31
|
+
Get the value of an environment variable. Add Mage specific logic to handle fetching
|
|
32
|
+
environment variables from other sources.
|
|
106
33
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
34
|
+
Args:
|
|
35
|
+
key (str): The name of the environment variable.
|
|
36
|
+
default (str, optional): The default value to return if the environment variable is
|
|
37
|
+
not set. Defaults to None.
|
|
110
38
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
OTEL_EXPORTER_OTLP_ENDPOINT = os.getenv('OTEL_EXPORTER_OTLP_ENDPOINT', None)
|
|
116
|
-
OTEL_EXPORTER_OTLP_HTTP_ENDPOINT = os.getenv('OTEL_EXPORTER_HTTP_OTLP_ENDPOINT', None)
|
|
117
|
-
OTEL_PYTHON_TORNADO_EXCLUDED_URLS = (
|
|
118
|
-
os.getenv('OTEL_PYTHON_TORNADO_EXCLUDED_URLS') or '/api/statuses'
|
|
119
|
-
)
|
|
39
|
+
Returns:
|
|
40
|
+
str: The value of the environment variable.
|
|
41
|
+
"""
|
|
42
|
+
return self.settings_backend.get(key, default=default)
|
|
120
43
|
|
|
121
|
-
DEFAULT_LOCALHOST_URL = 'http://localhost:6789'
|
|
122
|
-
MAGE_PUBLIC_HOST = os.getenv('MAGE_PUBLIC_HOST') or DEFAULT_LOCALHOST_URL
|
|
123
44
|
|
|
124
|
-
|
|
45
|
+
settings = Settings()
|
|
125
46
|
|
|
126
|
-
# All base path variables should not include a leading forward slash
|
|
127
|
-
# e.g. MAGE_BASE_PATH = 'test_prefix' -> localhost:6789/test_prefix/pipelines
|
|
128
|
-
BASE_PATH = os.getenv('MAGE_BASE_PATH')
|
|
129
|
-
# Requests base path is used to configure the base path for the frontend requests. Defaults
|
|
130
|
-
# to the MAGE_BASE_PATH environment variable.
|
|
131
|
-
REQUESTS_BASE_PATH = os.getenv('MAGE_REQUESTS_BASE_PATH', BASE_PATH)
|
|
132
|
-
# Routes base path is used to configure the base path for the backend routes. Defaults
|
|
133
|
-
# to the MAGE_BASE_PATH environment variable.
|
|
134
|
-
ROUTES_BASE_PATH = os.getenv('MAGE_ROUTES_BASE_PATH', BASE_PATH)
|
|
135
|
-
# Used for OAUTH
|
|
136
|
-
JWT_SECRET = os.getenv('JWT_SECRET', 'materia')
|
|
137
|
-
# Used for generating download tokens
|
|
138
|
-
JWT_DOWNLOAD_SECRET = os.getenv('JWT_DOWNLOAD_SECRET', generate_jwt_secret())
|
|
139
|
-
# Sets the trigger interval of the scheduler to a numeric value, in seconds
|
|
140
|
-
# Determines how often the scheduler gets invoked
|
|
141
|
-
try:
|
|
142
|
-
SCHEDULER_TRIGGER_INTERVAL = float(os.getenv('SCHEDULER_TRIGGER_INTERVAL', '10'))
|
|
143
|
-
except ValueError:
|
|
144
|
-
SCHEDULER_TRIGGER_INTERVAL = 10
|
|
145
47
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
MAGE_SETTINGS_ENVIRONMENT_VARIABLES = [
|
|
149
|
-
'DISABLE_NOTEBOOK_EDIT_ACCESS',
|
|
150
|
-
'DISABLE_AUTO_BROWSER_OPEN',
|
|
151
|
-
'REQUIRE_USER_AUTHENTICATION',
|
|
152
|
-
'AUTHENTICATION_MODE',
|
|
153
|
-
'OAUTH_DEFAULT_ACCESS',
|
|
154
|
-
'LDAP_SERVER',
|
|
155
|
-
'LDAP_BIND_DN',
|
|
156
|
-
'LDAP_BIND_PASSWORD',
|
|
157
|
-
'LDAP_BASE_DN',
|
|
158
|
-
'LDAP_AUTHENTICATION_FILTER',
|
|
159
|
-
'LDAP_AUTHORIZATION_FILTER',
|
|
160
|
-
'LDAP_ADMIN_USERNAME',
|
|
161
|
-
'LDAP_DEFAULT_ACCESS',
|
|
162
|
-
'LDAP_GROUP_FIELD',
|
|
163
|
-
'LDAP_ROLES_MAPPING',
|
|
164
|
-
'SERVER_VERBOSITY',
|
|
165
|
-
'SERVER_LOGGING_FORMAT',
|
|
166
|
-
'SHELL_COMMAND',
|
|
167
|
-
'USE_UNIQUE_TERMINAL',
|
|
168
|
-
'SENTRY_DSN',
|
|
169
|
-
'SENTRY_TRACES_SAMPLE_RATE',
|
|
170
|
-
'MAGE_PUBLIC_HOST',
|
|
171
|
-
'SCHEDULER_TRIGGER_INTERVAL',
|
|
172
|
-
'REQUIRE_USER_PERMISSIONS',
|
|
173
|
-
'ENABLE_PROMETHEUS',
|
|
174
|
-
'OTEL_EXPORTER_OTLP_ENDPOINT',
|
|
175
|
-
'OTEL_EXPORTER_OTLP_HTTP_ENDPOINT',
|
|
176
|
-
'MAX_FILE_CACHE_SIZE',
|
|
177
|
-
'REDIS_URL',
|
|
178
|
-
# Oauth variables
|
|
179
|
-
'ACTIVE_DIRECTORY_DIRECTORY_ID',
|
|
180
|
-
'ACTIVE_DIRECTORY_CLIENT_ID',
|
|
181
|
-
'ACTIVE_DIRECTORY_CLIENT_SECRET',
|
|
182
|
-
'OKTA_DOMAIN_URL',
|
|
183
|
-
'OKTA_CLIENT_ID',
|
|
184
|
-
'OKTA_CLIENT_SECRET',
|
|
185
|
-
'GOOGLE_CLIENT_ID',
|
|
186
|
-
'GOOGLE_CLIENT_SECRET',
|
|
187
|
-
'OIDC_CLIENT_ID',
|
|
188
|
-
'OIDC_CLIENT_SECRET',
|
|
189
|
-
'OIDC_DISCOVERY_URL',
|
|
190
|
-
'GHE_CLIENT_ID',
|
|
191
|
-
'GHE_CLIENT_SECRET',
|
|
192
|
-
'GHE_HOSTNAME',
|
|
193
|
-
'BITBUCKET_HOST',
|
|
194
|
-
'BITBUCKET_OAUTH_KEY',
|
|
195
|
-
'BITBUCKET_OAUTH_SECRET',
|
|
196
|
-
'GITLAB_HOST',
|
|
197
|
-
'GITLAB_CLIENT_ID',
|
|
198
|
-
'GITLAB_CLIENT_SECRET',
|
|
199
|
-
]
|
|
48
|
+
def get_settings_value(key: str, default: str = None) -> str:
|
|
49
|
+
return settings.get_value(key, default=default)
|