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
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BackendType(str, Enum):
|
|
11
|
+
"""
|
|
12
|
+
Enum for the different types of settings backends.
|
|
13
|
+
"""
|
|
14
|
+
AWS_SECRETS_MANAGER = 'aws_secrets_manager'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SettingsBackend:
|
|
18
|
+
"""
|
|
19
|
+
Base settings backend class. A settings backend is a read-only storage of Mage settings.
|
|
20
|
+
The source of the configuration settings is dependent on the specific loader. The default source
|
|
21
|
+
are environment variables.
|
|
22
|
+
"""
|
|
23
|
+
backend_type = None
|
|
24
|
+
|
|
25
|
+
def get(self, key: str, **kwargs) -> Optional[str]:
|
|
26
|
+
"""
|
|
27
|
+
Loads the configuration setting stored under `key`.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
key (str): Name of the setting to load
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Any: The setting value stored under `key` in the configuration manager. If key
|
|
34
|
+
doesn't exist, returns None.
|
|
35
|
+
"""
|
|
36
|
+
value = self._get(key, **kwargs) # noqa: E1128
|
|
37
|
+
if value is None:
|
|
38
|
+
value = os.getenv(key)
|
|
39
|
+
if value is None:
|
|
40
|
+
value = kwargs.get('default')
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
def _get(self, key: str, **kwargs) -> Optional[str]:
|
|
44
|
+
"""
|
|
45
|
+
Loads the configuration setting stored under `key`.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
key (str): Name of the setting to load
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Any: The setting value stored under `key` in the configuration manager. If key
|
|
52
|
+
doesn't exist, returns None.
|
|
53
|
+
"""
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class AWSSecretsManagerBackend(SettingsBackend):
|
|
58
|
+
"""
|
|
59
|
+
Settings backend that loads configuration settings from AWS Secrets Manager.
|
|
60
|
+
"""
|
|
61
|
+
backend_type = BackendType.AWS_SECRETS_MANAGER
|
|
62
|
+
|
|
63
|
+
def __init__(self, **kwargs) -> None:
|
|
64
|
+
import boto3
|
|
65
|
+
|
|
66
|
+
self.client = boto3.client('secretsmanager')
|
|
67
|
+
self.prefix = kwargs.get('prefix', '')
|
|
68
|
+
self.use_cache = kwargs.get('use_cache', False)
|
|
69
|
+
self.cache = None
|
|
70
|
+
if self.use_cache:
|
|
71
|
+
from aws_secretsmanager_caching import SecretCache, SecretCacheConfig
|
|
72
|
+
cache_config_arg = kwargs.get('cache_config', {})
|
|
73
|
+
cache_config = SecretCacheConfig(**cache_config_arg)
|
|
74
|
+
self.cache = SecretCache(config=cache_config, client=self.client)
|
|
75
|
+
|
|
76
|
+
def _get(self, key: str, **kwargs) -> Optional[str]:
|
|
77
|
+
from botocore.exceptions import ClientError
|
|
78
|
+
if self.prefix:
|
|
79
|
+
key = f'{self.prefix}{key}'
|
|
80
|
+
if self.cache is not None:
|
|
81
|
+
return self.cache.get_secret_string(key)
|
|
82
|
+
else:
|
|
83
|
+
try:
|
|
84
|
+
secret_response = self.client.get_secret_value(
|
|
85
|
+
SecretId=key,
|
|
86
|
+
)
|
|
87
|
+
if 'SecretBinary' in secret_response:
|
|
88
|
+
binary = secret_response['SecretBinary']
|
|
89
|
+
return base64.b64decode(binary)
|
|
90
|
+
else:
|
|
91
|
+
return secret_response['SecretString']
|
|
92
|
+
except ClientError as error:
|
|
93
|
+
if error.response['Error']['Code'] != 'ResourceNotFoundException':
|
|
94
|
+
logger.exception('Failed to get secret %s from AWS Secrets Manager.', key)
|
|
95
|
+
return None
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from mage_ai.settings.keys.auth import * # noqa: F401, F403
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# LDAP settings
|
|
2
|
+
|
|
3
|
+
LDAP_SERVER = 'LDAP_SERVER'
|
|
4
|
+
LDAP_BIND_DN = 'LDAP_BIND_DN'
|
|
5
|
+
LDAP_BIND_PASSWORD = 'LDAP_BIND_PASSWORD'
|
|
6
|
+
LDAP_BASE_DN = 'LDAP_BASE_DN'
|
|
7
|
+
LDAP_AUTHENTICATION_FILTER = 'LDAP_AUTHENTICATION_FILTER'
|
|
8
|
+
LDAP_AUTHORIZATION_FILTER = 'LDAP_AUTHORIZATION_FILTER'
|
|
9
|
+
LDAP_ADMIN_USERNAME = 'LDAP_ADMIN_USERNAME'
|
|
10
|
+
# Default access level to give to users created when authenticated through LDAP
|
|
11
|
+
# for the first time. value should be the name of a Mage role (e.g. Viewer, Editor, Admin)
|
|
12
|
+
LDAP_DEFAULT_ACCESS = 'LDAP_DEFAULT_ACCESS'
|
|
13
|
+
LDAP_GROUP_FIELD = 'LDAP_GROUP_FIELD'
|
|
14
|
+
LDAP_ROLES_MAPPING = 'LDAP_ROLES_MAPPING'
|
|
15
|
+
|
|
16
|
+
# Git settings
|
|
17
|
+
|
|
18
|
+
GIT_REPO_LINK = 'GIT_REPO_LINK'
|
|
19
|
+
GIT_REPO_PATH = 'GIT_REPO_PATH'
|
|
20
|
+
GIT_USERNAME = 'GIT_USERNAME'
|
|
21
|
+
GIT_EMAIL = 'GIT_EMAIL'
|
|
22
|
+
GIT_AUTH_TYPE = 'GIT_AUTH_TYPE'
|
|
23
|
+
GIT_BRANCH = 'GIT_BRANCH'
|
|
24
|
+
GIT_SYNC_ON_PIPELINE_RUN = 'GIT_SYNC_ON_PIPELINE_RUN'
|
|
25
|
+
GIT_SYNC_ON_START = 'GIT_SYNC_ON_START'
|
|
26
|
+
GIT_SYNC_ON_EXECUTOR_START = 'GIT_SYNC_ON_EXECUTOR_START'
|
|
27
|
+
GIT_SYNC_SUBMODULES = 'GIT_SYNC_SUBMODULES'
|
|
28
|
+
|
|
29
|
+
GIT_ENABLE_GIT_INTEGRATION = 'GIT_ENABLE_GIT_INTEGRATION'
|
|
30
|
+
GIT_OVERWRITE_WITH_PROJECT_SETTINGS = 'GIT_OVERWRITE_WITH_PROJECT_SETTINGS'
|
|
31
|
+
|
|
32
|
+
GIT_SSH_PUBLIC_KEY = 'GIT_SSH_PUBLIC_KEY'
|
|
33
|
+
GIT_SSH_PRIVATE_KEY = 'GIT_SSH_PRIVATE_KEY'
|
|
34
|
+
GIT_ACCESS_TOKEN = 'GIT_ACCESS_TOKEN'
|
|
35
|
+
|
|
36
|
+
# Git Provider OAuth settings
|
|
37
|
+
|
|
38
|
+
GHE_CLIENT_ID = 'GHE_CLIENT_ID'
|
|
39
|
+
GHE_CLIENT_SECRET = 'GHE_CLIENT_SECRET'
|
|
40
|
+
GHE_HOSTNAME = 'GHE_HOSTNAME'
|
|
41
|
+
|
|
42
|
+
GITLAB_HOST = 'GITLAB_HOST'
|
|
43
|
+
GITLAB_CLIENT_ID = 'GITLAB_CLIENT_ID'
|
|
44
|
+
GITLAB_CLIENT_SECRET = 'GITLAB_CLIENT_SECRET'
|
|
45
|
+
|
|
46
|
+
BITBUCKET_HOST = 'BITBUCKET_HOST'
|
|
47
|
+
BITBUCKET_OAUTH_KEY = 'BITBUCKET_OAUTH_KEY'
|
|
48
|
+
BITBUCKET_OAUTH_SECRET = 'BITBUCKET_OAUTH_SECRET'
|
|
49
|
+
|
|
50
|
+
# Okta settings
|
|
51
|
+
|
|
52
|
+
OKTA_DOMAIN_URL = 'OKTA_DOMAIN_URL'
|
|
53
|
+
OKTA_CLIENT_ID = 'OKTA_CLIENT_ID'
|
|
54
|
+
OKTA_CLIENT_SECRET = 'OKTA_CLIENT_SECRET'
|
|
55
|
+
|
|
56
|
+
# Google settings
|
|
57
|
+
|
|
58
|
+
GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID'
|
|
59
|
+
GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET'
|
|
60
|
+
|
|
61
|
+
# Active directory settings
|
|
62
|
+
|
|
63
|
+
ACTIVE_DIRECTORY_CLIENT_ID = 'ACTIVE_DIRECTORY_CLIENT_ID'
|
|
64
|
+
ACTIVE_DIRECTORY_CLIENT_SECRET = 'ACTIVE_DIRECTORY_CLIENT_SECRET'
|
|
65
|
+
ACTIVE_DIRECTORY_DIRECTORY_ID = 'ACTIVE_DIRECTORY_DIRECTORY_ID'
|
|
66
|
+
ACTIVE_DIRECTORY_ROLES_MAPPING = 'ACTIVE_DIRECTORY_ROLES_MAPPING'
|
|
67
|
+
|
|
68
|
+
# Azure DevOps settings
|
|
69
|
+
|
|
70
|
+
AZURE_DEVOPS_ORGANIZATION = 'AZURE_DEVOPS_ORGANIZATION'
|
|
71
|
+
|
|
72
|
+
# OIDC
|
|
73
|
+
|
|
74
|
+
OIDC_CLIENT_ID = 'OIDC_CLIENT_ID'
|
|
75
|
+
OIDC_CLIENT_SECRET = 'OIDC_CLIENT_SECRET'
|
|
76
|
+
OIDC_DISCOVERY_URL = 'OIDC_DISCOVERY_URL'
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from .secret_generation import generate_jwt_secret
|
|
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')
|
|
58
|
+
)
|
|
59
|
+
AUTHENTICATION_MODE = os.getenv('AUTHENTICATION_MODE', 'LOCAL')
|
|
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
|
|
66
|
+
|
|
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
|
+
|
|
71
|
+
# ----------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
HOSTNAME = os.getenv('HOSTNAME')
|
|
74
|
+
REDIS_URL = os.getenv('REDIS_URL')
|
|
75
|
+
SERVER_VERBOSITY = os.getenv('SERVER_VERBOSITY', 'info') or 'info'
|
|
76
|
+
SERVER_LOGGING_FORMAT = os.getenv('SERVER_LOGGING_FORMAT', 'plaintext')
|
|
77
|
+
SERVER_LOGGING_TEMPLATE = os.getenv(
|
|
78
|
+
'SERVER_LOGGING_TEMPLATE',
|
|
79
|
+
'%(levelname)s:%(name)s:%(message)s',
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
INITIAL_METADATA = os.getenv('INITIAL_METADATA', '{{}}')
|
|
83
|
+
|
|
84
|
+
DISABLE_AUTO_BROWSER_OPEN = get_bool_value(os.getenv('DISABLE_AUTO_BROWSER_OPEN', 'False'))
|
|
85
|
+
|
|
86
|
+
SHELL_COMMAND = os.getenv('SHELL_COMMAND', None)
|
|
87
|
+
USE_UNIQUE_TERMINAL = os.getenv('USE_UNIQUE_TERMINAL', None)
|
|
88
|
+
|
|
89
|
+
# sentry environment variables
|
|
90
|
+
SENTRY_DSN = os.getenv('SENTRY_DSN')
|
|
91
|
+
SENTRY_TRACES_SAMPLE_RATE = os.getenv('SENTRY_TRACES_SAMPLE_RATE', 1.0)
|
|
92
|
+
|
|
93
|
+
# New relic enable environment variable
|
|
94
|
+
ENABLE_NEW_RELIC = os.getenv('ENABLE_NEW_RELIC', False)
|
|
95
|
+
NEW_RELIC_CONFIG_PATH = os.getenv('NEW_RELIC_CONFIG_PATH', '')
|
|
96
|
+
|
|
97
|
+
# If enabled, the /metrics route will expose Tornado server metrics
|
|
98
|
+
ENABLE_PROMETHEUS = get_bool_value(os.getenv('ENABLE_PROMETHEUS', 'False'))
|
|
99
|
+
|
|
100
|
+
# OpenTelemetry configuration
|
|
101
|
+
OTEL_EXPORTER_OTLP_ENDPOINT = os.getenv('OTEL_EXPORTER_OTLP_ENDPOINT', None)
|
|
102
|
+
OTEL_EXPORTER_OTLP_HTTP_ENDPOINT = os.getenv('OTEL_EXPORTER_HTTP_OTLP_ENDPOINT', None)
|
|
103
|
+
OTEL_PYTHON_TORNADO_EXCLUDED_URLS = (
|
|
104
|
+
os.getenv('OTEL_PYTHON_TORNADO_EXCLUDED_URLS') or '/api/statuses'
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
DEFAULT_LOCALHOST_URL = 'http://localhost:6789'
|
|
108
|
+
MAGE_PUBLIC_HOST = os.getenv('MAGE_PUBLIC_HOST') or DEFAULT_LOCALHOST_URL
|
|
109
|
+
|
|
110
|
+
MAX_FILE_CACHE_SIZE = os.getenv('MAX_FILE_CACHE_SIZE') or (1024 * 1024) # 1 MB
|
|
111
|
+
|
|
112
|
+
# All base path variables should not include a leading forward slash
|
|
113
|
+
# e.g. MAGE_BASE_PATH = 'test_prefix' -> localhost:6789/test_prefix/pipelines
|
|
114
|
+
BASE_PATH = os.getenv('MAGE_BASE_PATH')
|
|
115
|
+
# Requests base path is used to configure the base path for the frontend requests. Defaults
|
|
116
|
+
# to the MAGE_BASE_PATH environment variable.
|
|
117
|
+
REQUESTS_BASE_PATH = os.getenv('MAGE_REQUESTS_BASE_PATH', BASE_PATH)
|
|
118
|
+
# Routes base path is used to configure the base path for the backend routes. Defaults
|
|
119
|
+
# to the MAGE_BASE_PATH environment variable.
|
|
120
|
+
ROUTES_BASE_PATH = os.getenv('MAGE_ROUTES_BASE_PATH', BASE_PATH)
|
|
121
|
+
# Used for OAUTH
|
|
122
|
+
JWT_SECRET = os.getenv('JWT_SECRET', 'materia')
|
|
123
|
+
# Used for generating download tokens
|
|
124
|
+
JWT_DOWNLOAD_SECRET = os.getenv('JWT_DOWNLOAD_SECRET', generate_jwt_secret())
|
|
125
|
+
# Sets the trigger interval of the scheduler to a numeric value, in seconds
|
|
126
|
+
# Determines how often the scheduler gets invoked
|
|
127
|
+
try:
|
|
128
|
+
SCHEDULER_TRIGGER_INTERVAL = float(os.getenv('SCHEDULER_TRIGGER_INTERVAL', '10'))
|
|
129
|
+
except ValueError:
|
|
130
|
+
SCHEDULER_TRIGGER_INTERVAL = 10
|
|
131
|
+
|
|
132
|
+
# List of environment variables used to configure Mage. The value of these settings
|
|
133
|
+
# will be copied between workspaces.
|
|
134
|
+
MAGE_SETTINGS_ENVIRONMENT_VARIABLES = [
|
|
135
|
+
'DISABLE_NOTEBOOK_EDIT_ACCESS',
|
|
136
|
+
'DISABLE_AUTO_BROWSER_OPEN',
|
|
137
|
+
'REQUIRE_USER_AUTHENTICATION',
|
|
138
|
+
'AUTHENTICATION_MODE',
|
|
139
|
+
'OAUTH_DEFAULT_ACCESS',
|
|
140
|
+
'LDAP_SERVER',
|
|
141
|
+
'LDAP_BIND_DN',
|
|
142
|
+
'LDAP_BIND_PASSWORD',
|
|
143
|
+
'LDAP_BASE_DN',
|
|
144
|
+
'LDAP_AUTHENTICATION_FILTER',
|
|
145
|
+
'LDAP_AUTHORIZATION_FILTER',
|
|
146
|
+
'LDAP_ADMIN_USERNAME',
|
|
147
|
+
'LDAP_DEFAULT_ACCESS',
|
|
148
|
+
'LDAP_GROUP_FIELD',
|
|
149
|
+
'LDAP_ROLES_MAPPING',
|
|
150
|
+
'SERVER_VERBOSITY',
|
|
151
|
+
'SERVER_LOGGING_FORMAT',
|
|
152
|
+
'SHELL_COMMAND',
|
|
153
|
+
'USE_UNIQUE_TERMINAL',
|
|
154
|
+
'SENTRY_DSN',
|
|
155
|
+
'SENTRY_TRACES_SAMPLE_RATE',
|
|
156
|
+
'MAGE_PUBLIC_HOST',
|
|
157
|
+
'SCHEDULER_TRIGGER_INTERVAL',
|
|
158
|
+
'REQUIRE_USER_PERMISSIONS',
|
|
159
|
+
'ENABLE_PROMETHEUS',
|
|
160
|
+
'OTEL_EXPORTER_OTLP_ENDPOINT',
|
|
161
|
+
'OTEL_EXPORTER_OTLP_HTTP_ENDPOINT',
|
|
162
|
+
'MAX_FILE_CACHE_SIZE',
|
|
163
|
+
'REDIS_URL',
|
|
164
|
+
# Oauth variables
|
|
165
|
+
'ACTIVE_DIRECTORY_DIRECTORY_ID',
|
|
166
|
+
'ACTIVE_DIRECTORY_CLIENT_ID',
|
|
167
|
+
'ACTIVE_DIRECTORY_CLIENT_SECRET',
|
|
168
|
+
'ACTIVE_DIRECTORY_ROLES_MAPPING',
|
|
169
|
+
'OKTA_DOMAIN_URL',
|
|
170
|
+
'OKTA_CLIENT_ID',
|
|
171
|
+
'OKTA_CLIENT_SECRET',
|
|
172
|
+
'GOOGLE_CLIENT_ID',
|
|
173
|
+
'GOOGLE_CLIENT_SECRET',
|
|
174
|
+
'OIDC_CLIENT_ID',
|
|
175
|
+
'OIDC_CLIENT_SECRET',
|
|
176
|
+
'OIDC_DISCOVERY_URL',
|
|
177
|
+
'GHE_CLIENT_ID',
|
|
178
|
+
'GHE_CLIENT_SECRET',
|
|
179
|
+
'GHE_HOSTNAME',
|
|
180
|
+
'BITBUCKET_HOST',
|
|
181
|
+
'BITBUCKET_OAUTH_KEY',
|
|
182
|
+
'BITBUCKET_OAUTH_SECRET',
|
|
183
|
+
'GITLAB_HOST',
|
|
184
|
+
'GITLAB_CLIENT_ID',
|
|
185
|
+
'GITLAB_CLIENT_SECRET',
|
|
186
|
+
'SERVER_LOGGING_TEMPLATE',
|
|
187
|
+
]
|
mage_ai/shared/io.py
CHANGED
|
@@ -39,7 +39,7 @@ def safe_write(filepath: str, content: str, write_func: Callable = None):
|
|
|
39
39
|
|
|
40
40
|
success = False
|
|
41
41
|
try:
|
|
42
|
-
with open(filepath, 'w') as fp:
|
|
42
|
+
with open(filepath, 'w', encoding='utf-8') as fp:
|
|
43
43
|
if write_func is not None:
|
|
44
44
|
write_func(fp, content)
|
|
45
45
|
else:
|
|
@@ -67,7 +67,7 @@ async def safe_write_async(filepath: str, content: str, write_func: Callable = N
|
|
|
67
67
|
|
|
68
68
|
success = False
|
|
69
69
|
try:
|
|
70
|
-
async with aiofiles.open(filepath, mode='w') as fp:
|
|
70
|
+
async with aiofiles.open(filepath, mode='w', encoding='utf-8') as fp:
|
|
71
71
|
if write_func is not None:
|
|
72
72
|
await write_func(fp, content)
|
|
73
73
|
else:
|
mage_ai/shared/logger.py
CHANGED
|
@@ -5,6 +5,7 @@ from contextlib import contextmanager, redirect_stdout
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from typing import Callable, List
|
|
7
7
|
|
|
8
|
+
from mage_ai.settings import SERVER_LOGGING_TEMPLATE
|
|
8
9
|
from mage_ai.shared.hash import merge_dict
|
|
9
10
|
|
|
10
11
|
logger = logging.getLogger(__name__)
|
|
@@ -84,16 +85,21 @@ class JSONFormatter(logging.Formatter):
|
|
|
84
85
|
|
|
85
86
|
|
|
86
87
|
def set_logging_format(logging_format: str = None, level: str = None) -> None:
|
|
87
|
-
handler = logging.StreamHandler()
|
|
88
|
-
handler.setFormatter(JSONFormatter())
|
|
89
|
-
|
|
90
|
-
root_logger = logging.getLogger()
|
|
91
88
|
if isinstance(logging_format, str):
|
|
92
89
|
logging_format = logging_format.lower()
|
|
90
|
+
|
|
91
|
+
root_logger = logging.getLogger()
|
|
92
|
+
if len(root_logger.handlers) > 0:
|
|
93
|
+
root_logger.removeHandler(root_logger.handlers[0])
|
|
94
|
+
|
|
95
|
+
handler = logging.StreamHandler()
|
|
93
96
|
if logging_format == 'json':
|
|
94
|
-
|
|
95
|
-
root_logger.removeHandler(root_logger.handlers[0])
|
|
97
|
+
handler.setFormatter(JSONFormatter())
|
|
96
98
|
root_logger.addHandler(handler)
|
|
99
|
+
else:
|
|
100
|
+
handler.setFormatter(logging.Formatter(SERVER_LOGGING_TEMPLATE))
|
|
101
|
+
root_logger.addHandler(handler)
|
|
102
|
+
|
|
97
103
|
if level:
|
|
98
104
|
try:
|
|
99
105
|
root_logger.setLevel(level.upper())
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from mage_ai.streaming.sources.base import BaseSource
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BasePythonSource(BaseSource):
|
|
7
|
+
def __init__(self, **kwargs):
|
|
8
|
+
"""
|
|
9
|
+
Not require config in the python source
|
|
10
|
+
"""
|
|
11
|
+
super().__init__(None, **kwargs)
|
|
12
|
+
|
|
13
|
+
def init_client(self):
|
|
14
|
+
"""
|
|
15
|
+
Intialize the client for the source.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def read(self, handler: Callable):
|
|
19
|
+
"""
|
|
20
|
+
Read the message from the source and use handler to process the message.
|
|
21
|
+
|
|
22
|
+
This method only needs to be implemented when consume_method is 'READ'.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def batch_read(self, handler: Callable):
|
|
26
|
+
"""
|
|
27
|
+
Batch read the messages from the source and use handler to process the messages.
|
|
28
|
+
|
|
29
|
+
This method only needs to be implemented when consume_method is 'BATCH_READ'.
|
|
30
|
+
"""
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import Dict
|
|
2
2
|
|
|
3
|
+
from mage_ai.data_preparation.decorators import collect_decorated_objs
|
|
3
4
|
from mage_ai.streaming.constants import SourceType
|
|
4
5
|
|
|
5
6
|
|
|
@@ -51,3 +52,27 @@ class SourceFactory:
|
|
|
51
52
|
raise Exception(
|
|
52
53
|
f'Consuming data from {connector_type} is not supported in streaming pipelines yet.',
|
|
53
54
|
)
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def get_python_source(self, content: str, **kwargs):
|
|
58
|
+
"""
|
|
59
|
+
Find the class that's decorated with streaming_source from the source code.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
content (str): The python code that contains the streaming source implementation.
|
|
63
|
+
**kwargs: {'global_vars': {...}}
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
The initialized class object.
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
Exception: Description
|
|
70
|
+
"""
|
|
71
|
+
decorated_sources = []
|
|
72
|
+
|
|
73
|
+
exec(content, {'streaming_source': collect_decorated_objs(decorated_sources)})
|
|
74
|
+
|
|
75
|
+
if not decorated_sources:
|
|
76
|
+
raise Exception('Not find the class that has streaming_source decorator.')
|
|
77
|
+
|
|
78
|
+
return decorated_sources[0](**kwargs)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
1
3
|
from mage_ai.tests.api.endpoints.mixins import (
|
|
2
4
|
BaseAPIEndpointTest,
|
|
3
5
|
build_list_endpoint_tests,
|
|
@@ -5,7 +7,17 @@ from mage_ai.tests.api.endpoints.mixins import (
|
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class OauthAPIEndpointTest(BaseAPIEndpointTest):
|
|
8
|
-
|
|
10
|
+
@classmethod
|
|
11
|
+
def setUpClass(self):
|
|
12
|
+
super().setUpClass()
|
|
13
|
+
os.environ['GOOGLE_CLIENT_ID'] = 'test'
|
|
14
|
+
os.environ['GOOGLE_CLIENT_SECRET'] = 'test secret'
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def tearDownClass(self):
|
|
18
|
+
super().tearDownClass()
|
|
19
|
+
del os.environ['GOOGLE_CLIENT_ID']
|
|
20
|
+
del os.environ['GOOGLE_CLIENT_SECRET']
|
|
9
21
|
|
|
10
22
|
|
|
11
23
|
build_list_endpoint_tests(
|
|
@@ -18,8 +30,4 @@ build_list_endpoint_tests(
|
|
|
18
30
|
'url',
|
|
19
31
|
'redirect_query_params',
|
|
20
32
|
],
|
|
21
|
-
patch_function_settings=[
|
|
22
|
-
('mage_ai.settings.sso.GOOGLE_CLIENT_ID', lambda: 'test'),
|
|
23
|
-
('mage_ai.settings.sso.GOOGLE_CLIENT_SECRET', lambda: 'test secret'),
|
|
24
|
-
]
|
|
25
33
|
)
|
|
@@ -7,7 +7,7 @@ from mage_ai.tests.api.operations.test_base import BaseApiTestCase
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class OperationTests(BaseApiTestCase):
|
|
10
|
-
@patch('mage_ai.settings.DISABLE_NOTEBOOK_EDIT_ACCESS', 1)
|
|
10
|
+
@patch('mage_ai.settings.server.DISABLE_NOTEBOOK_EDIT_ACCESS', 1)
|
|
11
11
|
@patch('mage_ai.api.utils.DISABLE_NOTEBOOK_EDIT_ACCESS', 1)
|
|
12
12
|
@patch('mage_ai.api.policies.BasePolicy.DISABLE_NOTEBOOK_EDIT_ACCESS', 1)
|
|
13
13
|
@patch('mage_ai.api.policies.BasePolicy.REQUIRE_USER_AUTHENTICATION', 0)
|
|
@@ -25,7 +25,7 @@ class OperationTests(BaseApiTestCase):
|
|
|
25
25
|
|
|
26
26
|
self.assertIsNotNone(response['error'])
|
|
27
27
|
|
|
28
|
-
@patch('mage_ai.settings.DISABLE_NOTEBOOK_EDIT_ACCESS', 1)
|
|
28
|
+
@patch('mage_ai.settings.server.DISABLE_NOTEBOOK_EDIT_ACCESS', 1)
|
|
29
29
|
@patch('mage_ai.api.utils.DISABLE_NOTEBOOK_EDIT_ACCESS', 1)
|
|
30
30
|
@patch('mage_ai.api.policies.BasePolicy.DISABLE_NOTEBOOK_EDIT_ACCESS', 1)
|
|
31
31
|
@patch('mage_ai.api.policies.BasePolicy.REQUIRE_USER_AUTHENTICATION', 1)
|