mirror of
https://github.com/apache/superset.git
synced 2026-04-18 23:55:00 +00:00
docs: bifurcate documentation into user and admin sections (#38196)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,590 +0,0 @@
|
||||
---
|
||||
title: API Reference
|
||||
hide_title: true
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
import { Alert } from 'antd';
|
||||
|
||||
## REST API Reference
|
||||
|
||||
Superset exposes a comprehensive **REST API** that follows the [OpenAPI specification](https://swagger.io/specification/).
|
||||
You can use this API to programmatically interact with Superset for automation, integrations, and custom applications.
|
||||
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
message="Code Samples & Schema Documentation"
|
||||
description={
|
||||
<span>
|
||||
Each endpoint includes ready-to-use code samples in <strong>cURL</strong>, <strong>Python</strong>, and <strong>JavaScript</strong>.
|
||||
The sidebar includes <strong>Schema definitions</strong> for detailed data model documentation.
|
||||
</span>
|
||||
}
|
||||
style={{ marginBottom: '24px' }}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
### Authentication
|
||||
|
||||
Most API endpoints require authentication via JWT tokens.
|
||||
|
||||
#### Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Get a JWT token
|
||||
curl -X POST http://localhost:8088/api/v1/security/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username": "admin", "password": "admin", "provider": "db"}'
|
||||
|
||||
# 2. Use the access_token from the response
|
||||
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
http://localhost:8088/api/v1/dashboard/
|
||||
```
|
||||
|
||||
#### Security Endpoints
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get the CSRF token](./api/get-the-csrf-token) | `/api/v1/security/csrf_token/` |
|
||||
| `POST` | [Get a guest token](./api/get-a-guest-token) | `/api/v1/security/guest_token/` |
|
||||
| `POST` | [Create security login](./api/create-security-login) | `/api/v1/security/login` |
|
||||
| `POST` | [Create security refresh](./api/create-security-refresh) | `/api/v1/security/refresh` |
|
||||
|
||||
---
|
||||
|
||||
### API Endpoints
|
||||
|
||||
#### Core Resources
|
||||
|
||||
<details>
|
||||
<summary><strong>Dashboards</strong> (26 endpoints) — Create, read, update, and delete dashboards.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `DELETE` | [Bulk delete dashboards](./api/bulk-delete-dashboards) | `/api/v1/dashboard/` |
|
||||
| `GET` | [Get a list of dashboards](./api/get-a-list-of-dashboards) | `/api/v1/dashboard/` |
|
||||
| `POST` | [Create a new dashboard](./api/create-a-new-dashboard) | `/api/v1/dashboard/` |
|
||||
| `GET` | [Get metadata information about this API resource (dashboard--info)](./api/get-metadata-information-about-this-api-resource-dashboard-info) | `/api/v1/dashboard/_info` |
|
||||
| `GET` | [Get a dashboard detail information](./api/get-a-dashboard-detail-information) | `/api/v1/dashboard/{id_or_slug}` |
|
||||
| `GET` | [Get a dashboard's chart definitions.](./api/get-a-dashboards-chart-definitions) | `/api/v1/dashboard/{id_or_slug}/charts` |
|
||||
| `POST` | [Create a copy of an existing dashboard](./api/create-a-copy-of-an-existing-dashboard) | `/api/v1/dashboard/{id_or_slug}/copy/` |
|
||||
| `GET` | [Get dashboard's datasets](./api/get-dashboards-datasets) | `/api/v1/dashboard/{id_or_slug}/datasets` |
|
||||
| `DELETE` | [Delete a dashboard's embedded configuration](./api/delete-a-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `GET` | [Get the dashboard's embedded configuration](./api/get-the-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `POST` | [Set a dashboard's embedded configuration](./api/set-a-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `PUT` | [Update dashboard by id_or_slug embedded](./api/update-dashboard-by-id-or-slug-embedded) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `GET` | [Get dashboard's tabs](./api/get-dashboards-tabs) | `/api/v1/dashboard/{id_or_slug}/tabs` |
|
||||
| `DELETE` | [Delete a dashboard](./api/delete-a-dashboard) | `/api/v1/dashboard/{pk}` |
|
||||
| `PUT` | [Update a dashboard](./api/update-a-dashboard) | `/api/v1/dashboard/{pk}` |
|
||||
| `POST` | [Compute and cache a screenshot (dashboard-pk-cache-dashboard-screenshot)](./api/compute-and-cache-a-screenshot-dashboard-pk-cache-dashboard-screenshot) | `/api/v1/dashboard/{pk}/cache_dashboard_screenshot/` |
|
||||
| `PUT` | [Update colors configuration for a dashboard.](./api/update-colors-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/colors` |
|
||||
| `DELETE` | [Remove the dashboard from the user favorite list](./api/remove-the-dashboard-from-the-user-favorite-list) | `/api/v1/dashboard/{pk}/favorites/` |
|
||||
| `POST` | [Mark the dashboard as favorite for the current user](./api/mark-the-dashboard-as-favorite-for-the-current-user) | `/api/v1/dashboard/{pk}/favorites/` |
|
||||
| `PUT` | [Update native filters configuration for a dashboard.](./api/update-native-filters-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/filters` |
|
||||
| `GET` | [Get a computed screenshot from cache (dashboard-pk-screenshot-digest)](./api/get-a-computed-screenshot-from-cache-dashboard-pk-screenshot-digest) | `/api/v1/dashboard/{pk}/screenshot/{digest}/` |
|
||||
| `GET` | [Get dashboard's thumbnail](./api/get-dashboards-thumbnail) | `/api/v1/dashboard/{pk}/thumbnail/{digest}/` |
|
||||
| `GET` | [Download multiple dashboards as YAML files](./api/download-multiple-dashboards-as-yaml-files) | `/api/v1/dashboard/export/` |
|
||||
| `GET` | [Check favorited dashboards for current user](./api/check-favorited-dashboards-for-current-user) | `/api/v1/dashboard/favorite_status/` |
|
||||
| `POST` | [Import dashboard(s) with associated charts/datasets/databases](./api/import-dashboard-s-with-associated-charts-datasets-databases) | `/api/v1/dashboard/import/` |
|
||||
| `GET` | [Get related fields data (dashboard-related-column-name)](./api/get-related-fields-data-dashboard-related-column-name) | `/api/v1/dashboard/related/{column_name}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Charts</strong> (20 endpoints) — Create, read, update, and delete charts (slices).</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `DELETE` | [Bulk delete charts](./api/bulk-delete-charts) | `/api/v1/chart/` |
|
||||
| `GET` | [Get a list of charts](./api/get-a-list-of-charts) | `/api/v1/chart/` |
|
||||
| `POST` | [Create a new chart](./api/create-a-new-chart) | `/api/v1/chart/` |
|
||||
| `GET` | [Get metadata information about this API resource (chart--info)](./api/get-metadata-information-about-this-api-resource-chart-info) | `/api/v1/chart/_info` |
|
||||
| `DELETE` | [Delete a chart](./api/delete-a-chart) | `/api/v1/chart/{pk}` |
|
||||
| `GET` | [Get a chart detail information](./api/get-a-chart-detail-information) | `/api/v1/chart/{pk}` |
|
||||
| `PUT` | [Update a chart](./api/update-a-chart) | `/api/v1/chart/{pk}` |
|
||||
| `GET` | [Compute and cache a screenshot (chart-pk-cache-screenshot)](./api/compute-and-cache-a-screenshot-chart-pk-cache-screenshot) | `/api/v1/chart/{pk}/cache_screenshot/` |
|
||||
| `GET` | [Return payload data response for a chart](./api/return-payload-data-response-for-a-chart) | `/api/v1/chart/{pk}/data/` |
|
||||
| `DELETE` | [Remove the chart from the user favorite list](./api/remove-the-chart-from-the-user-favorite-list) | `/api/v1/chart/{pk}/favorites/` |
|
||||
| `POST` | [Mark the chart as favorite for the current user](./api/mark-the-chart-as-favorite-for-the-current-user) | `/api/v1/chart/{pk}/favorites/` |
|
||||
| `GET` | [Get a computed screenshot from cache (chart-pk-screenshot-digest)](./api/get-a-computed-screenshot-from-cache-chart-pk-screenshot-digest) | `/api/v1/chart/{pk}/screenshot/{digest}/` |
|
||||
| `GET` | [Get chart thumbnail](./api/get-chart-thumbnail) | `/api/v1/chart/{pk}/thumbnail/{digest}/` |
|
||||
| `POST` | [Return payload data response for the given query (chart-data)](./api/return-payload-data-response-for-the-given-query-chart-data) | `/api/v1/chart/data` |
|
||||
| `GET` | [Return payload data response for the given query (chart-data-cache-key)](./api/return-payload-data-response-for-the-given-query-chart-data-cache-key) | `/api/v1/chart/data/{cache_key}` |
|
||||
| `GET` | [Download multiple charts as YAML files](./api/download-multiple-charts-as-yaml-files) | `/api/v1/chart/export/` |
|
||||
| `GET` | [Check favorited charts for current user](./api/check-favorited-charts-for-current-user) | `/api/v1/chart/favorite_status/` |
|
||||
| `POST` | [Import chart(s) with associated datasets and databases](./api/import-chart-s-with-associated-datasets-and-databases) | `/api/v1/chart/import/` |
|
||||
| `GET` | [Get related fields data (chart-related-column-name)](./api/get-related-fields-data-chart-related-column-name) | `/api/v1/chart/related/{column_name}` |
|
||||
| `PUT` | [Warm up the cache for the chart](./api/warm-up-the-cache-for-the-chart) | `/api/v1/chart/warm_up_cache` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Datasets</strong> (18 endpoints) — Manage datasets (tables) used for building charts.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `DELETE` | [Bulk delete datasets](./api/bulk-delete-datasets) | `/api/v1/dataset/` |
|
||||
| `GET` | [Get a list of datasets](./api/get-a-list-of-datasets) | `/api/v1/dataset/` |
|
||||
| `POST` | [Create a new dataset](./api/create-a-new-dataset) | `/api/v1/dataset/` |
|
||||
| `GET` | [Get metadata information about this API resource (dataset--info)](./api/get-metadata-information-about-this-api-resource-dataset-info) | `/api/v1/dataset/_info` |
|
||||
| `DELETE` | [Delete a dataset](./api/delete-a-dataset) | `/api/v1/dataset/{pk}` |
|
||||
| `GET` | [Get a dataset](./api/get-a-dataset) | `/api/v1/dataset/{pk}` |
|
||||
| `PUT` | [Update a dataset](./api/update-a-dataset) | `/api/v1/dataset/{pk}` |
|
||||
| `DELETE` | [Delete a dataset column](./api/delete-a-dataset-column) | `/api/v1/dataset/{pk}/column/{column_id}` |
|
||||
| `DELETE` | [Delete a dataset metric](./api/delete-a-dataset-metric) | `/api/v1/dataset/{pk}/metric/{metric_id}` |
|
||||
| `PUT` | [Refresh and update columns of a dataset](./api/refresh-and-update-columns-of-a-dataset) | `/api/v1/dataset/{pk}/refresh` |
|
||||
| `GET` | [Get charts and dashboards count associated to a dataset](./api/get-charts-and-dashboards-count-associated-to-a-dataset) | `/api/v1/dataset/{pk}/related_objects` |
|
||||
| `GET` | [Get distinct values from field data (dataset-distinct-column-name)](./api/get-distinct-values-from-field-data-dataset-distinct-column-name) | `/api/v1/dataset/distinct/{column_name}` |
|
||||
| `POST` | [Duplicate a dataset](./api/duplicate-a-dataset) | `/api/v1/dataset/duplicate` |
|
||||
| `GET` | [Download multiple datasets as YAML files](./api/download-multiple-datasets-as-yaml-files) | `/api/v1/dataset/export/` |
|
||||
| `POST` | [Retrieve a table by name, or create it if it does not exist](./api/retrieve-a-table-by-name-or-create-it-if-it-does-not-exist) | `/api/v1/dataset/get_or_create/` |
|
||||
| `POST` | [Import dataset(s) with associated databases](./api/import-dataset-s-with-associated-databases) | `/api/v1/dataset/import/` |
|
||||
| `GET` | [Get related fields data (dataset-related-column-name)](./api/get-related-fields-data-dataset-related-column-name) | `/api/v1/dataset/related/{column_name}` |
|
||||
| `PUT` | [Warm up the cache for each chart powered by the given table](./api/warm-up-the-cache-for-each-chart-powered-by-the-given-table) | `/api/v1/dataset/warm_up_cache` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Database</strong> (31 endpoints) — Manage database connections and metadata.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get a list of databases](./api/get-a-list-of-databases) | `/api/v1/database/` |
|
||||
| `POST` | [Create a new database](./api/create-a-new-database) | `/api/v1/database/` |
|
||||
| `GET` | [Get metadata information about this API resource (database--info)](./api/get-metadata-information-about-this-api-resource-database-info) | `/api/v1/database/_info` |
|
||||
| `DELETE` | [Delete a database](./api/delete-a-database) | `/api/v1/database/{pk}` |
|
||||
| `GET` | [Get a database](./api/get-a-database) | `/api/v1/database/{pk}` |
|
||||
| `PUT` | [Change a database](./api/change-a-database) | `/api/v1/database/{pk}` |
|
||||
| `GET` | [Get all catalogs from a database](./api/get-all-catalogs-from-a-database) | `/api/v1/database/{pk}/catalogs/` |
|
||||
| `GET` | [Get a database connection info](./api/get-a-database-connection-info) | `/api/v1/database/{pk}/connection` |
|
||||
| `GET` | [Get function names supported by a database](./api/get-function-names-supported-by-a-database) | `/api/v1/database/{pk}/function_names/` |
|
||||
| `GET` | [Get charts and dashboards count associated to a database](./api/get-charts-and-dashboards-count-associated-to-a-database) | `/api/v1/database/{pk}/related_objects/` |
|
||||
| `GET` | [The list of the database schemas where to upload information](./api/the-list-of-the-database-schemas-where-to-upload-information) | `/api/v1/database/{pk}/schemas_access_for_file_upload/` |
|
||||
| `GET` | [Get all schemas from a database](./api/get-all-schemas-from-a-database) | `/api/v1/database/{pk}/schemas/` |
|
||||
| `GET` | [Get database select star for table (database-pk-select-star-table-name)](./api/get-database-select-star-for-table-database-pk-select-star-table-name) | `/api/v1/database/{pk}/select_star/{table_name}/` |
|
||||
| `GET` | [Get database select star for table (database-pk-select-star-table-name-schema-name)](./api/get-database-select-star-for-table-database-pk-select-star-table-name-schema-name) | `/api/v1/database/{pk}/select_star/{table_name}/{schema_name}/` |
|
||||
| `DELETE` | [Delete a SSH tunnel](./api/delete-a-ssh-tunnel) | `/api/v1/database/{pk}/ssh_tunnel/` |
|
||||
| `POST` | [Re-sync all permissions for a database connection](./api/re-sync-all-permissions-for-a-database-connection) | `/api/v1/database/{pk}/sync_permissions/` |
|
||||
| `GET` | [Get table extra metadata (database-pk-table-extra-table-name-schema-name)](./api/get-table-extra-metadata-database-pk-table-extra-table-name-schema-name) | `/api/v1/database/{pk}/table_extra/{table_name}/{schema_name}/` |
|
||||
| `GET` | [Get table metadata](./api/get-table-metadata) | `/api/v1/database/{pk}/table_metadata/` |
|
||||
| `GET` | [Get table extra metadata (database-pk-table-metadata-extra)](./api/get-table-extra-metadata-database-pk-table-metadata-extra) | `/api/v1/database/{pk}/table_metadata/extra/` |
|
||||
| `GET` | [Get database table metadata](./api/get-database-table-metadata) | `/api/v1/database/{pk}/table/{table_name}/{schema_name}/` |
|
||||
| `GET` | [Get a list of tables for given database](./api/get-a-list-of-tables-for-given-database) | `/api/v1/database/{pk}/tables/` |
|
||||
| `POST` | [Upload a file to a database table](./api/upload-a-file-to-a-database-table) | `/api/v1/database/{pk}/upload/` |
|
||||
| `POST` | [Validate arbitrary SQL](./api/validate-arbitrary-sql) | `/api/v1/database/{pk}/validate_sql/` |
|
||||
| `GET` | [Get names of databases currently available](./api/get-names-of-databases-currently-available) | `/api/v1/database/available/` |
|
||||
| `GET` | [Download database(s) and associated dataset(s) as a zip file](./api/download-database-s-and-associated-dataset-s-as-a-zip-file) | `/api/v1/database/export/` |
|
||||
| `POST` | [Import database(s) with associated datasets](./api/import-database-s-with-associated-datasets) | `/api/v1/database/import/` |
|
||||
| `GET` | [Receive personal access tokens from OAuth2](./api/receive-personal-access-tokens-from-o-auth-2) | `/api/v1/database/oauth2/` |
|
||||
| `GET` | [Get related fields data (database-related-column-name)](./api/get-related-fields-data-database-related-column-name) | `/api/v1/database/related/{column_name}` |
|
||||
| `POST` | [Test a database connection](./api/test-a-database-connection) | `/api/v1/database/test_connection/` |
|
||||
| `POST` | [Upload a file and returns file metadata](./api/upload-a-file-and-returns-file-metadata) | `/api/v1/database/upload_metadata/` |
|
||||
| `POST` | [Validate database connection parameters](./api/validate-database-connection-parameters) | `/api/v1/database/validate_parameters/` |
|
||||
|
||||
</details>
|
||||
|
||||
#### Data Exploration
|
||||
|
||||
<details>
|
||||
<summary><strong>Explore</strong> (1 endpoints) — Chart exploration and data querying endpoints.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Assemble Explore related information in a single endpoint](./api/assemble-explore-related-information-in-a-single-endpoint) | `/api/v1/explore/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>SQL Lab</strong> (6 endpoints) — Execute SQL queries and manage SQL Lab sessions.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get the bootstrap data for SqlLab page](./api/get-the-bootstrap-data-for-sql-lab-page) | `/api/v1/sqllab/` |
|
||||
| `POST` | [Estimate the SQL query execution cost](./api/estimate-the-sql-query-execution-cost) | `/api/v1/sqllab/estimate/` |
|
||||
| `POST` | [Execute a SQL query](./api/execute-a-sql-query) | `/api/v1/sqllab/execute/` |
|
||||
| `GET` | [Export the SQL query results to a CSV](./api/export-the-sql-query-results-to-a-csv) | `/api/v1/sqllab/export/{client_id}/` |
|
||||
| `POST` | [Format SQL code](./api/format-sql-code) | `/api/v1/sqllab/format_sql/` |
|
||||
| `GET` | [Get the result of a SQL query execution](./api/get-the-result-of-a-sql-query-execution) | `/api/v1/sqllab/results/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Queries</strong> (17 endpoints) — View and manage SQL Lab query history.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get a list of queries](./api/get-a-list-of-queries) | `/api/v1/query/` |
|
||||
| `GET` | [Get query detail information](./api/get-query-detail-information) | `/api/v1/query/{pk}` |
|
||||
| `GET` | [Get distinct values from field data (query-distinct-column-name)](./api/get-distinct-values-from-field-data-query-distinct-column-name) | `/api/v1/query/distinct/{column_name}` |
|
||||
| `GET` | [Get related fields data (query-related-column-name)](./api/get-related-fields-data-query-related-column-name) | `/api/v1/query/related/{column_name}` |
|
||||
| `POST` | [Manually stop a query with client_id](./api/manually-stop-a-query-with-client-id) | `/api/v1/query/stop` |
|
||||
| `GET` | [Get a list of queries that changed after last_updated_ms](./api/get-a-list-of-queries-that-changed-after-last-updated-ms) | `/api/v1/query/updated_since` |
|
||||
| `DELETE` | [Bulk delete saved queries](./api/bulk-delete-saved-queries) | `/api/v1/saved_query/` |
|
||||
| `GET` | [Get a list of saved queries](./api/get-a-list-of-saved-queries) | `/api/v1/saved_query/` |
|
||||
| `POST` | [Create a saved query](./api/create-a-saved-query) | `/api/v1/saved_query/` |
|
||||
| `GET` | [Get metadata information about this API resource (saved-query--info)](./api/get-metadata-information-about-this-api-resource-saved-query-info) | `/api/v1/saved_query/_info` |
|
||||
| `DELETE` | [Delete a saved query](./api/delete-a-saved-query) | `/api/v1/saved_query/{pk}` |
|
||||
| `GET` | [Get a saved query](./api/get-a-saved-query) | `/api/v1/saved_query/{pk}` |
|
||||
| `PUT` | [Update a saved query](./api/update-a-saved-query) | `/api/v1/saved_query/{pk}` |
|
||||
| `GET` | [Get distinct values from field data (saved-query-distinct-column-name)](./api/get-distinct-values-from-field-data-saved-query-distinct-column-name) | `/api/v1/saved_query/distinct/{column_name}` |
|
||||
| `GET` | [Download multiple saved queries as YAML files](./api/download-multiple-saved-queries-as-yaml-files) | `/api/v1/saved_query/export/` |
|
||||
| `POST` | [Import saved queries with associated databases](./api/import-saved-queries-with-associated-databases) | `/api/v1/saved_query/import/` |
|
||||
| `GET` | [Get related fields data (saved-query-related-column-name)](./api/get-related-fields-data-saved-query-related-column-name) | `/api/v1/saved_query/related/{column_name}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Datasources</strong> (1 endpoints) — Query datasource metadata and column values.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get possible values for a datasource column](./api/get-possible-values-for-a-datasource-column) | `/api/v1/datasource/{datasource_type}/{datasource_id}/column/{column_name}/values/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Advanced Data Type</strong> (2 endpoints) — Endpoints for advanced data type operations and conversions.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Return an AdvancedDataTypeResponse](./api/return-an-advanced-data-type-response) | `/api/v1/advanced_data_type/convert` |
|
||||
| `GET` | [Return a list of available advanced data types](./api/return-a-list-of-available-advanced-data-types) | `/api/v1/advanced_data_type/types` |
|
||||
|
||||
</details>
|
||||
|
||||
#### Organization & Customization
|
||||
|
||||
<details>
|
||||
<summary><strong>Tags</strong> (15 endpoints) — Organize assets with tags.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `DELETE` | [Bulk delete tags](./api/bulk-delete-tags) | `/api/v1/tag/` |
|
||||
| `GET` | [Get a list of tags](./api/get-a-list-of-tags) | `/api/v1/tag/` |
|
||||
| `POST` | [Create a tag](./api/create-a-tag) | `/api/v1/tag/` |
|
||||
| `GET` | [Get metadata information about tag API endpoints](./api/get-metadata-information-about-tag-api-endpoints) | `/api/v1/tag/_info` |
|
||||
| `POST` | [Add tags to an object](./api/add-tags-to-an-object) | `/api/v1/tag/{object_type}/{object_id}/` |
|
||||
| `DELETE` | [Delete a tagged object](./api/delete-a-tagged-object) | `/api/v1/tag/{object_type}/{object_id}/{tag}/` |
|
||||
| `DELETE` | [Delete a tag](./api/delete-a-tag) | `/api/v1/tag/{pk}` |
|
||||
| `GET` | [Get a tag detail information](./api/get-a-tag-detail-information) | `/api/v1/tag/{pk}` |
|
||||
| `PUT` | [Update a tag](./api/update-a-tag) | `/api/v1/tag/{pk}` |
|
||||
| `DELETE` | [Delete tag by pk favorites](./api/delete-tag-by-pk-favorites) | `/api/v1/tag/{pk}/favorites/` |
|
||||
| `POST` | [Create tag by pk favorites](./api/create-tag-by-pk-favorites) | `/api/v1/tag/{pk}/favorites/` |
|
||||
| `POST` | [Bulk create tags and tagged objects](./api/bulk-create-tags-and-tagged-objects) | `/api/v1/tag/bulk_create` |
|
||||
| `GET` | [Get tag favorite status](./api/get-tag-favorite-status) | `/api/v1/tag/favorite_status/` |
|
||||
| `GET` | [Get all objects associated with a tag](./api/get-all-objects-associated-with-a-tag) | `/api/v1/tag/get_objects/` |
|
||||
| `GET` | [Get related fields data (tag-related-column-name)](./api/get-related-fields-data-tag-related-column-name) | `/api/v1/tag/related/{column_name}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Annotation Layers</strong> (14 endpoints) — Manage annotation layers and annotations for charts.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `DELETE` | [Delete multiple annotation layers in a bulk operation](./api/delete-multiple-annotation-layers-in-a-bulk-operation) | `/api/v1/annotation_layer/` |
|
||||
| `GET` | [Get a list of annotation layers (annotation-layer)](./api/get-a-list-of-annotation-layers-annotation-layer) | `/api/v1/annotation_layer/` |
|
||||
| `POST` | [Create an annotation layer (annotation-layer)](./api/create-an-annotation-layer-annotation-layer) | `/api/v1/annotation_layer/` |
|
||||
| `GET` | [Get metadata information about this API resource (annotation-layer--info)](./api/get-metadata-information-about-this-api-resource-annotation-layer-info) | `/api/v1/annotation_layer/_info` |
|
||||
| `DELETE` | [Delete annotation layer (annotation-layer-pk)](./api/delete-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
|
||||
| `GET` | [Get an annotation layer (annotation-layer-pk)](./api/get-an-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
|
||||
| `PUT` | [Update an annotation layer (annotation-layer-pk)](./api/update-an-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
|
||||
| `DELETE` | [Bulk delete annotation layers](./api/bulk-delete-annotation-layers) | `/api/v1/annotation_layer/{pk}/annotation/` |
|
||||
| `GET` | [Get a list of annotation layers (annotation-layer-pk-annotation)](./api/get-a-list-of-annotation-layers-annotation-layer-pk-annotation) | `/api/v1/annotation_layer/{pk}/annotation/` |
|
||||
| `POST` | [Create an annotation layer (annotation-layer-pk-annotation)](./api/create-an-annotation-layer-annotation-layer-pk-annotation) | `/api/v1/annotation_layer/{pk}/annotation/` |
|
||||
| `DELETE` | [Delete annotation layer (annotation-layer-pk-annotation-annotation-id)](./api/delete-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
|
||||
| `GET` | [Get an annotation layer (annotation-layer-pk-annotation-annotation-id)](./api/get-an-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
|
||||
| `PUT` | [Update an annotation layer (annotation-layer-pk-annotation-annotation-id)](./api/update-an-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
|
||||
| `GET` | [Get related fields data (annotation-layer-related-column-name)](./api/get-related-fields-data-annotation-layer-related-column-name) | `/api/v1/annotation_layer/related/{column_name}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>CSS Templates</strong> (8 endpoints) — Manage CSS templates for custom dashboard styling.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `DELETE` | [Bulk delete CSS templates](./api/bulk-delete-css-templates) | `/api/v1/css_template/` |
|
||||
| `GET` | [Get a list of CSS templates](./api/get-a-list-of-css-templates) | `/api/v1/css_template/` |
|
||||
| `POST` | [Create a CSS template](./api/create-a-css-template) | `/api/v1/css_template/` |
|
||||
| `GET` | [Get metadata information about this API resource (css-template--info)](./api/get-metadata-information-about-this-api-resource-css-template-info) | `/api/v1/css_template/_info` |
|
||||
| `DELETE` | [Delete a CSS template](./api/delete-a-css-template) | `/api/v1/css_template/{pk}` |
|
||||
| `GET` | [Get a CSS template](./api/get-a-css-template) | `/api/v1/css_template/{pk}` |
|
||||
| `PUT` | [Update a CSS template](./api/update-a-css-template) | `/api/v1/css_template/{pk}` |
|
||||
| `GET` | [Get related fields data (css-template-related-column-name)](./api/get-related-fields-data-css-template-related-column-name) | `/api/v1/css_template/related/{column_name}` |
|
||||
|
||||
</details>
|
||||
|
||||
#### Sharing & Embedding
|
||||
|
||||
<details>
|
||||
<summary><strong>Dashboard Permanent Link</strong> (2 endpoints) — Create and retrieve permanent links to dashboard states.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a new dashboard's permanent link](./api/create-a-new-dashboards-permanent-link) | `/api/v1/dashboard/{pk}/permalink` |
|
||||
| `GET` | [Get dashboard's permanent link state](./api/get-dashboards-permanent-link-state) | `/api/v1/dashboard/permalink/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Explore Permanent Link</strong> (2 endpoints) — Create and retrieve permanent links to chart explore states.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a new permanent link (explore-permalink)](./api/create-a-new-permanent-link-explore-permalink) | `/api/v1/explore/permalink` |
|
||||
| `GET` | [Get chart's permanent link state](./api/get-charts-permanent-link-state) | `/api/v1/explore/permalink/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>SQL Lab Permanent Link</strong> (2 endpoints) — Create and retrieve permanent links to SQL Lab states.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a new permanent link (sqllab-permalink)](./api/create-a-new-permanent-link-sqllab-permalink) | `/api/v1/sqllab/permalink` |
|
||||
| `GET` | [Get permanent link state for SQLLab editor.](./api/get-permanent-link-state-for-sql-lab-editor) | `/api/v1/sqllab/permalink/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Embedded Dashboard</strong> (1 endpoints) — Configure embedded dashboard settings.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get a report schedule log (embedded-dashboard-uuid)](./api/get-a-report-schedule-log-embedded-dashboard-uuid) | `/api/v1/embedded_dashboard/{uuid}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Dashboard Filter State</strong> (4 endpoints) — Manage temporary filter state for dashboards.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a dashboard's filter state](./api/create-a-dashboards-filter-state) | `/api/v1/dashboard/{pk}/filter_state` |
|
||||
| `DELETE` | [Delete a dashboard's filter state value](./api/delete-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
| `GET` | [Get a dashboard's filter state value](./api/get-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
| `PUT` | [Update a dashboard's filter state value](./api/update-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Explore Form Data</strong> (4 endpoints) — Manage temporary form data for chart exploration.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a new form_data](./api/create-a-new-form-data) | `/api/v1/explore/form_data` |
|
||||
| `DELETE` | [Delete a form_data](./api/delete-a-form-data) | `/api/v1/explore/form_data/{key}` |
|
||||
| `GET` | [Get a form_data](./api/get-a-form-data) | `/api/v1/explore/form_data/{key}` |
|
||||
| `PUT` | [Update an existing form_data](./api/update-an-existing-form-data) | `/api/v1/explore/form_data/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
#### Scheduling & Alerts
|
||||
|
||||
<details>
|
||||
<summary><strong>Report Schedules</strong> (11 endpoints) — Configure scheduled reports and alerts.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `DELETE` | [Bulk delete report schedules](./api/bulk-delete-report-schedules) | `/api/v1/report/` |
|
||||
| `GET` | [Get a list of report schedules](./api/get-a-list-of-report-schedules) | `/api/v1/report/` |
|
||||
| `POST` | [Create a report schedule](./api/create-a-report-schedule) | `/api/v1/report/` |
|
||||
| `GET` | [Get metadata information about this API resource (report--info)](./api/get-metadata-information-about-this-api-resource-report-info) | `/api/v1/report/_info` |
|
||||
| `DELETE` | [Delete a report schedule](./api/delete-a-report-schedule) | `/api/v1/report/{pk}` |
|
||||
| `GET` | [Get a report schedule](./api/get-a-report-schedule) | `/api/v1/report/{pk}` |
|
||||
| `PUT` | [Update a report schedule](./api/update-a-report-schedule) | `/api/v1/report/{pk}` |
|
||||
| `GET` | [Get a list of report schedule logs](./api/get-a-list-of-report-schedule-logs) | `/api/v1/report/{pk}/log/` |
|
||||
| `GET` | [Get a report schedule log (report-pk-log-log-id)](./api/get-a-report-schedule-log-report-pk-log-log-id) | `/api/v1/report/{pk}/log/{log_id}` |
|
||||
| `GET` | [Get related fields data (report-related-column-name)](./api/get-related-fields-data-report-related-column-name) | `/api/v1/report/related/{column_name}` |
|
||||
| `GET` | [Get slack channels](./api/get-slack-channels) | `/api/v1/report/slack_channels/` |
|
||||
|
||||
</details>
|
||||
|
||||
#### Security & Access Control
|
||||
|
||||
<details>
|
||||
<summary><strong>Security Roles</strong> (10 endpoints) — Manage security roles and their permissions.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security roles](./api/get-security-roles) | `/api/v1/security/roles/` |
|
||||
| `POST` | [Create security roles](./api/create-security-roles) | `/api/v1/security/roles/` |
|
||||
| `GET` | [Get security roles info](./api/get-security-roles-info) | `/api/v1/security/roles/_info` |
|
||||
| `DELETE` | [Delete security roles by pk](./api/delete-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
|
||||
| `GET` | [Get security roles by pk](./api/get-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
|
||||
| `PUT` | [Update security roles by pk](./api/update-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
|
||||
| `POST` | [Create security roles by role_id permissions](./api/create-security-roles-by-role-id-permissions) | `/api/v1/security/roles/{role_id}/permissions` |
|
||||
| `GET` | [Get security roles by role_id permissions](./api/get-security-roles-by-role-id-permissions) | `/api/v1/security/roles/{role_id}/permissions/` |
|
||||
| `PUT` | [Update security roles by role_id users](./api/update-security-roles-by-role-id-users) | `/api/v1/security/roles/{role_id}/users` |
|
||||
| `GET` | [List roles](./api/list-roles) | `/api/v1/security/roles/search/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Security Users</strong> (6 endpoints) — Manage user accounts.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security users](./api/get-security-users) | `/api/v1/security/users/` |
|
||||
| `POST` | [Create security users](./api/create-security-users) | `/api/v1/security/users/` |
|
||||
| `GET` | [Get security users info](./api/get-security-users-info) | `/api/v1/security/users/_info` |
|
||||
| `DELETE` | [Delete security users by pk](./api/delete-security-users-by-pk) | `/api/v1/security/users/{pk}` |
|
||||
| `GET` | [Get security users by pk](./api/get-security-users-by-pk) | `/api/v1/security/users/{pk}` |
|
||||
| `PUT` | [Update security users by pk](./api/update-security-users-by-pk) | `/api/v1/security/users/{pk}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Security Permissions</strong> (3 endpoints) — View available permissions.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security permissions](./api/get-security-permissions) | `/api/v1/security/permissions/` |
|
||||
| `GET` | [Get security permissions info](./api/get-security-permissions-info) | `/api/v1/security/permissions/_info` |
|
||||
| `GET` | [Get security permissions by pk](./api/get-security-permissions-by-pk) | `/api/v1/security/permissions/{pk}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Security Resources (View Menus)</strong> (6 endpoints) — Manage security resources (view menus).</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security resources](./api/get-security-resources) | `/api/v1/security/resources/` |
|
||||
| `POST` | [Create security resources](./api/create-security-resources) | `/api/v1/security/resources/` |
|
||||
| `GET` | [Get security resources info](./api/get-security-resources-info) | `/api/v1/security/resources/_info` |
|
||||
| `DELETE` | [Delete security resources by pk](./api/delete-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
|
||||
| `GET` | [Get security resources by pk](./api/get-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
|
||||
| `PUT` | [Update security resources by pk](./api/update-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Security Permissions on Resources (View Menus)</strong> (6 endpoints) — Manage permission-resource mappings.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security permissions resources](./api/get-security-permissions-resources) | `/api/v1/security/permissions-resources/` |
|
||||
| `POST` | [Create security permissions resources](./api/create-security-permissions-resources) | `/api/v1/security/permissions-resources/` |
|
||||
| `GET` | [Get security permissions resources info](./api/get-security-permissions-resources-info) | `/api/v1/security/permissions-resources/_info` |
|
||||
| `DELETE` | [Delete security permissions resources by pk](./api/delete-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
|
||||
| `GET` | [Get security permissions resources by pk](./api/get-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
|
||||
| `PUT` | [Update security permissions resources by pk](./api/update-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Row Level Security</strong> (8 endpoints) — Manage row-level security rules for data access control.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `DELETE` | [Bulk delete RLS rules](./api/bulk-delete-rls-rules) | `/api/v1/rowlevelsecurity/` |
|
||||
| `GET` | [Get a list of RLS](./api/get-a-list-of-rls) | `/api/v1/rowlevelsecurity/` |
|
||||
| `POST` | [Create a new RLS rule](./api/create-a-new-rls-rule) | `/api/v1/rowlevelsecurity/` |
|
||||
| `GET` | [Get metadata information about this API resource (rowlevelsecurity--info)](./api/get-metadata-information-about-this-api-resource-rowlevelsecurity-info) | `/api/v1/rowlevelsecurity/_info` |
|
||||
| `DELETE` | [Delete an RLS](./api/delete-an-rls) | `/api/v1/rowlevelsecurity/{pk}` |
|
||||
| `GET` | [Get an RLS](./api/get-an-rls) | `/api/v1/rowlevelsecurity/{pk}` |
|
||||
| `PUT` | [Update an RLS rule](./api/update-an-rls-rule) | `/api/v1/rowlevelsecurity/{pk}` |
|
||||
| `GET` | [Get related fields data (rowlevelsecurity-related-column-name)](./api/get-related-fields-data-rowlevelsecurity-related-column-name) | `/api/v1/rowlevelsecurity/related/{column_name}` |
|
||||
|
||||
</details>
|
||||
|
||||
#### Import/Export & Administration
|
||||
|
||||
<details>
|
||||
<summary><strong>Import/export</strong> (2 endpoints) — Import and export Superset assets (dashboards, charts, databases).</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Export all assets](./api/export-all-assets) | `/api/v1/assets/export/` |
|
||||
| `POST` | [Import multiple assets](./api/import-multiple-assets) | `/api/v1/assets/import/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>CacheRestApi</strong> (1 endpoints) — Cache management and invalidation operations.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Invalidate cache records and remove the database records](./api/invalidate-cache-records-and-remove-the-database-records) | `/api/v1/cachekey/invalidate` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>LogRestApi</strong> (4 endpoints) — Access audit logs and activity history.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get a list of logs](./api/get-a-list-of-logs) | `/api/v1/log/` |
|
||||
| `POST` | [Create log](./api/create-log) | `/api/v1/log/` |
|
||||
| `GET` | [Get a log detail information](./api/get-a-log-detail-information) | `/api/v1/log/{pk}` |
|
||||
| `GET` | [Get recent activity data for a user](./api/get-recent-activity-data-for-a-user) | `/api/v1/log/recent_activity/` |
|
||||
|
||||
</details>
|
||||
|
||||
#### User & System
|
||||
|
||||
<details>
|
||||
<summary><strong>Current User</strong> (2 endpoints) — Get information about the currently authenticated user.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get the user object](./api/get-the-user-object) | `/api/v1/me/` |
|
||||
| `GET` | [Get the user roles](./api/get-the-user-roles) | `/api/v1/me/roles/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>User</strong> (1 endpoints) — User profile and preferences.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get the user avatar](./api/get-the-user-avatar) | `/api/v1/user/{user_id}/avatar.png` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Menu</strong> (1 endpoints) — Get the Superset menu structure.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get menu](./api/get-menu) | `/api/v1/menu/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Available Domains</strong> (1 endpoints) — Get available domains for the Superset instance.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get all available domains](./api/get-all-available-domains) | `/api/v1/available_domains/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>AsyncEventsRestApi</strong> (1 endpoints) — Real-time event streaming via Server-Sent Events (SSE).</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Read off of the Redis events stream](./api/read-off-of-the-redis-events-stream) | `/api/v1/async_event/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>OpenApi</strong> (1 endpoints) — Access the OpenAPI specification.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get api by version openapi](./api/get-api-by-version-openapi) | `/api/{version}/_openapi` |
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
### Additional Resources
|
||||
|
||||
- [Superset REST API Blog Post](https://preset.io/blog/2020-10-01-superset-api/)
|
||||
- [Accessing APIs with Superset](https://preset.io/blog/accessing-apis-with-superset/)
|
||||
@@ -1,405 +0,0 @@
|
||||
---
|
||||
title: Alerts and Reports
|
||||
hide_title: true
|
||||
sidebar_position: 2
|
||||
version: 2
|
||||
---
|
||||
|
||||
# Alerts and Reports
|
||||
|
||||
Users can configure automated alerts and reports to send dashboards or charts to an email recipient or Slack channel.
|
||||
|
||||
- *Alerts* are sent when a SQL condition is reached
|
||||
- *Reports* are sent on a schedule
|
||||
|
||||
Alerts and reports are disabled by default. To turn them on, you'll need to change configuration settings and install a suitable headless browser in your environment.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Commons
|
||||
|
||||
#### In your `superset_config.py` or `superset_config_docker.py`
|
||||
|
||||
- `"ALERT_REPORTS"` [feature flag](/docs/configuration/configuring-superset#feature-flags) must be turned to True.
|
||||
- `beat_schedule` in CeleryConfig must contain schedule for `reports.scheduler`.
|
||||
- At least one of those must be configured, depending on what you want to use:
|
||||
- emails: `SMTP_*` settings
|
||||
- Slack messages: `SLACK_API_TOKEN`
|
||||
- Users can customize the email subject by including date code placeholders, which will automatically be replaced with the corresponding UTC date when the email is sent. To enable this functionality, activate the `"DATE_FORMAT_IN_EMAIL_SUBJECT"` [feature flag](/docs/configuration/configuring-superset#feature-flags). This enables date formatting in email subjects, preventing all reporting emails from being grouped into the same thread (optional for the reporting feature).
|
||||
- Use date codes from [strftime.org](https://strftime.org/) to create the email subject.
|
||||
- If no date code is provided, the original string will be used as the email subject.
|
||||
|
||||
##### Disable dry-run mode
|
||||
|
||||
Screenshots will be taken but no messages actually sent as long as `ALERT_REPORTS_NOTIFICATION_DRY_RUN = True`, its default value in `docker/pythonpath_dev/superset_config.py`. To disable dry-run mode and start receiving email/Slack notifications, set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py).
|
||||
|
||||
#### In your `Dockerfile`
|
||||
|
||||
You'll need to extend the Superset image to include a headless browser. Your options include:
|
||||
- Use Playwright with Chrome: this is the recommended approach as of version 4.1.x or greater. A working example of a Dockerfile that installs these tools is provided under "Building your own production Docker image" on the [Docker Builds](/docs/installation/docker-builds#building-your-own-production-docker-image) page. Read the code comments there as you'll also need to change a feature flag in your config.
|
||||
- Use Firefox: you'll need to install geckodriver and Firefox.
|
||||
- Use Chrome without Playwright: you'll need to install Chrome and set the value of `WEBDRIVER_TYPE` to `"chrome"` in your `superset_config.py`.
|
||||
|
||||
In Superset versions <=4.0x, users installed Firefox or Chrome and that was documented here.
|
||||
|
||||
Only the worker container needs the browser.
|
||||
|
||||
### Slack integration
|
||||
|
||||
To send alerts and reports to Slack channels, you need to create a new Slack Application on your workspace.
|
||||
|
||||
1. Connect to your Slack workspace, then head to [https://api.slack.com/apps].
|
||||
2. Create a new app.
|
||||
3. Go to "OAuth & Permissions" section, and give the following scopes to your app:
|
||||
- `incoming-webhook`
|
||||
- `files:write`
|
||||
- `chat:write`
|
||||
- `channels:read`
|
||||
- `groups:read`
|
||||
4. At the top of the "OAuth and Permissions" section, click "install to workspace".
|
||||
5. Select a default channel for your app and continue.
|
||||
(You can post to any channel by inviting your Superset app into that channel).
|
||||
6. The app should now be installed in your workspace, and a "Bot User OAuth Access Token" should have been created. Copy that token in the `SLACK_API_TOKEN` variable of your `superset_config.py`.
|
||||
7. Ensure the feature flag `ALERT_REPORT_SLACK_V2` is set to True in `superset_config.py`
|
||||
8. Restart the service (or run `superset init`) to pull in the new configuration.
|
||||
|
||||
Note: when you configure an alert or a report, the Slack channel list takes channel names without the leading '#' e.g. use `alerts` instead of `#alerts`.
|
||||
|
||||
#### Large Slack Workspaces (10k+ channels)
|
||||
|
||||
For workspaces with many channels, fetching the complete channel list can take several minutes and may encounter Slack API rate limits. Add the following to your `superset_config.py`:
|
||||
|
||||
```python
|
||||
from datetime import timedelta
|
||||
|
||||
# Increase cache timeout to reduce API calls
|
||||
# Default: 1 day (86400 seconds)
|
||||
SLACK_CACHE_TIMEOUT = int(timedelta(days=2).total_seconds())
|
||||
|
||||
# Increase retry count for rate limit errors
|
||||
# Default: 2
|
||||
SLACK_API_RATE_LIMIT_RETRY_COUNT = 5
|
||||
```
|
||||
|
||||
### Kubernetes-specific
|
||||
|
||||
- You must have a `celery beat` pod running. If you're using the chart included in the GitHub repository under [helm/superset](https://github.com/apache/superset/tree/master/helm/superset), you need to put `supersetCeleryBeat.enabled = true` in your values override.
|
||||
- You can see the dedicated docs about [Kubernetes installation](/docs/installation/kubernetes) for more details.
|
||||
|
||||
### Docker Compose specific
|
||||
|
||||
#### You must have in your `docker-compose.yml`
|
||||
|
||||
- A Redis message broker
|
||||
- PostgreSQL DB instead of SQLlite
|
||||
- One or more `celery worker`
|
||||
- A single `celery beat`
|
||||
|
||||
This process also works in a Docker swarm environment, you would just need to add `Deploy:` to the Superset, Redis and Postgres services along with your specific configs for your swarm.
|
||||
|
||||
### Detailed config
|
||||
|
||||
The following configurations need to be added to the `superset_config.py` file. This file is loaded when the image runs, and any configurations in it will override the default configurations found in the `config.py`.
|
||||
|
||||
You can find documentation about each field in the default `config.py` in the GitHub repository under [superset/config.py](https://github.com/apache/superset/blob/master/superset/config.py).
|
||||
|
||||
You need to replace default values with your custom Redis, Slack and/or SMTP config.
|
||||
|
||||
Superset uses Celery beat and Celery worker(s) to send alerts and reports.
|
||||
|
||||
- The beat is the scheduler that tells the worker when to perform its tasks. This schedule is defined when you create the alert or report.
|
||||
- The worker will process the tasks that need to be performed when an alert or report is fired.
|
||||
|
||||
In the `CeleryConfig`, only the `beat_schedule` is relevant to this feature, the rest of the `CeleryConfig` can be changed for your needs.
|
||||
|
||||
```python
|
||||
from celery.schedules import crontab
|
||||
|
||||
FEATURE_FLAGS = {
|
||||
"ALERT_REPORTS": True
|
||||
}
|
||||
|
||||
REDIS_HOST = "superset_cache"
|
||||
REDIS_PORT = "6379"
|
||||
|
||||
class CeleryConfig:
|
||||
broker_url = f"redis://{REDIS_HOST}:{REDIS_PORT}/0"
|
||||
imports = (
|
||||
"superset.sql_lab",
|
||||
"superset.tasks.scheduler",
|
||||
)
|
||||
result_backend = f"redis://{REDIS_HOST}:{REDIS_PORT}/0"
|
||||
worker_prefetch_multiplier = 10
|
||||
task_acks_late = True
|
||||
task_annotations = {
|
||||
"sql_lab.get_sql_results": {
|
||||
"rate_limit": "100/s",
|
||||
},
|
||||
}
|
||||
beat_schedule = {
|
||||
"reports.scheduler": {
|
||||
"task": "reports.scheduler",
|
||||
"schedule": crontab(minute="*", hour="*"),
|
||||
},
|
||||
"reports.prune_log": {
|
||||
"task": "reports.prune_log",
|
||||
"schedule": crontab(minute=0, hour=0),
|
||||
},
|
||||
}
|
||||
CELERY_CONFIG = CeleryConfig
|
||||
|
||||
SCREENSHOT_LOCATE_WAIT = 100
|
||||
SCREENSHOT_LOAD_WAIT = 600
|
||||
|
||||
# Slack configuration
|
||||
SLACK_API_TOKEN = "xoxb-"
|
||||
|
||||
# Email configuration
|
||||
SMTP_HOST = "smtp.sendgrid.net" # change to your host
|
||||
SMTP_PORT = 2525 # your port, e.g. 587
|
||||
SMTP_STARTTLS = True
|
||||
SMTP_SSL_SERVER_AUTH = True # If you're using an SMTP server with a valid certificate
|
||||
SMTP_SSL = False
|
||||
SMTP_USER = "your_user" # use the empty string "" if using an unauthenticated SMTP server
|
||||
SMTP_PASSWORD = "your_password" # use the empty string "" if using an unauthenticated SMTP server
|
||||
SMTP_MAIL_FROM = "noreply@youremail.com"
|
||||
EMAIL_REPORTS_SUBJECT_PREFIX = "[Superset] " # optional - overwrites default value in config.py of "[Report] "
|
||||
|
||||
# WebDriver configuration
|
||||
# If you use Firefox or Playwright with Chrome, you can stick with default values
|
||||
# If you use Chrome and are *not* using Playwright, then add the following WEBDRIVER_TYPE and WEBDRIVER_OPTION_ARGS
|
||||
WEBDRIVER_TYPE = "chrome"
|
||||
WEBDRIVER_OPTION_ARGS = [
|
||||
"--force-device-scale-factor=2.0",
|
||||
"--high-dpi-support=2.0",
|
||||
"--headless",
|
||||
"--disable-gpu",
|
||||
"--disable-dev-shm-usage",
|
||||
"--no-sandbox",
|
||||
"--disable-setuid-sandbox",
|
||||
"--disable-extensions",
|
||||
]
|
||||
|
||||
# This is for internal use, you can keep http
|
||||
WEBDRIVER_BASEURL = "http://superset:8088" # When running using docker compose use "http://superset_app:8088'
|
||||
# This is the link sent to the recipient. Change to your domain, e.g. https://superset.mydomain.com
|
||||
WEBDRIVER_BASEURL_USER_FRIENDLY = "http://localhost:8088"
|
||||
```
|
||||
|
||||
You also need
|
||||
to specify on behalf of which username to render the dashboards. In general, dashboards and charts
|
||||
are not accessible to unauthorized requests, that is why the worker needs to take over credentials
|
||||
of an existing user to take a snapshot.
|
||||
|
||||
By default, Alerts and Reports are executed as the owner of the alert/report object. To use a fixed user account,
|
||||
just change the config as follows (`admin` in this example):
|
||||
|
||||
```python
|
||||
from superset.tasks.types import FixedExecutor
|
||||
|
||||
ALERT_REPORTS_EXECUTORS = [FixedExecutor("admin")]
|
||||
```
|
||||
|
||||
Please refer to `ExecutorType` in the codebase for other executor types.
|
||||
|
||||
**Important notes**
|
||||
|
||||
- Be mindful of the concurrency setting for celery (using `-c 4`). Selenium/webdriver instances can
|
||||
consume a lot of CPU / memory on your servers.
|
||||
- In some cases, if you notice a lot of leaked geckodriver processes, try running your celery
|
||||
processes with `celery worker --pool=prefork --max-tasks-per-child=128 ...`
|
||||
- It is recommended to run separate workers for the `sql_lab` and `email_reports` tasks. This can be
|
||||
done using the `queue` field in `task_annotations`.
|
||||
- Adjust `WEBDRIVER_BASEURL` in your configuration file if celery workers can’t access Superset via
|
||||
its default value of `http://0.0.0.0:8080/`.
|
||||
|
||||
It's also possible to specify a minimum interval between each report's execution through the config file:
|
||||
|
||||
``` python
|
||||
# Set a minimum interval threshold between executions (for each Alert/Report)
|
||||
# Value should be an integer
|
||||
ALERT_MINIMUM_INTERVAL = int(timedelta(minutes=10).total_seconds())
|
||||
REPORT_MINIMUM_INTERVAL = int(timedelta(minutes=5).total_seconds())
|
||||
```
|
||||
|
||||
Alternatively, you can assign a function to `ALERT_MINIMUM_INTERVAL` and/or `REPORT_MINIMUM_INTERVAL`. This is useful to dynamically retrieve a value as needed:
|
||||
|
||||
``` python
|
||||
def alert_dynamic_minimal_interval(**kwargs) -> int:
|
||||
"""
|
||||
Define logic here to retrieve the value dynamically
|
||||
"""
|
||||
|
||||
ALERT_MINIMUM_INTERVAL = alert_dynamic_minimal_interval
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
There are many reasons that reports might not be working. Try these steps to check for specific issues.
|
||||
|
||||
### Confirm feature flag is enabled and you have sufficient permissions
|
||||
|
||||
If you don't see "Alerts & Reports" under the *Manage* section of the Settings dropdown in the Superset UI, you need to enable the `ALERT_REPORTS` feature flag (see above). Enable another feature flag and check to see that it took effect, to verify that your config file is getting loaded.
|
||||
|
||||
Log in as an admin user to ensure you have adequate permissions.
|
||||
|
||||
### Check the logs of your Celery worker
|
||||
|
||||
This is the best source of information about the problem. In a docker compose deployment, you can do this with a command like `docker logs superset_worker --since 1h`.
|
||||
|
||||
### Check web browser and webdriver installation
|
||||
|
||||
To take a screenshot, the worker visits the dashboard or chart using a headless browser, then takes a screenshot. If you are able to send a chart as CSV or text but can't send as PNG, your problem may lie with the browser.
|
||||
|
||||
If you are handling the installation of the headless browser on your own, do your own verification to ensure that the headless browser opens successfully in the worker environment.
|
||||
|
||||
### Send a test email
|
||||
|
||||
One symptom of an invalid connection to an email server is receiving an error of `[Errno 110] Connection timed out` in your logs when the report tries to send.
|
||||
|
||||
Confirm via testing that your outbound email configuration is correct. Here is the simplest test, for an un-authenticated email SMTP email service running on port 25. If you are sending over SSL, for instance, study how [Superset's codebase sends emails](https://github.com/apache/superset/blob/master/superset/utils/core.py#L818) and then test with those commands and arguments.
|
||||
|
||||
Start Python in your worker environment, replace all example values, and run:
|
||||
|
||||
```python
|
||||
import smtplib
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
from_email = 'superset_emails@example.com'
|
||||
to_email = 'your_email@example.com'
|
||||
msg = MIMEMultipart()
|
||||
msg['From'] = from_email
|
||||
msg['To'] = to_email
|
||||
msg['Subject'] = 'Superset SMTP config test'
|
||||
message = 'It worked'
|
||||
msg.attach(MIMEText(message))
|
||||
mailserver = smtplib.SMTP('smtpmail.example.com', 25)
|
||||
mailserver.sendmail(from_email, to_email, msg.as_string())
|
||||
mailserver.quit()
|
||||
```
|
||||
|
||||
This should send an email.
|
||||
|
||||
Possible fixes:
|
||||
|
||||
- Some cloud hosts disable outgoing unauthenticated SMTP email to prevent spam. For instance, [Azure blocks port 25 by default on some machines](https://learn.microsoft.com/en-us/azure/virtual-network/troubleshoot-outbound-smtp-connectivity). Enable that port or use another sending method.
|
||||
- Use another set of SMTP credentials that you verify works in this setup.
|
||||
|
||||
### Browse to your report from the worker
|
||||
|
||||
The worker may be unable to reach the report. It will use the value of `WEBDRIVER_BASEURL` to browse to the report. If that route is invalid, or presents an authentication challenge that the worker can't pass, the report screenshot will fail.
|
||||
|
||||
Check this by attempting to `curl` the URL of a report that you see in the error logs of your worker. For instance, from the worker environment, run `curl http://superset_app:8088/superset/dashboard/1/`. You may get different responses depending on whether the dashboard exists - for example, you may need to change the `1` in that URL. If there's a URL in your logs from a failed report screenshot, that's a good place to start. The goal is to determine a valid value for `WEBDRIVER_BASEURL` and determine if an issue like HTTPS or authentication is redirecting your worker.
|
||||
|
||||
In a deployment with authentication measures enabled like HTTPS and Single Sign-On, it may make sense to have the worker navigate directly to the Superset application running in the same location, avoiding the need to sign in. For instance, you could use `WEBDRIVER_BASEURL="http://superset_app:8088"` for a docker compose deployment, and set `"force_https": False,` in your `TALISMAN_CONFIG`.
|
||||
|
||||
### Duplicate report deliveries
|
||||
|
||||
In some deployment configurations a scheduled report can be delivered more than once around its planned time. This typically happens when more than one process is responsible for running the alerts & reports schedule (for example, multiple schedulers or Celery beat instances). To avoid duplicate emails or notifications:
|
||||
|
||||
- Ensure that only a **single scheduler/beat process** is configured to trigger alerts and reports for a given environment.
|
||||
- If you run **multiple Celery workers**, verify that there is still only one component responsible for scheduling the report tasks (workers should execute tasks, not schedule them independently).
|
||||
- Review your deployment/orchestration setup (for example systemd, Docker, or Kubernetes) to make sure the alerts & reports scheduler is **not started from multiple places by accident**.
|
||||
|
||||
## Scheduling Queries as Reports
|
||||
|
||||
You can optionally allow your users to schedule queries directly in SQL Lab. This is done by adding
|
||||
extra metadata to saved queries, which are then picked up by an external scheduled (like
|
||||
[Apache Airflow](https://airflow.apache.org/)).
|
||||
|
||||
To allow scheduled queries, add the following to `SCHEDULED_QUERIES` in your configuration file:
|
||||
|
||||
```python
|
||||
SCHEDULED_QUERIES = {
|
||||
# This information is collected when the user clicks "Schedule query",
|
||||
# and saved into the `extra` field of saved queries.
|
||||
# See: https://github.com/mozilla-services/react-jsonschema-form
|
||||
'JSONSCHEMA': {
|
||||
'title': 'Schedule',
|
||||
'description': (
|
||||
'In order to schedule a query, you need to specify when it '
|
||||
'should start running, when it should stop running, and how '
|
||||
'often it should run. You can also optionally specify '
|
||||
'dependencies that should be met before the query is '
|
||||
'executed. Please read the documentation for best practices '
|
||||
'and more information on how to specify dependencies.'
|
||||
),
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'output_table': {
|
||||
'type': 'string',
|
||||
'title': 'Output table name',
|
||||
},
|
||||
'start_date': {
|
||||
'type': 'string',
|
||||
'title': 'Start date',
|
||||
# date-time is parsed using the chrono library, see
|
||||
# https://www.npmjs.com/package/chrono-node#usage
|
||||
'format': 'date-time',
|
||||
'default': 'tomorrow at 9am',
|
||||
},
|
||||
'end_date': {
|
||||
'type': 'string',
|
||||
'title': 'End date',
|
||||
# date-time is parsed using the chrono library, see
|
||||
# https://www.npmjs.com/package/chrono-node#usage
|
||||
'format': 'date-time',
|
||||
'default': '9am in 30 days',
|
||||
},
|
||||
'schedule_interval': {
|
||||
'type': 'string',
|
||||
'title': 'Schedule interval',
|
||||
},
|
||||
'dependencies': {
|
||||
'type': 'array',
|
||||
'title': 'Dependencies',
|
||||
'items': {
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'UISCHEMA': {
|
||||
'schedule_interval': {
|
||||
'ui:placeholder': '@daily, @weekly, etc.',
|
||||
},
|
||||
'dependencies': {
|
||||
'ui:help': (
|
||||
'Check the documentation for the correct format when '
|
||||
'defining dependencies.'
|
||||
),
|
||||
},
|
||||
},
|
||||
'VALIDATION': [
|
||||
# ensure that start_date <= end_date
|
||||
{
|
||||
'name': 'less_equal',
|
||||
'arguments': ['start_date', 'end_date'],
|
||||
'message': 'End date cannot be before start date',
|
||||
# this is where the error message is shown
|
||||
'container': 'end_date',
|
||||
},
|
||||
],
|
||||
# link to the scheduler; this example links to an Airflow pipeline
|
||||
# that uses the query id and the output table as its name
|
||||
'linkback': (
|
||||
'https://airflow.example.com/admin/airflow/tree?'
|
||||
'dag_id=query_${id}_${extra_json.schedule_info.output_table}'
|
||||
),
|
||||
}
|
||||
```
|
||||
|
||||
This configuration is based on
|
||||
[react-jsonschema-form](https://github.com/mozilla-services/react-jsonschema-form) and will add a
|
||||
menu item called “Schedule” to SQL Lab. When the menu item is clicked, a modal will show up where
|
||||
the user can add the metadata required for scheduling the query.
|
||||
|
||||
This information can then be retrieved from the endpoint `/api/v1/saved_query/` and used to
|
||||
schedule the queries that have `schedule_info` in their JSON metadata. For schedulers other than
|
||||
Airflow, additional fields can be easily added to the configuration file above.
|
||||
|
||||
:::resources
|
||||
- [Tutorial: Automated Alerts and Reporting via Slack/Email in Superset](https://dev.to/ngtduc693/apache-superset-topic-5-automated-alerts-and-reporting-via-slackemail-in-superset-2gbe)
|
||||
- [Blog: Integrating Slack alerts and Apache Superset for better data observability](https://medium.com/affinityanswers-tech/integrating-slack-alerts-and-apache-superset-for-better-data-observability-fd2f9a12c350)
|
||||
:::
|
||||
@@ -1,108 +0,0 @@
|
||||
---
|
||||
title: Async Queries via Celery
|
||||
hide_title: true
|
||||
sidebar_position: 4
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Async Queries via Celery
|
||||
|
||||
## Celery
|
||||
|
||||
On large analytic databases, it’s common to run queries that execute for minutes or hours. To enable
|
||||
support for long running queries that execute beyond the typical web request’s timeout (30-60
|
||||
seconds), it is necessary to configure an asynchronous backend for Superset which consists of:
|
||||
|
||||
- one or many Superset workers (which is implemented as a Celery worker), and can be started with
|
||||
the `celery worker` command, run `celery worker --help` to view the related options.
|
||||
- a celery broker (message queue) for which we recommend using Redis or RabbitMQ
|
||||
- a results backend that defines where the worker will persist the query results
|
||||
|
||||
Configuring Celery requires defining a `CELERY_CONFIG` in your `superset_config.py`. Both the worker
|
||||
and web server processes should have the same configuration.
|
||||
|
||||
```python
|
||||
class CeleryConfig(object):
|
||||
broker_url = "redis://localhost:6379/0"
|
||||
imports = (
|
||||
"superset.sql_lab",
|
||||
"superset.tasks.scheduler",
|
||||
)
|
||||
result_backend = "redis://localhost:6379/0"
|
||||
worker_prefetch_multiplier = 10
|
||||
task_acks_late = True
|
||||
task_annotations = {
|
||||
"sql_lab.get_sql_results": {
|
||||
"rate_limit": "100/s",
|
||||
},
|
||||
}
|
||||
|
||||
CELERY_CONFIG = CeleryConfig
|
||||
```
|
||||
|
||||
To start a Celery worker to leverage the configuration, run the following command:
|
||||
|
||||
```bash
|
||||
celery --app=superset.tasks.celery_app:app worker --pool=prefork -O fair -c 4
|
||||
```
|
||||
|
||||
To start a job which schedules periodic background jobs, run the following command:
|
||||
|
||||
```bash
|
||||
celery --app=superset.tasks.celery_app:app beat
|
||||
```
|
||||
|
||||
To setup a result backend, you need to pass an instance of a derivative of `BaseCache` (`from
|
||||
flask_caching.backends.base import BaseCache`) to the RESULTS_BACKEND configuration key in your
|
||||
superset_config.py. You can use Memcached, Redis, S3 (https://pypi.python.org/pypi/s3werkzeugcache),
|
||||
memory or the file system (in a single server-type setup or for testing), or to write your own
|
||||
caching interface. Your `superset_config.py` may look something like:
|
||||
|
||||
```python
|
||||
# On S3
|
||||
from s3cache.s3cache import S3Cache
|
||||
S3_CACHE_BUCKET = 'foobar-superset'
|
||||
S3_CACHE_KEY_PREFIX = 'sql_lab_result'
|
||||
RESULTS_BACKEND = S3Cache(S3_CACHE_BUCKET, S3_CACHE_KEY_PREFIX)
|
||||
|
||||
# On Redis
|
||||
from flask_caching.backends.rediscache import RedisCache
|
||||
RESULTS_BACKEND = RedisCache(
|
||||
host='localhost', port=6379, key_prefix='superset_results')
|
||||
```
|
||||
|
||||
For performance gains, [MessagePack](https://github.com/msgpack/msgpack-python) and
|
||||
[PyArrow](https://arrow.apache.org/docs/python/) are now used for results serialization. This can be
|
||||
disabled by setting `RESULTS_BACKEND_USE_MSGPACK = False` in your `superset_config.py`, should any
|
||||
issues arise. Please clear your existing results cache store when upgrading an existing environment.
|
||||
|
||||
**Important Notes**
|
||||
|
||||
- It is important that all the worker nodes and web servers in the Superset cluster _share a common
|
||||
metadata database_. This means that SQLite will not work in this context since it has limited
|
||||
support for concurrency and typically lives on the local file system.
|
||||
|
||||
- There should _only be one instance of celery beat running_ in your entire setup. If not,
|
||||
background jobs can get scheduled multiple times resulting in weird behaviors like duplicate
|
||||
delivery of reports, higher than expected load / traffic etc.
|
||||
|
||||
- SQL Lab will _only run your queries asynchronously if_ you enable **Asynchronous Query Execution**
|
||||
in your database settings (Sources > Databases > Edit record).
|
||||
|
||||
## Celery Flower
|
||||
|
||||
Flower is a web based tool for monitoring the Celery cluster which you can install from pip:
|
||||
|
||||
```bash
|
||||
pip install flower
|
||||
```
|
||||
|
||||
You can run flower using:
|
||||
|
||||
```bash
|
||||
celery --app=superset.tasks.celery_app:app flower
|
||||
```
|
||||
|
||||
:::resources
|
||||
- [Blog: How to Set Up Global Async Queries (GAQ) in Apache Superset](https://medium.com/@ngigilevis/how-to-set-up-global-async-queries-gaq-in-apache-superset-a-complete-guide-9d2f4a047559)
|
||||
:::
|
||||
@@ -1,243 +0,0 @@
|
||||
---
|
||||
title: Caching
|
||||
hide_title: true
|
||||
sidebar_position: 3
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Caching
|
||||
|
||||
:::note
|
||||
When a cache backend is configured, Superset expects it to remain available. Operations will
|
||||
fail if the configured backend becomes unavailable rather than silently degrading. This
|
||||
fail-fast behavior ensures operators are immediately aware of infrastructure issues.
|
||||
:::
|
||||
|
||||
Superset uses [Flask-Caching](https://flask-caching.readthedocs.io/) for caching purposes.
|
||||
Flask-Caching supports various caching backends, including Redis (recommended), Memcached,
|
||||
SimpleCache (in-memory), or the local filesystem.
|
||||
[Custom cache backends](https://flask-caching.readthedocs.io/en/latest/#custom-cache-backends)
|
||||
are also supported.
|
||||
|
||||
Caching can be configured by providing dictionaries in
|
||||
`superset_config.py` that comply with [the Flask-Caching config specifications](https://flask-caching.readthedocs.io/en/latest/#configuring-flask-caching).
|
||||
|
||||
The following cache configurations can be customized in this way:
|
||||
|
||||
- Dashboard filter state (required): `FILTER_STATE_CACHE_CONFIG`.
|
||||
- Explore chart form data (required): `EXPLORE_FORM_DATA_CACHE_CONFIG`
|
||||
- Metadata cache (optional): `CACHE_CONFIG`
|
||||
- Charting data queried from datasets (optional): `DATA_CACHE_CONFIG`
|
||||
|
||||
For example, to configure the filter state cache using Redis:
|
||||
|
||||
```python
|
||||
FILTER_STATE_CACHE_CONFIG = {
|
||||
'CACHE_TYPE': 'RedisCache',
|
||||
'CACHE_DEFAULT_TIMEOUT': 86400,
|
||||
'CACHE_KEY_PREFIX': 'superset_filter_cache',
|
||||
'CACHE_REDIS_URL': 'redis://localhost:6379/0'
|
||||
}
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
In order to use dedicated cache stores, additional python libraries must be installed
|
||||
|
||||
- For Redis: we recommend the [redis](https://pypi.python.org/pypi/redis) Python package
|
||||
- Memcached: we recommend using [pylibmc](https://pypi.org/project/pylibmc/) client library as
|
||||
`python-memcached` does not handle storing binary data correctly.
|
||||
|
||||
These libraries can be installed using pip.
|
||||
|
||||
## Fallback Metastore Cache
|
||||
|
||||
Note, that some form of Filter State and Explore caching are required. If either of these caches
|
||||
are undefined, Superset falls back to using a built-in cache that stores data in the metadata
|
||||
database. While it is recommended to use a dedicated cache, the built-in cache can also be used
|
||||
to cache other data.
|
||||
|
||||
For example, to use the built-in cache to store chart data, use the following config:
|
||||
|
||||
```python
|
||||
DATA_CACHE_CONFIG = {
|
||||
"CACHE_TYPE": "SupersetMetastoreCache",
|
||||
"CACHE_KEY_PREFIX": "superset_results", # make sure this string is unique to avoid collisions
|
||||
"CACHE_DEFAULT_TIMEOUT": 86400, # 60 seconds * 60 minutes * 24 hours
|
||||
}
|
||||
```
|
||||
|
||||
## Chart Cache Timeout
|
||||
|
||||
The cache timeout for charts may be overridden by the settings for an individual chart, dataset, or
|
||||
database. Each of these configurations will be checked in order before falling back to the default
|
||||
value defined in `DATA_CACHE_CONFIG`.
|
||||
|
||||
Note, that by setting the cache timeout to `-1`, caching for charting data can be disabled, either
|
||||
per chart, dataset or database, or by default if set in `DATA_CACHE_CONFIG`.
|
||||
|
||||
## SQL Lab Query Results
|
||||
|
||||
Caching for SQL Lab query results is used when async queries are enabled and is configured using
|
||||
`RESULTS_BACKEND`.
|
||||
|
||||
Note that this configuration does not use a flask-caching dictionary for its configuration, but
|
||||
instead requires a cachelib object.
|
||||
|
||||
See [Async Queries via Celery](/docs/configuration/async-queries-celery) for details.
|
||||
|
||||
## Caching Thumbnails
|
||||
|
||||
This is an optional feature that can be turned on by activating its [feature flag](/docs/configuration/configuring-superset#feature-flags) on config:
|
||||
|
||||
```
|
||||
FEATURE_FLAGS = {
|
||||
"THUMBNAILS": True,
|
||||
"THUMBNAILS_SQLA_LISTENERS": True,
|
||||
}
|
||||
```
|
||||
|
||||
By default thumbnails are rendered per user, and will fall back to the Selenium user for anonymous users.
|
||||
To always render thumbnails as a fixed user (`admin` in this example), use the following configuration:
|
||||
|
||||
```python
|
||||
from superset.tasks.types import FixedExecutor
|
||||
|
||||
THUMBNAIL_EXECUTORS = [FixedExecutor("admin")]
|
||||
```
|
||||
|
||||
For this feature you will need a cache system and celery workers. All thumbnails are stored on cache
|
||||
and are processed asynchronously by the workers.
|
||||
|
||||
An example config where images are stored on S3 could be:
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
from s3cache.s3cache import S3Cache
|
||||
|
||||
...
|
||||
|
||||
class CeleryConfig(object):
|
||||
broker_url = "redis://localhost:6379/0"
|
||||
imports = (
|
||||
"superset.sql_lab",
|
||||
"superset.tasks.thumbnails",
|
||||
)
|
||||
result_backend = "redis://localhost:6379/0"
|
||||
worker_prefetch_multiplier = 10
|
||||
task_acks_late = True
|
||||
|
||||
|
||||
CELERY_CONFIG = CeleryConfig
|
||||
|
||||
def init_thumbnail_cache(app: Flask) -> S3Cache:
|
||||
return S3Cache("bucket_name", 'thumbs_cache/')
|
||||
|
||||
|
||||
THUMBNAIL_CACHE_CONFIG = init_thumbnail_cache
|
||||
```
|
||||
|
||||
Using the above example cache keys for dashboards will be `superset_thumb__dashboard__{ID}`. You can
|
||||
override the base URL for selenium using:
|
||||
|
||||
```
|
||||
WEBDRIVER_BASEURL = "https://superset.company.com"
|
||||
```
|
||||
|
||||
Additional selenium web drive configuration can be set using `WEBDRIVER_CONFIGURATION`. You can
|
||||
implement a custom function to authenticate selenium. The default function uses the `flask-login`
|
||||
session cookie. Here's an example of a custom function signature:
|
||||
|
||||
```python
|
||||
def auth_driver(driver: WebDriver, user: "User") -> WebDriver:
|
||||
pass
|
||||
```
|
||||
|
||||
Then on configuration:
|
||||
|
||||
```
|
||||
WEBDRIVER_AUTH_FUNC = auth_driver
|
||||
```
|
||||
|
||||
## Signal Cache Backend
|
||||
|
||||
Superset supports an optional signal cache (`SIGNAL_CACHE_CONFIG`) for
|
||||
high-performance distributed operations. This configuration enables:
|
||||
|
||||
- **Distributed locking**: Moves lock operations from the metadata database to Redis, improving
|
||||
performance and reducing metastore load
|
||||
- **Real-time event notifications**: Enables instant pub/sub messaging for task abort signals and
|
||||
completion notifications instead of polling-based approaches
|
||||
|
||||
:::note
|
||||
This requires Redis or Valkey specifically—it uses Redis-specific features (pub/sub, `SET NX EX`)
|
||||
that are not available in general Flask-Caching backends.
|
||||
:::
|
||||
|
||||
### Configuration
|
||||
|
||||
The signal cache uses Flask-Caching style configuration for consistency with other cache
|
||||
backends. Configure `SIGNAL_CACHE_CONFIG` in `superset_config.py`:
|
||||
|
||||
```python
|
||||
SIGNAL_CACHE_CONFIG = {
|
||||
"CACHE_TYPE": "RedisCache",
|
||||
"CACHE_REDIS_HOST": "localhost",
|
||||
"CACHE_REDIS_PORT": 6379,
|
||||
"CACHE_REDIS_DB": 0,
|
||||
"CACHE_REDIS_PASSWORD": "", # Optional
|
||||
}
|
||||
```
|
||||
|
||||
For Redis Sentinel deployments:
|
||||
|
||||
```python
|
||||
SIGNAL_CACHE_CONFIG = {
|
||||
"CACHE_TYPE": "RedisSentinelCache",
|
||||
"CACHE_REDIS_SENTINELS": [("sentinel1", 26379), ("sentinel2", 26379)],
|
||||
"CACHE_REDIS_SENTINEL_MASTER": "mymaster",
|
||||
"CACHE_REDIS_SENTINEL_PASSWORD": None, # Sentinel password (if different)
|
||||
"CACHE_REDIS_PASSWORD": "", # Redis password
|
||||
"CACHE_REDIS_DB": 0,
|
||||
}
|
||||
```
|
||||
|
||||
For SSL/TLS connections:
|
||||
|
||||
```python
|
||||
SIGNAL_CACHE_CONFIG = {
|
||||
"CACHE_TYPE": "RedisCache",
|
||||
"CACHE_REDIS_HOST": "redis.example.com",
|
||||
"CACHE_REDIS_PORT": 6380,
|
||||
"CACHE_REDIS_SSL": True,
|
||||
"CACHE_REDIS_SSL_CERTFILE": "/path/to/client.crt",
|
||||
"CACHE_REDIS_SSL_KEYFILE": "/path/to/client.key",
|
||||
"CACHE_REDIS_SSL_CA_CERTS": "/path/to/ca.crt",
|
||||
}
|
||||
```
|
||||
|
||||
### Distributed Lock TTL
|
||||
|
||||
You can configure the default lock TTL (time-to-live) in seconds. Locks automatically expire after
|
||||
this duration to prevent deadlocks from crashed processes:
|
||||
|
||||
```python
|
||||
DISTRIBUTED_LOCK_DEFAULT_TTL = 30 # Default: 30 seconds
|
||||
```
|
||||
|
||||
Individual lock acquisitions can override this value when needed.
|
||||
|
||||
### Database-Only Mode
|
||||
|
||||
When `SIGNAL_CACHE_CONFIG` is not configured, Superset uses database-backed operations:
|
||||
|
||||
- **Locking**: Uses the KeyValue table with periodic cleanup of expired entries
|
||||
- **Event notifications**: Uses database polling instead of pub/sub
|
||||
|
||||
While database-backed operations work reliably, the Redis backend is recommended for production
|
||||
deployments where low latency and reduced database load are important.
|
||||
|
||||
:::resources
|
||||
- [Blog: The Data Engineer's Guide to Lightning-Fast Superset Dashboards](https://preset.io/blog/the-data-engineers-guide-to-lightning-fast-apache-superset-dashboards/)
|
||||
- [Blog: Accelerating Dashboards with Materialized Views](https://preset.io/blog/accelerating-apache-superset-dashboards-with-materialized-views/)
|
||||
:::
|
||||
@@ -1,448 +0,0 @@
|
||||
---
|
||||
title: Configuring Superset
|
||||
hide_title: true
|
||||
sidebar_position: 1
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Configuring Superset
|
||||
|
||||
## superset_config.py
|
||||
|
||||
Superset exposes hundreds of configurable parameters through its
|
||||
[config.py module](https://github.com/apache/superset/blob/master/superset/config.py). The
|
||||
variables and objects exposed act as a public interface of the bulk of what you may want
|
||||
to configure, alter and interface with. In this python module, you'll find all these
|
||||
parameters, sensible defaults, as well as rich documentation in the form of comments
|
||||
|
||||
To configure your application, you need to create your own configuration module, which
|
||||
will allow you to override few or many of these parameters. Instead of altering the core module,
|
||||
you'll want to define your own module (typically a file named `superset_config.py`).
|
||||
Add this file to your `PYTHONPATH` or create an environment variable
|
||||
`SUPERSET_CONFIG_PATH` specifying the full path of the `superset_config.py`.
|
||||
|
||||
For example, if deploying on Superset directly on a Linux-based system where your
|
||||
`superset_config.py` is under `/app` directory, you can run:
|
||||
|
||||
```bash
|
||||
export SUPERSET_CONFIG_PATH=/app/superset_config.py
|
||||
```
|
||||
|
||||
If you are using your own custom Dockerfile with the official Superset image as base image,
|
||||
then you can add your overrides as shown below:
|
||||
|
||||
```bash
|
||||
COPY --chown=superset superset_config.py /app/
|
||||
ENV SUPERSET_CONFIG_PATH /app/superset_config.py
|
||||
```
|
||||
|
||||
Docker compose deployments handle application configuration differently using specific conventions.
|
||||
Refer to the [docker compose tips & configuration](/docs/installation/docker-compose#docker-compose-tips--configuration)
|
||||
for details.
|
||||
|
||||
The following is an example of just a few of the parameters you can set in your `superset_config.py` file:
|
||||
|
||||
```
|
||||
# Superset specific config
|
||||
ROW_LIMIT = 5000
|
||||
|
||||
# Flask App Builder configuration
|
||||
# Your App secret key will be used for securely signing the session cookie
|
||||
# and encrypting sensitive information on the database
|
||||
# Make sure you are changing this key for your deployment with a strong key.
|
||||
# Alternatively you can set it with `SUPERSET_SECRET_KEY` environment variable.
|
||||
# You MUST set this for production environments or the server will refuse
|
||||
# to start and you will see an error in the logs accordingly.
|
||||
SECRET_KEY = 'YOUR_OWN_RANDOM_GENERATED_SECRET_KEY'
|
||||
|
||||
# The SQLAlchemy connection string to your database backend
|
||||
# This connection defines the path to the database that stores your
|
||||
# superset metadata (slices, connections, tables, dashboards, ...).
|
||||
# Note that the connection information to connect to the datasources
|
||||
# you want to explore are managed directly in the web UI
|
||||
# The check_same_thread=false property ensures the sqlite client does not attempt
|
||||
# to enforce single-threaded access, which may be problematic in some edge cases
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:////path/to/superset.db?check_same_thread=false'
|
||||
|
||||
# Flask-WTF flag for CSRF
|
||||
WTF_CSRF_ENABLED = True
|
||||
# Add endpoints that need to be exempt from CSRF protection
|
||||
WTF_CSRF_EXEMPT_LIST = []
|
||||
# A CSRF token that expires in 1 year
|
||||
WTF_CSRF_TIME_LIMIT = 60 * 60 * 24 * 365
|
||||
|
||||
# Set this API key to enable Mapbox visualizations
|
||||
MAPBOX_API_KEY = ''
|
||||
```
|
||||
|
||||
:::tip
|
||||
Note that it is typical to copy and paste [only] the portions of the
|
||||
core [superset/config.py](https://github.com/apache/superset/blob/master/superset/config.py) that
|
||||
you want to alter, along with the related comments into your own `superset_config.py` file.
|
||||
:::
|
||||
|
||||
All the parameters and default values defined
|
||||
in [superset/config.py](https://github.com/apache/superset/blob/master/superset/config.py)
|
||||
can be altered in your local `superset_config.py`. Administrators will want to read through the file
|
||||
to understand what can be configured locally as well as the default values in place.
|
||||
|
||||
Since `superset_config.py` acts as a Flask configuration module, it can be used to alter the
|
||||
settings of Flask itself, as well as Flask extensions that Superset bundles like
|
||||
`flask-wtf`, `flask-caching`, `flask-migrate`,
|
||||
and `flask-appbuilder`. Each one of these extensions offers intricate configurability.
|
||||
Flask App Builder, the web framework used by Superset, also offers many
|
||||
configuration settings. Please consult the
|
||||
[Flask App Builder Documentation](https://flask-appbuilder.readthedocs.org/en/latest/config.html)
|
||||
for more information on how to configure it.
|
||||
|
||||
At the very least, you'll want to change `SECRET_KEY` and `SQLALCHEMY_DATABASE_URI`. Continue reading for more about each of these.
|
||||
|
||||
## Specifying a SECRET_KEY
|
||||
|
||||
### Adding an initial SECRET_KEY
|
||||
|
||||
Superset requires a user-specified SECRET_KEY to start up. This requirement was [added in version 2.1.0 to force secure configurations](https://preset.io/blog/superset-security-update-default-secret_key-vulnerability/). Add a strong SECRET_KEY to your `superset_config.py` file like:
|
||||
|
||||
```python
|
||||
SECRET_KEY = 'YOUR_OWN_RANDOM_GENERATED_SECRET_KEY'
|
||||
```
|
||||
|
||||
You can generate a strong secure key with `openssl rand -base64 42`.
|
||||
|
||||
:::caution Use a strong secret key
|
||||
This key will be used for securely signing session cookies and encrypting sensitive information stored in Superset's application metadata database.
|
||||
Your deployment must use a complex, unique key.
|
||||
:::
|
||||
|
||||
### Rotating to a newer SECRET_KEY
|
||||
|
||||
If you wish to change your existing SECRET_KEY, add the existing SECRET_KEY to your `superset_config.py` file as
|
||||
`PREVIOUS_SECRET_KEY =`and provide your new key as `SECRET_KEY =`. You can find your current SECRET_KEY with these
|
||||
commands - if running Superset with Docker, execute from within the Superset application container:
|
||||
|
||||
```python
|
||||
superset shell
|
||||
from flask import current_app; print(current_app.config["SECRET_KEY"])
|
||||
```
|
||||
|
||||
Save your `superset_config.py` with these values and then run `superset re-encrypt-secrets`.
|
||||
|
||||
## Setting up a production metadata database
|
||||
|
||||
Superset needs a database to store the information it manages, like the definitions of
|
||||
charts, dashboards, and many other things.
|
||||
|
||||
By default, Superset is configured to use [SQLite](https://www.sqlite.org/),
|
||||
a self-contained, single-file database that offers a simple and fast way to get started
|
||||
(without requiring any installation). However, for production environments,
|
||||
using SQLite is highly discouraged due to security, scalability, and data integrity reasons.
|
||||
It's important to use only the supported database engines and consider using a different
|
||||
database engine on a separate host or container.
|
||||
|
||||
Superset supports the following database engines/versions:
|
||||
|
||||
| Database Engine | Supported Versions |
|
||||
| ----------------------------------------- | ---------------------------------------------- |
|
||||
| [PostgreSQL](https://www.postgresql.org/) | 10.X, 11.X, 12.X, 13.X, 14.X, 15.X, 16.X, 17.X |
|
||||
| [MySQL](https://www.mysql.com/) | 5.7, 8.X |
|
||||
|
||||
Use the following database drivers and connection strings:
|
||||
|
||||
| Database | PyPI package | Connection String |
|
||||
| ----------------------------------------- | ------------------------- | ---------------------------------------------------------------------- |
|
||||
| [PostgreSQL](https://www.postgresql.org/) | `pip install psycopg2` | `postgresql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` |
|
||||
| [MySQL](https://www.mysql.com/) | `pip install mysqlclient` | `mysql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` |
|
||||
|
||||
:::tip
|
||||
Properly setting up metadata store is beyond the scope of this documentation. We recommend
|
||||
using a hosted managed service such as [Amazon RDS](https://aws.amazon.com/rds/) or
|
||||
[Google Cloud Databases](https://cloud.google.com/products/databases?hl=en) to handle
|
||||
service and supporting infrastructure and backup strategy.
|
||||
:::
|
||||
|
||||
To configure Superset metastore set `SQLALCHEMY_DATABASE_URI` config key on `superset_config`
|
||||
to the appropriate connection string.
|
||||
|
||||
## Running on a WSGI HTTP Server
|
||||
|
||||
While you can run Superset on NGINX or Apache, we recommend using Gunicorn in async mode. This
|
||||
enables impressive concurrency even and is fairly easy to install and configure. Please refer to the
|
||||
documentation of your preferred technology to set up this Flask WSGI application in a way that works
|
||||
well in your environment. Here’s an async setup known to work well in production:
|
||||
|
||||
```
|
||||
-w 10 \
|
||||
-k gevent \
|
||||
--worker-connections 1000 \
|
||||
--timeout 120 \
|
||||
-b 0.0.0.0:6666 \
|
||||
--limit-request-line 0 \
|
||||
--limit-request-field_size 0 \
|
||||
--statsd-host localhost:8125 \
|
||||
"superset.app:create_app()"
|
||||
```
|
||||
|
||||
Refer to the [Gunicorn documentation](https://docs.gunicorn.org/en/stable/design.html) for more
|
||||
information. _Note that the development web server (`superset run` or `flask run`) is not intended
|
||||
for production use._
|
||||
|
||||
If you're not using Gunicorn, you may want to disable the use of `flask-compress` by setting
|
||||
`COMPRESS_REGISTER = False` in your `superset_config.py`.
|
||||
|
||||
Currently, the Google BigQuery Python SDK is not compatible with `gevent`, due to some dynamic monkeypatching on python core library by `gevent`.
|
||||
So, when you use `BigQuery` datasource on Superset, you have to use `gunicorn` worker type except `gevent`.
|
||||
|
||||
## HTTPS Configuration
|
||||
|
||||
You can configure HTTPS upstream via a load balancer or a reverse proxy (such as nginx) and do SSL/TLS Offloading before traffic reaches the Superset application. In this setup, local traffic from a Celery worker taking a snapshot of a chart for Alerts & Reports can access Superset at a `http://` URL, from behind the ingress point.
|
||||
You can also configure [SSL in Gunicorn](https://docs.gunicorn.org/en/stable/settings.html#ssl) (the Python webserver) if you are using an official Superset Docker image.
|
||||
|
||||
## Configuration Behind a Load Balancer
|
||||
|
||||
If you are running superset behind a load balancer or reverse proxy (e.g. NGINX or ELB on AWS), you
|
||||
may need to utilize a healthcheck endpoint so that your load balancer knows if your superset
|
||||
instance is running. This is provided at `/health` which will return a 200 response containing “OK”
|
||||
if the webserver is running.
|
||||
|
||||
If the load balancer is inserting `X-Forwarded-For/X-Forwarded-Proto` headers, you should set
|
||||
`ENABLE_PROXY_FIX = True` in the superset config file (`superset_config.py`) to extract and use the
|
||||
headers.
|
||||
|
||||
In case the reverse proxy is used for providing SSL encryption, an explicit definition of the
|
||||
`X-Forwarded-Proto` may be required. For the Apache webserver this can be set as follows:
|
||||
|
||||
```
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
```
|
||||
|
||||
## Configuring the application root
|
||||
|
||||
*Please be advised that this feature is in BETA.*
|
||||
|
||||
Superset supports running the application under a non-root path. The root path
|
||||
prefix can be specified in one of two ways:
|
||||
|
||||
- Setting the `SUPERSET_APP_ROOT` environment variable to the desired prefix.
|
||||
- Customizing the [Flask entrypoint](https://github.com/apache/superset/blob/master/superset/app.py#L29)
|
||||
by passing the `superset_app_root` variable.
|
||||
|
||||
Note, the prefix should start with a `/`.
|
||||
|
||||
### Customizing the Flask entrypoint
|
||||
|
||||
To configure a prefix, e.g `/analytics`, pass the `superset_app_root` argument to
|
||||
`create_app` when calling flask run either through the `FLASK_APP`
|
||||
environment variable:
|
||||
|
||||
```sh
|
||||
FLASK_APP="superset:create_app(superset_app_root='/analytics')"
|
||||
```
|
||||
|
||||
or as part of the `--app` argument to `flask run`:
|
||||
|
||||
```sh
|
||||
flask --app "superset.app:create_app(superset_app_root='/analytics')"
|
||||
```
|
||||
|
||||
### Docker builds
|
||||
|
||||
The [docker compose](/docs/installation/docker-compose#configuring-further) developer
|
||||
configuration includes an additional environmental variable,
|
||||
[`SUPERSET_APP_ROOT`](https://github.com/apache/superset/blob/master/docker/.env),
|
||||
to simplify the process of setting up a non-default root path across the services.
|
||||
|
||||
In `docker/.env-local` set `SUPERSET_APP_ROOT` to the desired prefix and then bring the
|
||||
services up with `docker compose up --detach`.
|
||||
|
||||
## Custom OAuth2 Configuration
|
||||
|
||||
Superset is built on Flask-AppBuilder (FAB), which supports many providers out of the box
|
||||
(GitHub, Twitter, LinkedIn, Google, Azure, etc). Beyond those, Superset can be configured to connect
|
||||
with other OAuth2 Authorization Server implementations that support “code” authorization.
|
||||
|
||||
Make sure the pip package [`Authlib`](https://authlib.org/) is installed on the webserver.
|
||||
|
||||
First, configure authorization in Superset `superset_config.py`.
|
||||
|
||||
```python
|
||||
from flask_appbuilder.security.manager import AUTH_OAUTH
|
||||
|
||||
# Set the authentication type to OAuth
|
||||
AUTH_TYPE = AUTH_OAUTH
|
||||
|
||||
OAUTH_PROVIDERS = [
|
||||
{ 'name':'egaSSO',
|
||||
'token_key':'access_token', # Name of the token in the response of access_token_url
|
||||
'icon':'fa-address-card', # Icon for the provider
|
||||
'remote_app': {
|
||||
'client_id':'myClientId', # Client Id (Identify Superset application)
|
||||
'client_secret':'MySecret', # Secret for this Client Id (Identify Superset application)
|
||||
'client_kwargs':{
|
||||
'scope': 'read' # Scope for the Authorization
|
||||
},
|
||||
'access_token_method':'POST', # HTTP Method to call access_token_url
|
||||
'access_token_params':{ # Additional parameters for calls to access_token_url
|
||||
'client_id':'myClientId'
|
||||
},
|
||||
'jwks_uri':'https://myAuthorizationServe/adfs/discovery/keys', # may be required to generate token
|
||||
'access_token_headers':{ # Additional headers for calls to access_token_url
|
||||
'Authorization': 'Basic Base64EncodedClientIdAndSecret'
|
||||
},
|
||||
'api_base_url':'https://myAuthorizationServer/oauth2AuthorizationServer/',
|
||||
'access_token_url':'https://myAuthorizationServer/oauth2AuthorizationServer/token',
|
||||
'authorize_url':'https://myAuthorizationServer/oauth2AuthorizationServer/authorize'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
# Will allow user self registration, allowing to create Flask users from Authorized User
|
||||
AUTH_USER_REGISTRATION = True
|
||||
|
||||
# The default user self registration role
|
||||
AUTH_USER_REGISTRATION_ROLE = "Public"
|
||||
```
|
||||
|
||||
In case you want to assign the `Admin` role on new user registration, it can be assigned as follows:
|
||||
```python
|
||||
AUTH_USER_REGISTRATION_ROLE = "Admin"
|
||||
```
|
||||
If you encounter the [issue](https://github.com/apache/superset/issues/13243) of not being able to list users from the Superset main page settings, although a newly registered user has an `Admin` role, please re-run `superset init` to sync the required permissions. Below is the command to re-run `superset init` using docker compose.
|
||||
```
|
||||
docker-compose exec superset superset init
|
||||
```
|
||||
|
||||
Then, create a `CustomSsoSecurityManager` that extends `SupersetSecurityManager` and overrides
|
||||
`oauth_user_info`:
|
||||
|
||||
```python
|
||||
import logging
|
||||
from superset.security import SupersetSecurityManager
|
||||
|
||||
class CustomSsoSecurityManager(SupersetSecurityManager):
|
||||
|
||||
def oauth_user_info(self, provider, response=None):
|
||||
logging.debug("Oauth2 provider: {0}.".format(provider))
|
||||
if provider == 'egaSSO':
|
||||
# As example, this line request a GET to base_url + '/' + userDetails with Bearer Authentication,
|
||||
# and expects that authorization server checks the token, and response with user details
|
||||
me = self.appbuilder.sm.oauth_remotes[provider].get('userDetails').data
|
||||
logging.debug("user_data: {0}".format(me))
|
||||
return { 'name' : me['name'], 'email' : me['email'], 'id' : me['user_name'], 'username' : me['user_name'], 'first_name':'', 'last_name':''}
|
||||
...
|
||||
```
|
||||
|
||||
This file must be located in the same directory as `superset_config.py` with the name
|
||||
`custom_sso_security_manager.py`. Finally, add the following 2 lines to `superset_config.py`:
|
||||
|
||||
```
|
||||
from custom_sso_security_manager import CustomSsoSecurityManager
|
||||
CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
|
||||
```
|
||||
|
||||
**Notes**
|
||||
|
||||
- The redirect URL will be `https://<superset-webserver>/oauth-authorized/<provider-name>`
|
||||
When configuring an OAuth2 authorization provider if needed. For instance, the redirect URL will
|
||||
be `https://<superset-webserver>/oauth-authorized/egaSSO` for the above configuration.
|
||||
|
||||
- If an OAuth2 authorization server supports OpenID Connect 1.0, you could configure its configuration
|
||||
document URL only without providing `api_base_url`, `access_token_url`, `authorize_url` and other
|
||||
required options like user info endpoint, jwks uri etc. For instance:
|
||||
|
||||
```python
|
||||
OAUTH_PROVIDERS = [
|
||||
{ 'name':'egaSSO',
|
||||
'token_key':'access_token', # Name of the token in the response of access_token_url
|
||||
'icon':'fa-address-card', # Icon for the provider
|
||||
'remote_app': {
|
||||
'client_id':'myClientId', # Client Id (Identify Superset application)
|
||||
'client_secret':'MySecret', # Secret for this Client Id (Identify Superset application)
|
||||
'server_metadata_url': 'https://myAuthorizationServer/.well-known/openid-configuration'
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## LDAP Authentication
|
||||
|
||||
FAB supports authenticating user credentials against an LDAP server.
|
||||
To use LDAP you must install the [python-ldap](https://www.python-ldap.org/en/latest/installing.html) package.
|
||||
See [FAB's LDAP documentation](https://flask-appbuilder.readthedocs.io/en/latest/security.html#authentication-ldap)
|
||||
for details.
|
||||
|
||||
## Mapping LDAP or OAUTH groups to Superset roles
|
||||
|
||||
AUTH_ROLES_MAPPING in Flask-AppBuilder is a dictionary that maps from LDAP/OAUTH group names to FAB roles.
|
||||
It is used to assign roles to users who authenticate using LDAP or OAuth.
|
||||
|
||||
### Mapping OAUTH groups to Superset roles
|
||||
|
||||
The following `AUTH_ROLES_MAPPING` dictionary would map the OAUTH group "superset_users" to the Superset roles "Gamma" as well as "Alpha", and the OAUTH group "superset_admins" to the Superset role "Admin".
|
||||
|
||||
```python
|
||||
AUTH_ROLES_MAPPING = {
|
||||
"superset_users": ["Gamma","Alpha"],
|
||||
"superset_admins": ["Admin"],
|
||||
}
|
||||
```
|
||||
|
||||
### Mapping LDAP groups to Superset roles
|
||||
|
||||
The following `AUTH_ROLES_MAPPING` dictionary would map the LDAP DN "cn=superset_users,ou=groups,dc=example,dc=com" to the Superset roles "Gamma" as well as "Alpha", and the LDAP DN "cn=superset_admins,ou=groups,dc=example,dc=com" to the Superset role "Admin".
|
||||
|
||||
```python
|
||||
AUTH_ROLES_MAPPING = {
|
||||
"cn=superset_users,ou=groups,dc=example,dc=com": ["Gamma","Alpha"],
|
||||
"cn=superset_admins,ou=groups,dc=example,dc=com": ["Admin"],
|
||||
}
|
||||
```
|
||||
|
||||
Note: This requires `AUTH_LDAP_SEARCH` to be set. For more details, please see the [FAB Security documentation](https://flask-appbuilder.readthedocs.io/en/latest/security.html).
|
||||
|
||||
### Syncing roles at login
|
||||
|
||||
You can also use the `AUTH_ROLES_SYNC_AT_LOGIN` configuration variable to control how often Flask-AppBuilder syncs the user's roles with the LDAP/OAUTH groups. If `AUTH_ROLES_SYNC_AT_LOGIN` is set to True, Flask-AppBuilder will sync the user's roles each time they log in. If `AUTH_ROLES_SYNC_AT_LOGIN` is set to False, Flask-AppBuilder will only sync the user's roles when they first register.
|
||||
|
||||
## Flask app Configuration Hook
|
||||
|
||||
`FLASK_APP_MUTATOR` is a configuration function that can be provided in your environment, receives
|
||||
the app object and can alter it in any way. For example, add `FLASK_APP_MUTATOR` into your
|
||||
`superset_config.py` to setup session cookie expiration time to 24 hours:
|
||||
|
||||
```python
|
||||
from flask import session
|
||||
from flask import Flask
|
||||
|
||||
|
||||
def make_session_permanent():
|
||||
'''
|
||||
Enable maxAge for the cookie 'session'
|
||||
'''
|
||||
session.permanent = True
|
||||
|
||||
# Set up max age of session to 24 hours
|
||||
PERMANENT_SESSION_LIFETIME = timedelta(hours=24)
|
||||
def FLASK_APP_MUTATOR(app: Flask) -> None:
|
||||
app.before_request_funcs.setdefault(None, []).append(make_session_permanent)
|
||||
```
|
||||
|
||||
## Feature Flags
|
||||
|
||||
To support a diverse set of users, Superset has some features that are not enabled by default. For
|
||||
example, some users have stronger security restrictions, while some others may not. So Superset
|
||||
allows users to enable or disable some features by config. For feature owners, you can add optional
|
||||
functionalities in Superset, but will be only affected by a subset of users.
|
||||
|
||||
You can enable or disable features with flag from `superset_config.py`:
|
||||
|
||||
```python
|
||||
FEATURE_FLAGS = {
|
||||
'PRESTO_EXPAND_DATA': False,
|
||||
}
|
||||
```
|
||||
|
||||
A current list of feature flags can be found in the [Feature Flags](/docs/configuration/feature-flags) documentation.
|
||||
|
||||
:::resources
|
||||
- [Blog: Feature Flags in Apache Superset](https://preset.io/blog/feature-flags-in-apache-superset-and-preset/)
|
||||
:::
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
title: Country Map Tools
|
||||
sidebar_position: 10
|
||||
version: 1
|
||||
---
|
||||
|
||||
import countriesData from '../../data/countries.json';
|
||||
|
||||
# The Country Map Visualization
|
||||
|
||||
The Country Map visualization allows you to plot lightweight choropleth maps of
|
||||
your countries by province, states, or other subdivision types. It does not rely
|
||||
on any third-party map services but would require you to provide the
|
||||
[ISO-3166-2](https://en.wikipedia.org/wiki/ISO_3166-2) codes of your country's
|
||||
top-level subdivisions. Comparing to a province or state's full names, the ISO
|
||||
code is less ambiguous and is unique to all regions in the world.
|
||||
|
||||
## Included Maps
|
||||
|
||||
The current list of countries can be found in the src
|
||||
[legacy-plugin-chart-country-map/src/countries.ts](https://github.com/apache/superset/blob/master/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries.ts)
|
||||
|
||||
The Country Maps visualization already ships with the maps for the following countries:
|
||||
|
||||
<ul style={{columns: 3}}>
|
||||
{countriesData.countries.map((country, index) => (
|
||||
<li key={index}>{country}</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
## Adding a New Country
|
||||
|
||||
To add a new country to the list, you'd have to edit files in
|
||||
[@superset-ui/legacy-plugin-chart-country-map](https://github.com/apache/superset/tree/master/superset-frontend/plugins/legacy-plugin-chart-country-map).
|
||||
|
||||
1. Generate a new GeoJSON file for your country following the guide in [this Jupyter notebook](https://github.com/apache/superset/blob/master/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country%20Map%20GeoJSON%20Generator.ipynb).
|
||||
2. Edit the countries list in [legacy-plugin-chart-country-map/src/countries.ts](https://github.com/apache/superset/blob/master/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries.ts).
|
||||
3. Install superset-frontend dependencies: `cd superset-frontend && npm install`
|
||||
4. Verify your countries in Superset plugins storybook: `npm run plugins:storybook`.
|
||||
5. Build and install Superset from source code.
|
||||
@@ -1,62 +0,0 @@
|
||||
---
|
||||
title: Event Logging
|
||||
sidebar_position: 9
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Logging
|
||||
|
||||
## Event Logging
|
||||
|
||||
Superset by default logs special action events in its internal database (DBEventLogger). These logs can be accessed
|
||||
on the UI by navigating to **Security > Action Log**. You can freely customize these logs by
|
||||
implementing your own event log class.
|
||||
**When custom log class is enabled DBEventLogger is disabled and logs
|
||||
stop being populated in UI logs view.**
|
||||
To achieve both, custom log class should extend built-in DBEventLogger log class.
|
||||
|
||||
Here's an example of a simple JSON-to-stdout class:
|
||||
|
||||
```python
|
||||
def log(self, user_id, action, *args, **kwargs):
|
||||
records = kwargs.get('records', list())
|
||||
dashboard_id = kwargs.get('dashboard_id')
|
||||
slice_id = kwargs.get('slice_id')
|
||||
duration_ms = kwargs.get('duration_ms')
|
||||
referrer = kwargs.get('referrer')
|
||||
|
||||
for record in records:
|
||||
log = dict(
|
||||
action=action,
|
||||
json=record,
|
||||
dashboard_id=dashboard_id,
|
||||
slice_id=slice_id,
|
||||
duration_ms=duration_ms,
|
||||
referrer=referrer,
|
||||
user_id=user_id
|
||||
)
|
||||
print(json.dumps(log))
|
||||
```
|
||||
|
||||
End by updating your config to pass in an instance of the logger you want to use:
|
||||
|
||||
```
|
||||
EVENT_LOGGER = JSONStdOutEventLogger()
|
||||
```
|
||||
|
||||
## StatsD Logging
|
||||
|
||||
Superset can be configured to log events to [StatsD](https://github.com/statsd/statsd)
|
||||
if desired. Most endpoints hit are logged as
|
||||
well as key events like query start and end in SQL Lab.
|
||||
|
||||
To setup StatsD logging, it’s a matter of configuring the logger in your `superset_config.py`.
|
||||
If not already present, you need to ensure that the `statsd`-package is installed in Superset's python environment.
|
||||
|
||||
```python
|
||||
from superset.stats_logger import StatsdStatsLogger
|
||||
STATS_LOGGER = StatsdStatsLogger(host='localhost', port=8125, prefix='superset')
|
||||
```
|
||||
|
||||
Note that it’s also possible to implement your own logger by deriving
|
||||
`superset.stats_logger.BaseStatsLogger`.
|
||||
@@ -1,107 +0,0 @@
|
||||
---
|
||||
title: Feature Flags
|
||||
hide_title: true
|
||||
sidebar_position: 2
|
||||
version: 1
|
||||
---
|
||||
|
||||
import featureFlags from '@site/static/feature-flags.json';
|
||||
|
||||
export const FlagTable = ({flags}) => (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Flag</th>
|
||||
<th>Default</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{flags.map((flag) => (
|
||||
<tr key={flag.name}>
|
||||
<td><code>{flag.name}</code></td>
|
||||
<td><code>{flag.default ? 'True' : 'False'}</code></td>
|
||||
<td>
|
||||
{flag.description}
|
||||
{flag.docs && (
|
||||
<> (<a href={flag.docs}>docs</a>)</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
||||
# Feature Flags
|
||||
|
||||
Superset uses feature flags to control the availability of features. Feature flags allow
|
||||
gradual rollout of new functionality and provide a way to enable experimental features.
|
||||
|
||||
To enable a feature flag, add it to your `superset_config.py`:
|
||||
|
||||
```python
|
||||
FEATURE_FLAGS = {
|
||||
"ENABLE_TEMPLATE_PROCESSING": True,
|
||||
}
|
||||
```
|
||||
|
||||
## Lifecycle
|
||||
|
||||
Feature flags progress through lifecycle stages:
|
||||
|
||||
| Stage | Description |
|
||||
|-------|-------------|
|
||||
| **Development** | Experimental features under active development. May be incomplete or unstable. |
|
||||
| **Testing** | Feature complete but undergoing testing. Usable but may contain bugs. |
|
||||
| **Stable** | Production-ready features. Safe for all deployments. |
|
||||
| **Deprecated** | Features scheduled for removal. Migrate away from these. |
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
These features are experimental and under active development. Use only in development environments.
|
||||
|
||||
<FlagTable flags={featureFlags.flags.development} />
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
These features are complete but still being tested. They are usable but may have bugs.
|
||||
|
||||
<FlagTable flags={featureFlags.flags.testing} />
|
||||
|
||||
---
|
||||
|
||||
## Stable
|
||||
|
||||
These features are production-ready and safe to enable.
|
||||
|
||||
<FlagTable flags={featureFlags.flags.stable} />
|
||||
|
||||
---
|
||||
|
||||
## Deprecated
|
||||
|
||||
These features are scheduled for removal. Plan to migrate away from them.
|
||||
|
||||
<FlagTable flags={featureFlags.flags.deprecated} />
|
||||
|
||||
---
|
||||
|
||||
## Adding New Feature Flags
|
||||
|
||||
When adding a new feature flag to `superset/config.py`, include the following annotations:
|
||||
|
||||
```python
|
||||
# Description of what the feature does
|
||||
# @lifecycle: development | testing | stable | deprecated
|
||||
# @docs: https://superset.apache.org/docs/... (optional)
|
||||
# @category: runtime_config | path_to_deprecation (optional, for stable flags)
|
||||
"MY_NEW_FEATURE": False,
|
||||
```
|
||||
|
||||
This documentation is auto-generated from the annotations in
|
||||
[config.py](https://github.com/apache/superset/blob/master/superset/config.py).
|
||||
@@ -1,126 +0,0 @@
|
||||
---
|
||||
title: Importing and Exporting Datasources
|
||||
hide_title: true
|
||||
sidebar_position: 11
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Importing and Exporting Datasources
|
||||
|
||||
The superset cli allows you to import and export datasources from and to YAML. Datasources include
|
||||
databases. The data is expected to be organized in the following hierarchy:
|
||||
|
||||
```text
|
||||
├──databases
|
||||
| ├──database_1
|
||||
| | ├──table_1
|
||||
| | | ├──columns
|
||||
| | | | ├──column_1
|
||||
| | | | ├──column_2
|
||||
| | | | └──... (more columns)
|
||||
| | | └──metrics
|
||||
| | | ├──metric_1
|
||||
| | | ├──metric_2
|
||||
| | | └──... (more metrics)
|
||||
| | └── ... (more tables)
|
||||
| └── ... (more databases)
|
||||
```
|
||||
|
||||
## Exporting Datasources to YAML
|
||||
|
||||
You can print your current datasources to stdout by running:
|
||||
|
||||
```bash
|
||||
superset export_datasources
|
||||
```
|
||||
|
||||
To save your datasources to a ZIP file run:
|
||||
|
||||
```bash
|
||||
superset export_datasources -f <filename>
|
||||
```
|
||||
|
||||
By default, default (null) values will be omitted. Use the -d flag to include them. If you want back
|
||||
references to be included (e.g. a column to include the table id it belongs to) use the -b flag.
|
||||
|
||||
Alternatively, you can export datasources using the UI:
|
||||
|
||||
1. Open **Sources -> Databases** to export all tables associated to a single or multiple databases.
|
||||
(**Tables** for one or more tables)
|
||||
2. Select the items you would like to export.
|
||||
3. Click **Actions -> Export** to YAML
|
||||
4. If you want to import an item that you exported through the UI, you will need to nest it inside
|
||||
its parent element, e.g. a database needs to be nested under databases a table needs to be nested
|
||||
inside a database element.
|
||||
|
||||
In order to obtain an **exhaustive list of all fields** you can import using the YAML import run:
|
||||
|
||||
```bash
|
||||
superset export_datasource_schema
|
||||
```
|
||||
|
||||
As a reminder, you can use the `-b` flag to include back references.
|
||||
|
||||
## Importing Datasources
|
||||
|
||||
In order to import datasources from a ZIP file, run:
|
||||
|
||||
```bash
|
||||
superset import_datasources -p <path / filename>
|
||||
```
|
||||
|
||||
The optional username flag **-u** sets the user used for the datasource import. The default is 'admin'. Example:
|
||||
|
||||
```bash
|
||||
superset import_datasources -p <path / filename> -u 'admin'
|
||||
```
|
||||
|
||||
## Legacy Importing Datasources
|
||||
|
||||
### From older versions of Superset to current version
|
||||
|
||||
When using Superset version 4.x.x to import from an older version (2.x.x or 3.x.x) importing is supported as the command `legacy_import_datasources` and expects a JSON or directory of JSONs. The options are `-r` for recursive and `-u` for specifying a user. Example of legacy import without options:
|
||||
|
||||
```bash
|
||||
superset legacy_import_datasources -p <path or filename>
|
||||
```
|
||||
|
||||
### From older versions of Superset to older versions
|
||||
|
||||
When using an older Superset version (2.x.x & 3.x.x) of Superset, the command is `import_datasources`. ZIP and YAML files are supported and to switch between them the feature flag `VERSIONED_EXPORT` is used. When `VERSIONED_EXPORT` is `True`, `import_datasources` expects a ZIP file, otherwise YAML. Example:
|
||||
|
||||
```bash
|
||||
superset import_datasources -p <path or filename>
|
||||
```
|
||||
|
||||
When `VERSIONED_EXPORT` is `False`, if you supply a path all files ending with **yaml** or **yml** will be parsed. You can apply
|
||||
additional flags (e.g. to search the supplied path recursively):
|
||||
|
||||
```bash
|
||||
superset import_datasources -p <path> -r
|
||||
```
|
||||
|
||||
The sync flag **-s** takes parameters in order to sync the supplied elements with your file. Be
|
||||
careful this can delete the contents of your meta database. Example:
|
||||
|
||||
```bash
|
||||
superset import_datasources -p <path / filename> -s columns,metrics
|
||||
```
|
||||
|
||||
This will sync all metrics and columns for all datasources found in the `<path /filename>` in the
|
||||
Superset meta database. This means columns and metrics not specified in YAML will be deleted. If you
|
||||
would add tables to columns,metrics those would be synchronised as well.
|
||||
|
||||
If you don’t supply the sync flag (**-s**) importing will only add and update (override) fields.
|
||||
E.g. you can add a verbose_name to the column ds in the table random_time_series from the example
|
||||
datasets by saving the following YAML to file and then running the **import_datasources** command.
|
||||
|
||||
```yaml
|
||||
databases:
|
||||
- database_name: main
|
||||
tables:
|
||||
- table_name: random_time_series
|
||||
columns:
|
||||
- column_name: ds
|
||||
verbose_name: datetime
|
||||
```
|
||||
@@ -1,78 +0,0 @@
|
||||
---
|
||||
title: Map Tiles
|
||||
sidebar_position: 12
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Map tiles
|
||||
|
||||
Superset uses OSM and Mapbox tiles by default. OSM is free but you still need setting your MAPBOX_API_KEY if you want to use mapbox maps.
|
||||
|
||||
## Setting map tiles
|
||||
|
||||
Map tiles can be set with `DECKGL_BASE_MAP` in your `superset_config.py` or `superset_config_docker.py`
|
||||
For adding your own map tiles, you can use the following format.
|
||||
|
||||
```python
|
||||
DECKGL_BASE_MAP = [
|
||||
['tile://https://your_personal_url/{z}/{x}/{y}.png', 'MyTile']
|
||||
]
|
||||
```
|
||||
Openstreetmap tiles url can be added without prefix.
|
||||
```python
|
||||
DECKGL_BASE_MAP = [
|
||||
['https://c.tile.openstreetmap.org/{z}/{x}/{y}.png', 'OpenStreetMap']
|
||||
]
|
||||
```
|
||||
|
||||
Default values are:
|
||||
```python
|
||||
DECKGL_BASE_MAP = [
|
||||
['https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'Streets (OSM)'],
|
||||
['https://tile.osm.ch/osm-swiss-style/{z}/{x}/{y}.png', 'Topography (OSM)'],
|
||||
['mapbox://styles/mapbox/streets-v9', 'Streets'],
|
||||
['mapbox://styles/mapbox/dark-v9', 'Dark'],
|
||||
['mapbox://styles/mapbox/light-v9', 'Light'],
|
||||
['mapbox://styles/mapbox/satellite-streets-v9', 'Satellite Streets'],
|
||||
['mapbox://styles/mapbox/satellite-v9', 'Satellite'],
|
||||
['mapbox://styles/mapbox/outdoors-v9', 'Outdoors'],
|
||||
]
|
||||
```
|
||||
|
||||
It is possible to set only mapbox by removing osm tiles and other way around.
|
||||
|
||||
:::warning
|
||||
Setting `DECKGL_BASE_MAP` overwrite default values
|
||||
:::
|
||||
|
||||
After defining your map tiles, set them in these variables:
|
||||
- `CORS_OPTIONS`
|
||||
- `connect-src` of `TALISMAN_CONFIG` and `TALISMAN_CONFIG_DEV` variables.
|
||||
|
||||
```python
|
||||
ENABLE_CORS = True
|
||||
CORS_OPTIONS: dict[Any, Any] = {
|
||||
"origins": [
|
||||
"https://tile.openstreetmap.org",
|
||||
"https://tile.osm.ch",
|
||||
"https://your_personal_url/{z}/{x}/{y}.png",
|
||||
]
|
||||
}
|
||||
|
||||
.
|
||||
.
|
||||
|
||||
TALISMAN_CONFIG = {
|
||||
"content_security_policy": {
|
||||
...
|
||||
"connect-src": [
|
||||
"'self'",
|
||||
"https://api.mapbox.com",
|
||||
"https://events.mapbox.com",
|
||||
"https://tile.openstreetmap.org",
|
||||
"https://tile.osm.ch",
|
||||
"https://your_personal_url/{z}/{x}/{y}.png",
|
||||
],
|
||||
...
|
||||
}
|
||||
```
|
||||
@@ -1,171 +0,0 @@
|
||||
---
|
||||
title: Network and Security Settings
|
||||
sidebar_position: 7
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Network and Security Settings
|
||||
|
||||
## CORS
|
||||
|
||||
|
||||
:::note
|
||||
In Superset versions prior to `5.x` you have to install to install `flask-cors` with `pip install flask-cors` to enable CORS support.
|
||||
:::
|
||||
|
||||
|
||||
The following keys in `superset_config.py` can be specified to configure CORS:
|
||||
|
||||
- `ENABLE_CORS`: Must be set to `True` in order to enable CORS
|
||||
- `CORS_OPTIONS`: options passed to Flask-CORS
|
||||
([documentation](https://flask-cors.readthedocs.io/en/latest/api.html#extension))
|
||||
|
||||
## HTTP headers
|
||||
|
||||
Note that Superset bundles [flask-talisman](https://pypi.org/project/talisman/)
|
||||
Self-described as a small Flask extension that handles setting HTTP headers that can help
|
||||
protect against a few common web application security issues.
|
||||
|
||||
## HTML Embedding of Dashboards and Charts
|
||||
|
||||
There are two ways to embed a dashboard: Using the [SDK](https://www.npmjs.com/package/@superset-ui/embedded-sdk) or embedding a direct link. Note that in the latter case everybody who knows the link is able to access the dashboard.
|
||||
|
||||
### Embedding a Public Direct Link to a Dashboard
|
||||
|
||||
This works by first changing the content security policy (CSP) of [flask-talisman](https://github.com/GoogleCloudPlatform/flask-talisman) to allow for certain domains to display Superset content. Then a dashboard can be made publicly accessible, i.e. **bypassing authentication**. Once made public, the dashboard's URL can be added to an iframe in another website's HTML code.
|
||||
|
||||
#### Changing flask-talisman CSP
|
||||
|
||||
Add to `superset_config.py` the entire `TALISMAN_CONFIG` section from `config.py` and include a `frame-ancestors` section:
|
||||
|
||||
```python
|
||||
TALISMAN_ENABLED = True
|
||||
TALISMAN_CONFIG = {
|
||||
"content_security_policy": {
|
||||
...
|
||||
"frame-ancestors": ["*.my-domain.com", "*.another-domain.com"],
|
||||
...
|
||||
```
|
||||
|
||||
Restart Superset for this configuration change to take effect.
|
||||
|
||||
#### Making a Dashboard Public
|
||||
|
||||
There are two approaches to making dashboards publicly accessible:
|
||||
|
||||
**Option 1: Dataset-based access (simpler)**
|
||||
1. Set `PUBLIC_ROLE_LIKE = "Public"` in `superset_config.py`
|
||||
2. Grant the Public role access to the relevant datasets (Menu → Security → List Roles → Public)
|
||||
3. All published dashboards using those datasets become visible to anonymous users
|
||||
|
||||
**Option 2: Dashboard-level access (selective control)**
|
||||
1. Set `PUBLIC_ROLE_LIKE = "Public"` in `superset_config.py`
|
||||
2. Add the `'DASHBOARD_RBAC': True` [Feature Flag](/docs/configuration/feature-flags)
|
||||
3. Edit each dashboard's properties and add the "Public" role
|
||||
4. Only dashboards with the Public role explicitly assigned are visible to anonymous users
|
||||
|
||||
See the [Public role documentation](/docs/security/security#public) for more details.
|
||||
|
||||
#### Embedding a Public Dashboard
|
||||
|
||||
Now anybody can directly access the dashboard's URL. You can embed it in an iframe like so:
|
||||
|
||||
```html
|
||||
<iframe
|
||||
width="600"
|
||||
height="400"
|
||||
seamless
|
||||
frameBorder="0"
|
||||
scrolling="no"
|
||||
src="https://superset.my-domain.com/superset/dashboard/10/?standalone=1&height=400"
|
||||
>
|
||||
</iframe>
|
||||
```
|
||||
|
||||
#### Embedding a Chart
|
||||
|
||||
A chart's embed code can be generated by going to a chart's edit view and then clicking at the top right on `...` > `Share` > `Embed code`
|
||||
|
||||
### Enabling Embedding via the SDK
|
||||
|
||||
Clicking on `...` next to `EDIT DASHBOARD` on the top right of the dashboard's overview page should yield a drop-down menu including the entry "Embed dashboard".
|
||||
|
||||
To enable this entry, add the following line to the `.env` file:
|
||||
|
||||
```text
|
||||
SUPERSET_FEATURE_EMBEDDED_SUPERSET=true
|
||||
```
|
||||
|
||||
### Hiding the Logout Button in Embedded Contexts
|
||||
|
||||
When Superset is embedded in an application that manages authentication via SSO (OAuth2, SAML, or JWT), the logout button should be hidden since session management is handled by the parent application.
|
||||
|
||||
To hide the logout button in embedded contexts, add to `superset_config.py`:
|
||||
|
||||
```python
|
||||
FEATURE_FLAGS = {
|
||||
"DISABLE_EMBEDDED_SUPERSET_LOGOUT": True,
|
||||
}
|
||||
```
|
||||
|
||||
This flag only hides the logout button when Superset detects it is running inside an iframe. Users accessing Superset directly (not embedded) will still see the logout button regardless of this setting.
|
||||
|
||||
:::note
|
||||
When embedding with SSO, also set `SESSION_COOKIE_SAMESITE = 'None'` and `SESSION_COOKIE_SECURE = True`. See [Security documentation](/docs/security/securing_superset) for details.
|
||||
:::
|
||||
|
||||
## CSRF settings
|
||||
|
||||
Similarly, [flask-wtf](https://flask-wtf.readthedocs.io/en/0.15.x/config/) is used to manage
|
||||
some CSRF configurations. If you need to exempt endpoints from CSRF (e.g. if you are
|
||||
running a custom auth postback endpoint), you can add the endpoints to `WTF_CSRF_EXEMPT_LIST`:
|
||||
|
||||
## SSH Tunneling
|
||||
|
||||
1. Turn on feature flag
|
||||
- Change [`SSH_TUNNELING`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L489) to `True`
|
||||
- If you want to add more security when establishing the tunnel we allow users to overwrite the `SSHTunnelManager` class [here](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L507)
|
||||
- You can also set the [`SSH_TUNNEL_LOCAL_BIND_ADDRESS`](https://github.com/apache/superset/blob/eb8386e3f0647df6d1bbde8b42073850796cc16f/superset/config.py#L508) this the host address where the tunnel will be accessible on your VPC
|
||||
|
||||
2. Create database w/ ssh tunnel enabled
|
||||
- With the feature flag enabled you should now see ssh tunnel toggle.
|
||||
- Click the toggle to enable SSH tunneling and add your credentials accordingly.
|
||||
- Superset allows for two different types of authentication (Basic + Private Key). These credentials should come from your service provider.
|
||||
|
||||
3. Verify data is flowing
|
||||
- Once SSH tunneling has been enabled, go to SQL Lab and write a query to verify data is properly flowing.
|
||||
|
||||
## Domain Sharding
|
||||
|
||||
:::note
|
||||
Domain Sharding is deprecated as of Superset 5.0.0, and will be removed in Superset 6.0.0. Please Enable HTTP2 to keep more open connections per domain.
|
||||
:::
|
||||
|
||||
Chrome allows up to 6 open connections per domain at a time. When there are more than 6 slices in
|
||||
dashboard, a lot of time fetch requests are queued up and wait for next available socket.
|
||||
[PR 5039](https://github.com/apache/superset/pull/5039) adds domain sharding to Superset,
|
||||
and this feature will be enabled by configuration only (by default Superset doesn’t allow
|
||||
cross-domain request).
|
||||
|
||||
Add the following setting in your `superset_config.py` file:
|
||||
|
||||
- `SUPERSET_WEBSERVER_DOMAINS`: list of allowed hostnames for domain sharding feature.
|
||||
|
||||
Please create your domain shards as subdomains of your main domain for authorization to
|
||||
work properly on new domains. For Example:
|
||||
|
||||
- `SUPERSET_WEBSERVER_DOMAINS=['superset-1.mydomain.com','superset-2.mydomain.com','superset-3.mydomain.com','superset-4.mydomain.com']`
|
||||
|
||||
or add the following setting in your `superset_config.py` file if domain shards are not subdomains of main domain.
|
||||
|
||||
- `SESSION_COOKIE_DOMAIN = '.mydomain.com'`
|
||||
|
||||
## Middleware
|
||||
|
||||
Superset allows you to add your own middleware. To add your own middleware, update the
|
||||
`ADDITIONAL_MIDDLEWARE` key in your `superset_config.py`. `ADDITIONAL_MIDDLEWARE` should be a list
|
||||
of your additional middleware classes.
|
||||
|
||||
For example, to use `AUTH_REMOTE_USER` from behind a proxy server like nginx, you have to add a
|
||||
simple middleware class to add the value of `HTTP_X_PROXY_REMOTE_USER` (or any other custom header
|
||||
from the proxy) to Gunicorn’s `REMOTE_USER` environment variable.
|
||||
@@ -1,596 +0,0 @@
|
||||
---
|
||||
title: SQL Templating
|
||||
hide_title: true
|
||||
sidebar_position: 5
|
||||
version: 1
|
||||
---
|
||||
|
||||
# SQL Templating
|
||||
|
||||
## Jinja Templates
|
||||
|
||||
SQL Lab and Explore supports [Jinja templating](https://jinja.palletsprojects.com/en/2.11.x/) in queries.
|
||||
To enable templating, the `ENABLE_TEMPLATE_PROCESSING` [feature flag](/docs/configuration/configuring-superset#feature-flags) needs to be enabled in `superset_config.py`.
|
||||
|
||||
:::warning[Security Warning]
|
||||
|
||||
While powerful, this feature executes template code on the server. Within the Superset security model, this is **intended functionality**, as users with permissions to edit charts and virtual datasets are considered **trusted users**.
|
||||
|
||||
If you grant these permissions to untrusted users, this feature can be exploited as a **Server-Side Template Injection (SSTI)** vulnerability. Do not enable `ENABLE_TEMPLATE_PROCESSING` unless you fully understand and accept the associated security risks.
|
||||
|
||||
:::
|
||||
|
||||
When templating is enabled, python code can be embedded in virtual datasets and
|
||||
in Custom SQL in the filter and metric controls in Explore. By default, the following variables are
|
||||
made available in the Jinja context:
|
||||
|
||||
- `columns`: columns which to group by in the query
|
||||
- `filter`: filters applied in the query
|
||||
- `from_dttm`: start `datetime` value from the selected time range (`None` if undefined). **Note:** Only available in virtual datasets when a time range filter is applied in Explore/Chart views—not available in standalone SQL Lab queries. (deprecated beginning in version 5.0, use `get_time_filter` instead)
|
||||
- `to_dttm`: end `datetime` value from the selected time range (`None` if undefined). **Note:** Only available in virtual datasets when a time range filter is applied in Explore/Chart views—not available in standalone SQL Lab queries. (deprecated beginning in version 5.0, use `get_time_filter` instead)
|
||||
- `groupby`: columns which to group by in the query (deprecated)
|
||||
- `metrics`: aggregate expressions in the query
|
||||
- `row_limit`: row limit of the query
|
||||
- `row_offset`: row offset of the query
|
||||
- `table_columns`: columns available in the dataset
|
||||
- `time_column`: temporal column of the query (`None` if undefined)
|
||||
- `time_grain`: selected time grain (`None` if undefined)
|
||||
|
||||
For example, to add a time range to a virtual dataset, you can write the following:
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM tbl
|
||||
WHERE dttm_col > '{{ from_dttm }}' and dttm_col < '{{ to_dttm }}'
|
||||
```
|
||||
|
||||
You can also use [Jinja's logic](https://jinja.palletsprojects.com/en/2.11.x/templates/#tests)
|
||||
to make your query robust to clearing the timerange filter:
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM tbl
|
||||
WHERE (
|
||||
{% if from_dttm is not none %}
|
||||
dttm_col > '{{ from_dttm }}' AND
|
||||
{% endif %}
|
||||
{% if to_dttm is not none %}
|
||||
dttm_col < '{{ to_dttm }}' AND
|
||||
{% endif %}
|
||||
1 = 1
|
||||
)
|
||||
```
|
||||
|
||||
The `1 = 1` at the end ensures a value is present for the `WHERE` clause even when
|
||||
the time filter is not set. For many database engines, this could be replaced with `true`.
|
||||
|
||||
Note that the Jinja parameters are called within _double_ brackets in the query and with
|
||||
_single_ brackets in the logic blocks.
|
||||
|
||||
### Understanding Context Availability
|
||||
|
||||
Some Jinja variables like `from_dttm`, `to_dttm`, and `filter` are **only available when a chart or dashboard provides them**. They are populated from:
|
||||
|
||||
- Time range filters applied in Explore/Chart views
|
||||
- Dashboard native filters
|
||||
- Filter components
|
||||
|
||||
**These variables are NOT available in standalone SQL Lab queries** because there's no filter context. If you try to use `{{ from_dttm }}` directly in SQL Lab, you'll get an "undefined parameter" error.
|
||||
|
||||
#### Testing Time-Filtered Queries in SQL Lab
|
||||
|
||||
To test queries that use time variables in SQL Lab, you have several options:
|
||||
|
||||
**Option 1: Use Jinja defaults (recommended)**
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM tbl
|
||||
WHERE dttm_col > '{{ from_dttm | default("2024-01-01", true) }}'
|
||||
AND dttm_col < '{{ to_dttm | default("2024-12-31", true) }}'
|
||||
```
|
||||
|
||||
**Option 2: Use SQL Lab Parameters**
|
||||
|
||||
Set parameters in the SQL Lab UI (Parameters menu):
|
||||
```json
|
||||
{
|
||||
"from_dttm": "2024-01-01",
|
||||
"to_dttm": "2024-12-31"
|
||||
}
|
||||
```
|
||||
|
||||
**Option 3: Use `{% set %}` for testing**
|
||||
|
||||
```sql
|
||||
{% set from_dttm = "2024-01-01" %}
|
||||
{% set to_dttm = "2024-12-31" %}
|
||||
SELECT *
|
||||
FROM tbl
|
||||
WHERE dttm_col > '{{ from_dttm }}' AND dttm_col < '{{ to_dttm }}'
|
||||
```
|
||||
|
||||
:::tip
|
||||
When you save a SQL Lab query as a virtual dataset and use it in a chart with time filters,
|
||||
the actual filter values will override any defaults or test values you set.
|
||||
:::
|
||||
|
||||
To add custom functionality to the Jinja context, you need to overload the default Jinja
|
||||
context in your environment by defining the `JINJA_CONTEXT_ADDONS` in your superset configuration
|
||||
(`superset_config.py`). Objects referenced in this dictionary are made available for users to use
|
||||
where the Jinja context is made available.
|
||||
|
||||
```python
|
||||
JINJA_CONTEXT_ADDONS = {
|
||||
'my_crazy_macro': lambda x: x*2,
|
||||
}
|
||||
```
|
||||
|
||||
Default values for jinja templates can be specified via `Parameters` menu in the SQL Lab user interface.
|
||||
In the UI you can assign a set of parameters as JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"my_table": "foo"
|
||||
}
|
||||
```
|
||||
|
||||
The parameters become available in your SQL (example: `SELECT * FROM {{ my_table }}` ) by using Jinja templating syntax.
|
||||
SQL Lab template parameters are stored with the dataset as `TEMPLATE PARAMETERS`.
|
||||
|
||||
There is a special ``_filters`` parameter which can be used to test filters used in the jinja template.
|
||||
|
||||
```json
|
||||
{
|
||||
"_filters": [
|
||||
{
|
||||
"col": "action_type",
|
||||
"op": "IN",
|
||||
"val": ["sell", "buy"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```sql
|
||||
SELECT action, count(*) as times
|
||||
FROM logs
|
||||
WHERE action in {{ filter_values('action_type')|where_in }}
|
||||
GROUP BY action
|
||||
```
|
||||
|
||||
Note ``_filters`` is not stored with the dataset. It's only used within the SQL Lab UI.
|
||||
|
||||
Besides default Jinja templating, SQL lab also supports self-defined template processor by setting
|
||||
the `CUSTOM_TEMPLATE_PROCESSORS` in your superset configuration. The values in this dictionary
|
||||
overwrite the default Jinja template processors of the specified database engine. The example below
|
||||
configures a custom presto template processor which implements its own logic of processing macro
|
||||
template with regex parsing. It uses the `$` style macro instead of `{{ }}` style in Jinja
|
||||
templating.
|
||||
|
||||
By configuring it with `CUSTOM_TEMPLATE_PROCESSORS`, a SQL template on a presto database is
|
||||
processed by the custom one rather than the default one.
|
||||
|
||||
```python
|
||||
def DATE(
|
||||
ts: datetime, day_offset: SupportsInt = 0, hour_offset: SupportsInt = 0
|
||||
) -> str:
|
||||
"""Current day as a string."""
|
||||
day_offset, hour_offset = int(day_offset), int(hour_offset)
|
||||
offset_day = (ts + timedelta(days=day_offset, hours=hour_offset)).date()
|
||||
return str(offset_day)
|
||||
|
||||
class CustomPrestoTemplateProcessor(PrestoTemplateProcessor):
|
||||
"""A custom presto template processor."""
|
||||
|
||||
engine = "presto"
|
||||
|
||||
def process_template(self, sql: str, **kwargs) -> str:
|
||||
"""Processes a sql template with $ style macro using regex."""
|
||||
# Add custom macros functions.
|
||||
macros = {
|
||||
"DATE": partial(DATE, datetime.utcnow())
|
||||
} # type: Dict[str, Any]
|
||||
# Update with macros defined in context and kwargs.
|
||||
macros.update(self.context)
|
||||
macros.update(kwargs)
|
||||
|
||||
def replacer(match):
|
||||
"""Expand $ style macros with corresponding function calls."""
|
||||
macro_name, args_str = match.groups()
|
||||
args = [a.strip() for a in args_str.split(",")]
|
||||
if args == [""]:
|
||||
args = []
|
||||
f = macros[macro_name[1:]]
|
||||
return f(*args)
|
||||
|
||||
macro_names = ["$" + name for name in macros.keys()]
|
||||
pattern = r"(%s)\s*\(([^()]*)\)" % "|".join(map(re.escape, macro_names))
|
||||
return re.sub(pattern, replacer, sql)
|
||||
|
||||
CUSTOM_TEMPLATE_PROCESSORS = {
|
||||
CustomPrestoTemplateProcessor.engine: CustomPrestoTemplateProcessor
|
||||
}
|
||||
```
|
||||
|
||||
SQL Lab also includes a live query validation feature with pluggable backends. You can configure
|
||||
which validation implementation is used with which database engine by adding a block like the
|
||||
following to your configuration file:
|
||||
|
||||
```python
|
||||
FEATURE_FLAGS = {
|
||||
'SQL_VALIDATORS_BY_ENGINE': {
|
||||
'presto': 'PrestoDBSQLValidator',
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The available validators and names can be found in
|
||||
[sql_validators](https://github.com/apache/superset/tree/master/superset/sql_validators).
|
||||
|
||||
## Available Macros
|
||||
|
||||
In this section, we'll walkthrough the pre-defined Jinja macros in Superset.
|
||||
|
||||
### Current Username
|
||||
|
||||
The `{{ current_username() }}` macro returns the `username` of the currently logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the `username` value will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
cache hit in the future and Superset can retrieve cached data.
|
||||
|
||||
You can disable the inclusion of the `username` value in the calculation of the
|
||||
cache key by adding the following parameter to your Jinja code:
|
||||
|
||||
```python
|
||||
{{ current_username(add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
### Current User ID
|
||||
|
||||
The `{{ current_user_id() }}` macro returns the account ID of the currently logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the account `id` value will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
cache hit in the future and Superset can retrieve cached data.
|
||||
|
||||
You can disable the inclusion of the account `id` value in the calculation of the
|
||||
cache key by adding the following parameter to your Jinja code:
|
||||
|
||||
```python
|
||||
{{ current_user_id(add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
### Current User Email
|
||||
|
||||
The `{{ current_user_email() }}` macro returns the email address of the currently logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the email address value will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
cache hit in the future and Superset can retrieve cached data.
|
||||
|
||||
You can disable the inclusion of the email value in the calculation of the
|
||||
cache key by adding the following parameter to your Jinja code:
|
||||
|
||||
```python
|
||||
{{ current_user_email(add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
### Current User Roles
|
||||
|
||||
The `{{ current_user_roles() }}` macro returns an array of roles for the logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the roles value will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
cache hit in the future and Superset can retrieve cached data.
|
||||
|
||||
You can disable the inclusion of the roles value in the calculation of the
|
||||
cache key by adding the following parameter to your Jinja code:
|
||||
|
||||
```python
|
||||
{{ current_user_roles(add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
You can json-stringify the array by adding `|tojson` to your Jinja code:
|
||||
```python
|
||||
{{ current_user_roles()|tojson }}
|
||||
```
|
||||
|
||||
You can use the `|where_in` filter to use your roles in a SQL statement. For example, if `current_user_roles()` returns `['admin', 'viewer']`, the following template:
|
||||
```python
|
||||
SELECT * FROM users WHERE role IN {{ current_user_roles()|where_in }}
|
||||
```
|
||||
|
||||
Will be rendered as:
|
||||
```sql
|
||||
SELECT * FROM users WHERE role IN ('admin', 'viewer')
|
||||
```
|
||||
|
||||
### Current User RLS Rules
|
||||
|
||||
The `{{ current_user_rls_rules() }}` macro returns an array of RLS rules applied to the current dataset for the logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then the list of RLS Rules will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
cache hit in the future and Superset can retrieve cached data.
|
||||
|
||||
### Custom URL Parameters
|
||||
|
||||
The `{{ url_param('custom_variable') }}` macro lets you define arbitrary URL
|
||||
parameters and reference them in your SQL code.
|
||||
|
||||
Here's a concrete example:
|
||||
|
||||
- You write the following query in SQL Lab:
|
||||
|
||||
```sql
|
||||
SELECT count(*)
|
||||
FROM ORDERS
|
||||
WHERE country_code = '{{ url_param('countrycode') }}'
|
||||
```
|
||||
|
||||
- You're hosting Superset at the domain www.example.com and you send your
|
||||
coworker in Spain the following SQL Lab URL `www.example.com/superset/sqllab?countrycode=ES`
|
||||
and your coworker in the USA the following SQL Lab URL `www.example.com/superset/sqllab?countrycode=US`
|
||||
- For your coworker in Spain, the SQL Lab query will be rendered as:
|
||||
|
||||
```sql
|
||||
SELECT count(*)
|
||||
FROM ORDERS
|
||||
WHERE country_code = 'ES'
|
||||
```
|
||||
|
||||
- For your coworker in the USA, the SQL Lab query will be rendered as:
|
||||
|
||||
```sql
|
||||
SELECT count(*)
|
||||
FROM ORDERS
|
||||
WHERE country_code = 'US'
|
||||
```
|
||||
|
||||
### Explicitly Including Values in Cache Key
|
||||
|
||||
The `{{ cache_key_wrapper() }}` function explicitly instructs Superset to add a value to the
|
||||
accumulated list of values used in the calculation of the cache key.
|
||||
|
||||
This function is only needed when you want to wrap your own custom function return values
|
||||
in the cache key. You can gain more context
|
||||
[here](https://github.com/apache/superset/blob/efd70077014cbed62e493372d33a2af5237eaadf/superset/jinja_context.py#L133-L148).
|
||||
|
||||
Note that this function powers the caching of the `user_id` and `username` values
|
||||
in the `current_user_id()` and `current_username()` function calls (if you have caching enabled).
|
||||
|
||||
### Filter Values
|
||||
|
||||
You can retrieve the value for a specific filter as a list using `{{ filter_values() }}`.
|
||||
|
||||
This is useful if:
|
||||
|
||||
- You want to use a filter component to filter a query where the name of filter component column doesn't match the one in the select statement
|
||||
- You want to have the ability to filter inside the main query for performance purposes
|
||||
|
||||
Here's a concrete example:
|
||||
|
||||
```sql
|
||||
SELECT action, count(*) as times
|
||||
FROM logs
|
||||
WHERE
|
||||
action in {{ filter_values('action_type')|where_in }}
|
||||
GROUP BY action
|
||||
```
|
||||
|
||||
There `where_in` filter converts the list of values from `filter_values('action_type')` into a string suitable for an `IN` expression.
|
||||
|
||||
### Filters for a Specific Column
|
||||
|
||||
The `{{ get_filters() }}` macro returns the filters applied to a given column. In addition to
|
||||
returning the values (similar to how `filter_values()` does), the `get_filters()` macro
|
||||
returns the operator specified in the Explore UI.
|
||||
|
||||
This is useful if:
|
||||
|
||||
- You want to handle more than the IN operator in your SQL clause
|
||||
- You want to handle generating custom SQL conditions for a filter
|
||||
- You want to have the ability to filter inside the main query for speed purposes
|
||||
|
||||
Here's a concrete example:
|
||||
|
||||
```sql
|
||||
WITH RECURSIVE
|
||||
superiors(employee_id, manager_id, full_name, level, lineage) AS (
|
||||
SELECT
|
||||
employee_id,
|
||||
manager_id,
|
||||
full_name,
|
||||
1 as level,
|
||||
employee_id as lineage
|
||||
FROM
|
||||
employees
|
||||
WHERE
|
||||
1=1
|
||||
|
||||
{# Render a blank line #}
|
||||
{%- for filter in get_filters('full_name', remove_filter=True) -%}
|
||||
|
||||
{%- if filter.get('op') == 'IN' -%}
|
||||
AND
|
||||
full_name IN {{ filter.get('val')|where_in }}
|
||||
{%- endif -%}
|
||||
|
||||
{%- if filter.get('op') == 'LIKE' -%}
|
||||
AND
|
||||
full_name LIKE {{ "'" + filter.get('val') + "'" }}
|
||||
{%- endif -%}
|
||||
|
||||
{%- endfor -%}
|
||||
UNION ALL
|
||||
SELECT
|
||||
e.employee_id,
|
||||
e.manager_id,
|
||||
e.full_name,
|
||||
s.level + 1 as level,
|
||||
s.lineage
|
||||
FROM
|
||||
employees e,
|
||||
superiors s
|
||||
WHERE s.manager_id = e.employee_id
|
||||
)
|
||||
|
||||
SELECT
|
||||
employee_id, manager_id, full_name, level, lineage
|
||||
FROM
|
||||
superiors
|
||||
order by lineage, level
|
||||
```
|
||||
|
||||
### Time Filter
|
||||
|
||||
The `{{ get_time_filter() }}` macro returns the time filter applied to a specific column. This is useful if you want
|
||||
to handle time filters inside the virtual dataset, as by default the time filter is placed on the outer query. This can
|
||||
considerably improve performance, as many databases and query engines are able to optimize the query better
|
||||
if the temporal filter is placed on the inner query, as opposed to the outer query.
|
||||
|
||||
The macro takes the following parameters:
|
||||
|
||||
- `column`: Name of the temporal column. Leave undefined to reference the time range from a Dashboard Native Time Range
|
||||
filter (when present).
|
||||
- `default`: The default value to fall back to if the time filter is not present, or has the value `No filter`
|
||||
- `target_type`: The target temporal type as recognized by the target database (e.g. `TIMESTAMP`, `DATE` or
|
||||
`DATETIME`). If `column` is defined, the format will default to the type of the column. This is used to produce
|
||||
the format of the `from_expr` and `to_expr` properties of the returned `TimeFilter` object.
|
||||
- `strftime`: format using the `strftime` method of `datetime` for custom time formatting.
|
||||
([see docs for valid format codes](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes)).
|
||||
When defined `target_type` will be ignored.
|
||||
- `remove_filter`: When set to true, mark the filter as processed, removing it from the outer query. Useful when a
|
||||
filter should only apply to the inner query.
|
||||
|
||||
The return type has the following properties:
|
||||
|
||||
- `from_expr`: the start of the time filter (if any)
|
||||
- `to_expr`: the end of the time filter (if any)
|
||||
- `time_range`: The applied time range
|
||||
|
||||
Here's a concrete example using the `logs` table from the Superset metastore:
|
||||
|
||||
```
|
||||
{% set time_filter = get_time_filter("dttm", remove_filter=True) %}
|
||||
{% set from_expr = time_filter.from_expr %}
|
||||
{% set to_expr = time_filter.to_expr %}
|
||||
{% set time_range = time_filter.time_range %}
|
||||
SELECT
|
||||
*,
|
||||
'{{ time_range }}' as time_range
|
||||
FROM logs
|
||||
{% if from_expr or to_expr %}WHERE 1 = 1
|
||||
{% if from_expr %}AND dttm >= {{ from_expr }}{% endif %}
|
||||
{% if to_expr %}AND dttm < {{ to_expr }}{% endif %}
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
Assuming we are creating a table chart with a simple `COUNT(*)` as the metric with a time filter `Last week` on the
|
||||
`dttm` column, this would render the following query on Postgres (note the formatting of the temporal filters, and
|
||||
the absence of time filters on the outer query):
|
||||
|
||||
```
|
||||
SELECT COUNT(*) AS count
|
||||
FROM
|
||||
(SELECT *,
|
||||
'Last week' AS time_range
|
||||
FROM public.logs
|
||||
WHERE 1 = 1
|
||||
AND dttm >= TO_TIMESTAMP('2024-08-27 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US')
|
||||
AND dttm < TO_TIMESTAMP('2024-09-03 00:00:00.000000', 'YYYY-MM-DD HH24:MI:SS.US')) AS virtual_table
|
||||
ORDER BY count DESC
|
||||
LIMIT 1000;
|
||||
```
|
||||
|
||||
When using the `default` parameter, the templated query can be simplified, as the endpoints will always be defined
|
||||
(to use a fixed time range, you can also use something like `default="2024-08-27 : 2024-09-03"`)
|
||||
|
||||
```
|
||||
{% set time_filter = get_time_filter("dttm", default="Last week", remove_filter=True) %}
|
||||
SELECT
|
||||
*,
|
||||
'{{ time_filter.time_range }}' as time_range
|
||||
FROM logs
|
||||
WHERE
|
||||
dttm >= {{ time_filter.from_expr }}
|
||||
AND dttm < {{ time_filter.to_expr }}
|
||||
```
|
||||
|
||||
### Datasets
|
||||
|
||||
It's possible to query physical and virtual datasets using the `dataset` macro. This is useful if you've defined computed columns and metrics on your datasets, and want to reuse the definition in adhoc SQL Lab queries.
|
||||
|
||||
To use the macro, first you need to find the ID of the dataset. This can be done by going to the view showing all the datasets, hovering over the dataset you're interested in, and looking at its URL. For example, if the URL for a dataset is https://superset.example.org/explore/?dataset_type=table&dataset_id=42 its ID is 42.
|
||||
|
||||
Once you have the ID you can query it as if it were a table:
|
||||
|
||||
```sql
|
||||
SELECT * FROM {{ dataset(42) }} LIMIT 10
|
||||
```
|
||||
|
||||
If you want to select the metric definitions as well, in addition to the columns, you need to pass an additional keyword argument:
|
||||
|
||||
```sql
|
||||
SELECT * FROM {{ dataset(42, include_metrics=True) }} LIMIT 10
|
||||
```
|
||||
|
||||
Since metrics are aggregations, the resulting SQL expression will be grouped by all non-metric columns. You can specify a subset of columns to group by instead:
|
||||
|
||||
```sql
|
||||
SELECT * FROM {{ dataset(42, include_metrics=True, columns=["ds", "category"]) }} LIMIT 10
|
||||
```
|
||||
|
||||
### Metrics
|
||||
|
||||
The `{{ metric('metric_key', dataset_id) }}` macro can be used to retrieve the metric SQL syntax from a dataset. This can be useful for different purposes:
|
||||
|
||||
- Override the metric label in the chart level
|
||||
- Combine multiple metrics in a calculation
|
||||
- Retrieve a metric syntax in SQL lab
|
||||
- Re-use metrics across datasets
|
||||
|
||||
This macro avoids copy/paste, allowing users to centralize the metric definition in the dataset layer.
|
||||
|
||||
The `dataset_id` parameter is optional, and if not provided Superset will use the current dataset from context (for example, when using this macro in the Chart Builder, by default the `macro_key` will be searched in the dataset powering the chart).
|
||||
The parameter can be used in SQL Lab, or when fetching a metric from another dataset.
|
||||
|
||||
## Available Filters
|
||||
|
||||
Superset supports [builtin filters from the Jinja2 templating package](https://jinja.palletsprojects.com/en/stable/templates/#builtin-filters). Custom filters have also been implemented:
|
||||
|
||||
### Where In
|
||||
Parses a list into a SQL-compatible statement. This is useful with macros that return an array (for example the `filter_values` macro):
|
||||
|
||||
```
|
||||
Dashboard filter with "First", "Second" and "Third" options selected
|
||||
{{ filter_values('column') }} => ["First", "Second", "Third"]
|
||||
{{ filter_values('column')|where_in }} => ('First', 'Second', 'Third')
|
||||
```
|
||||
|
||||
By default, this filter returns `()` (as a string) in case the value is null. The `default_to_none` parameter can be se to `True` to return null in this case:
|
||||
|
||||
```
|
||||
Dashboard filter without any value applied
|
||||
{{ filter_values('column') }} => ()
|
||||
{{ filter_values('column')|where_in(default_to_none=True) }} => None
|
||||
```
|
||||
|
||||
### To Datetime
|
||||
|
||||
Loads a string as a `datetime` object. This is useful when performing date operations. For example:
|
||||
```
|
||||
{% set from_expr = get_time_filter("dttm", strftime="%Y-%m-%d").from_expr %}
|
||||
{% set to_expr = get_time_filter("dttm", strftime="%Y-%m-%d").to_expr %}
|
||||
{% if (to_expr|to_datetime(format="%Y-%m-%d") - from_expr|to_datetime(format="%Y-%m-%d")).days > 100 %}
|
||||
do something
|
||||
{% else %}
|
||||
do something else
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
:::resources
|
||||
- [Blog: Intro to Jinja Templating in Apache Superset](https://preset.io/blog/intro-jinja-templating-apache-superset/)
|
||||
:::
|
||||
@@ -1,405 +0,0 @@
|
||||
---
|
||||
title: Theming
|
||||
hide_title: true
|
||||
sidebar_position: 12
|
||||
version: 1
|
||||
---
|
||||
# Theming Superset
|
||||
|
||||
:::note
|
||||
`apache-superset>=6.0`
|
||||
:::
|
||||
|
||||
Superset now rides on **Ant Design v5's token-based theming**.
|
||||
Every Antd token works, plus a handful of Superset-specific ones for charts and dashboard chrome.
|
||||
|
||||
## Managing Themes via UI
|
||||
|
||||
Superset includes a built-in **Theme Management** interface accessible from the admin menu under **Settings > Themes**.
|
||||
|
||||
### Creating a New Theme
|
||||
|
||||
1. Navigate to **Settings > Themes** in the Superset interface
|
||||
2. Click **+ Theme** to create a new theme
|
||||
3. Use the [Ant Design Theme Editor](https://ant.design/theme-editor) to design your theme:
|
||||
- Design your palette, typography, and component overrides
|
||||
- Open the `CONFIG` modal and copy the JSON configuration
|
||||
4. Paste the JSON into the theme definition field in Superset
|
||||
5. Give your theme a descriptive name and save
|
||||
|
||||
You can also extend with Superset-specific tokens (documented in the default theme object) before you import.
|
||||
|
||||
### System Theme Administration
|
||||
|
||||
When `ENABLE_UI_THEME_ADMINISTRATION = True` is configured, administrators can manage system-wide themes directly from the UI:
|
||||
|
||||
#### Setting System Themes
|
||||
- **System Default Theme**: Click the sun icon on any theme to set it as the system-wide default
|
||||
- **System Dark Theme**: Click the moon icon on any theme to set it as the system dark mode theme
|
||||
- **Automatic OS Detection**: When both default and dark themes are set, Superset automatically detects and applies the appropriate theme based on OS preferences
|
||||
|
||||
#### Managing System Themes
|
||||
- System themes are indicated with special badges in the theme list
|
||||
- Only administrators with write permissions can modify system theme settings
|
||||
- Removing a system theme designation reverts to configuration file defaults
|
||||
|
||||
### Applying Themes to Dashboards
|
||||
|
||||
Once created, themes can be applied to individual dashboards:
|
||||
- Edit any dashboard and select your custom theme from the theme dropdown
|
||||
- Each dashboard can have its own theme, allowing for branded or context-specific styling
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Python Configuration
|
||||
|
||||
Configure theme behavior via `superset_config.py`:
|
||||
|
||||
```python
|
||||
# Enable UI-based theme administration for admins
|
||||
ENABLE_UI_THEME_ADMINISTRATION = True
|
||||
|
||||
# Optional: Set initial default themes via configuration
|
||||
# These can be overridden via the UI when ENABLE_UI_THEME_ADMINISTRATION = True
|
||||
THEME_DEFAULT = {
|
||||
"token": {
|
||||
"colorPrimary": "#2893B3",
|
||||
"colorSuccess": "#5ac189",
|
||||
# ... your theme JSON configuration
|
||||
}
|
||||
}
|
||||
|
||||
# Optional: Dark theme configuration
|
||||
THEME_DARK = {
|
||||
"algorithm": "dark",
|
||||
"token": {
|
||||
"colorPrimary": "#2893B3",
|
||||
# ... your dark theme overrides
|
||||
}
|
||||
}
|
||||
|
||||
# To force a single theme on all users, set THEME_DARK = None
|
||||
# When both themes are defined (via UI or config):
|
||||
# - Users can manually switch between themes
|
||||
# - OS preference detection is automatically enabled
|
||||
```
|
||||
|
||||
### Migration from Configuration to UI
|
||||
|
||||
When `ENABLE_UI_THEME_ADMINISTRATION = True`:
|
||||
|
||||
1. System themes set via the UI take precedence over configuration file settings
|
||||
2. The UI shows which themes are currently set as system defaults
|
||||
3. Administrators can change system themes without restarting Superset
|
||||
4. Configuration file themes serve as fallbacks when no UI themes are set
|
||||
|
||||
### Copying Themes Between Systems
|
||||
|
||||
To export a theme for use in configuration files or another instance:
|
||||
|
||||
1. Navigate to **Settings > Themes** and click the export icon on your desired theme
|
||||
2. Extract the JSON configuration from the exported YAML file
|
||||
3. Use this JSON in your `superset_config.py` or import it into another Superset instance
|
||||
|
||||
## Theme Development Workflow
|
||||
|
||||
1. **Design**: Use the [Ant Design Theme Editor](https://ant.design/theme-editor) to iterate on your design
|
||||
2. **Test**: Create themes in Superset's CRUD interface for testing
|
||||
3. **Apply**: Assign themes to specific dashboards or configure instance-wide
|
||||
4. **Iterate**: Modify theme JSON directly in the CRUD interface or re-import from the theme editor
|
||||
|
||||
## Custom Fonts
|
||||
|
||||
Superset supports custom fonts through the theme configuration, allowing you to use branded or custom typefaces without rebuilding the application.
|
||||
|
||||
### Default Fonts
|
||||
|
||||
By default, Superset uses Inter and Fira Code fonts which are bundled with the application via `@fontsource` packages. These fonts work offline and require no external network calls.
|
||||
|
||||
### Configuring Custom Fonts
|
||||
|
||||
To use custom fonts, add font URLs to your theme configuration using the `fontUrls` token:
|
||||
|
||||
```python
|
||||
THEME_DEFAULT = {
|
||||
"token": {
|
||||
# Load fonts from external sources (e.g., Google Fonts, Adobe Fonts)
|
||||
"fontUrls": [
|
||||
"https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap",
|
||||
"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap",
|
||||
],
|
||||
# Reference the loaded fonts
|
||||
"fontFamily": "Roboto, -apple-system, BlinkMacSystemFont, sans-serif",
|
||||
"fontFamilyCode": "JetBrains Mono, Monaco, monospace",
|
||||
# ... other theme tokens
|
||||
}
|
||||
}
|
||||
|
||||
# Update CSP to allow font sources
|
||||
TALISMAN_CONFIG = {
|
||||
"content_security_policy": {
|
||||
"font-src": ["'self'", "https://fonts.googleapis.com", "https://fonts.gstatic.com"],
|
||||
"style-src": ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or in the CRUD interface theme JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": {
|
||||
"fontUrls": [
|
||||
"https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap"
|
||||
],
|
||||
"fontFamily": "Roboto, -apple-system, BlinkMacSystemFont, sans-serif",
|
||||
"fontFamilyCode": "JetBrains Mono, Monaco, monospace"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
Font URLs are validated against a configurable allowlist. By default, fonts from `fonts.googleapis.com`, `fonts.gstatic.com`, and `use.typekit.net` are allowed. Configure `THEME_FONT_URL_ALLOWED_DOMAINS` to customize the allowed domains.
|
||||
:::
|
||||
|
||||
### Font Sources
|
||||
|
||||
- **Google Fonts**: Free, CDN-hosted fonts with wide variety
|
||||
- **Adobe Fonts**: Premium fonts (requires subscription and kit ID)
|
||||
- **Self-hosted**: Place font files in `/static/assets/fonts/` and reference via CSS
|
||||
|
||||
This feature works with the stock Docker image - no custom build required!
|
||||
|
||||
## ECharts Configuration Overrides
|
||||
|
||||
:::note
|
||||
Available since Superset 6.0
|
||||
:::
|
||||
|
||||
Superset provides fine-grained control over ECharts visualizations through theme-level configuration overrides. This allows you to customize the appearance and behavior of all ECharts-based charts without modifying individual chart configurations.
|
||||
|
||||
### Global ECharts Overrides
|
||||
|
||||
Apply settings to all ECharts visualizations using `echartsOptionsOverrides`:
|
||||
|
||||
```python
|
||||
THEME_DEFAULT = {
|
||||
"token": {
|
||||
"colorPrimary": "#2893B3",
|
||||
# ... other Ant Design tokens
|
||||
},
|
||||
"echartsOptionsOverrides": {
|
||||
"grid": {
|
||||
"left": "10%",
|
||||
"right": "10%",
|
||||
"top": "15%",
|
||||
"bottom": "15%"
|
||||
},
|
||||
"tooltip": {
|
||||
"backgroundColor": "rgba(0, 0, 0, 0.8)",
|
||||
"borderColor": "#ccc",
|
||||
"textStyle": {
|
||||
"color": "#fff"
|
||||
}
|
||||
},
|
||||
"legend": {
|
||||
"textStyle": {
|
||||
"fontSize": 14,
|
||||
"fontWeight": "bold"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Chart-Specific Overrides
|
||||
|
||||
Target specific chart types using `echartsOptionsOverridesByChartType`:
|
||||
|
||||
```python
|
||||
THEME_DEFAULT = {
|
||||
"token": {
|
||||
"colorPrimary": "#2893B3",
|
||||
# ... other tokens
|
||||
},
|
||||
"echartsOptionsOverridesByChartType": {
|
||||
"echarts_pie": {
|
||||
"legend": {
|
||||
"orient": "vertical",
|
||||
"right": 10,
|
||||
"top": "center"
|
||||
}
|
||||
},
|
||||
"echarts_timeseries": {
|
||||
"xAxis": {
|
||||
"axisLabel": {
|
||||
"rotate": 45,
|
||||
"fontSize": 12
|
||||
}
|
||||
},
|
||||
"dataZoom": [{
|
||||
"type": "slider",
|
||||
"show": True,
|
||||
"start": 0,
|
||||
"end": 100
|
||||
}]
|
||||
},
|
||||
"echarts_bubble": {
|
||||
"grid": {
|
||||
"left": "15%",
|
||||
"bottom": "20%"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### UI Configuration
|
||||
|
||||
You can also configure ECharts overrides through the theme CRUD interface:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": {
|
||||
"colorPrimary": "#2893B3"
|
||||
},
|
||||
"echartsOptionsOverrides": {
|
||||
"grid": {
|
||||
"left": "10%",
|
||||
"right": "10%"
|
||||
},
|
||||
"tooltip": {
|
||||
"backgroundColor": "rgba(0, 0, 0, 0.8)"
|
||||
}
|
||||
},
|
||||
"echartsOptionsOverridesByChartType": {
|
||||
"echarts_pie": {
|
||||
"legend": {
|
||||
"orient": "vertical",
|
||||
"right": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Override Precedence
|
||||
|
||||
The system applies overrides in the following order (last wins):
|
||||
|
||||
1. **Base ECharts theme** - Default Superset styling
|
||||
2. **Plugin options** - Chart-specific configurations
|
||||
3. **Global overrides** - `echartsOptionsOverrides`
|
||||
4. **Chart-specific overrides** - `echartsOptionsOverridesByChartType[chartType]`
|
||||
|
||||
This ensures chart-specific overrides take precedence over global ones.
|
||||
|
||||
### Common Chart Types
|
||||
|
||||
Available chart types for `echartsOptionsOverridesByChartType`:
|
||||
|
||||
- `echarts_timeseries` - Time series/line charts
|
||||
- `echarts_pie` - Pie and donut charts
|
||||
- `echarts_bubble` - Bubble/scatter charts
|
||||
- `echarts_funnel` - Funnel charts
|
||||
- `echarts_gauge` - Gauge charts
|
||||
- `echarts_radar` - Radar charts
|
||||
- `echarts_boxplot` - Box plot charts
|
||||
- `echarts_treemap` - Treemap charts
|
||||
- `echarts_sunburst` - Sunburst charts
|
||||
- `echarts_graph` - Network/graph charts
|
||||
- `echarts_sankey` - Sankey diagrams
|
||||
- `echarts_heatmap` - Heatmaps
|
||||
- `echarts_mixed_timeseries` - Mixed time series
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Start with global overrides** for consistent styling across all charts
|
||||
2. **Use chart-specific overrides** for unique requirements per visualization type
|
||||
3. **Test thoroughly** as overrides use deep merge - nested objects are combined, but arrays are completely replaced
|
||||
4. **Document your overrides** to help team members understand custom styling
|
||||
5. **Consider performance** - complex overrides may impact chart rendering speed
|
||||
|
||||
### Example: Corporate Branding
|
||||
|
||||
```python
|
||||
# Complete corporate theme with ECharts customization
|
||||
THEME_DEFAULT = {
|
||||
"token": {
|
||||
"colorPrimary": "#1B4D3E",
|
||||
"fontFamily": "Corporate Sans, Arial, sans-serif"
|
||||
},
|
||||
"echartsOptionsOverrides": {
|
||||
"grid": {
|
||||
"left": "8%",
|
||||
"right": "8%",
|
||||
"top": "12%",
|
||||
"bottom": "12%"
|
||||
},
|
||||
"textStyle": {
|
||||
"fontFamily": "Corporate Sans, Arial, sans-serif"
|
||||
},
|
||||
"title": {
|
||||
"textStyle": {
|
||||
"color": "#1B4D3E",
|
||||
"fontSize": 18,
|
||||
"fontWeight": "bold"
|
||||
}
|
||||
}
|
||||
},
|
||||
"echartsOptionsOverridesByChartType": {
|
||||
"echarts_timeseries": {
|
||||
"xAxis": {
|
||||
"axisLabel": {
|
||||
"color": "#666",
|
||||
"fontSize": 11
|
||||
}
|
||||
}
|
||||
},
|
||||
"echarts_pie": {
|
||||
"legend": {
|
||||
"textStyle": {
|
||||
"fontSize": 12
|
||||
},
|
||||
"itemGap": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This feature provides powerful theming capabilities while maintaining the flexibility of ECharts' extensive configuration options.
|
||||
|
||||
## Advanced Features
|
||||
|
||||
- **System Themes**: Manage system-wide default and dark themes via UI or configuration
|
||||
- **Per-Dashboard Theming**: Each dashboard can have its own visual identity
|
||||
- **JSON Editor**: Edit theme configurations directly within Superset's interface
|
||||
- **Custom Fonts**: Load external fonts via configuration without rebuilding
|
||||
- **OS Dark Mode Detection**: Automatically switches themes based on system preferences
|
||||
- **Theme Import/Export**: Share themes between instances via YAML files
|
||||
|
||||
## API Access
|
||||
|
||||
For programmatic theme management, Superset provides REST endpoints:
|
||||
|
||||
- `GET /api/v1/theme/` - List all themes
|
||||
- `POST /api/v1/theme/` - Create a new theme
|
||||
- `PUT /api/v1/theme/{id}` - Update a theme
|
||||
- `DELETE /api/v1/theme/{id}` - Delete a theme
|
||||
- `PUT /api/v1/theme/{id}/set_system_default` - Set as system default theme (admin only)
|
||||
- `PUT /api/v1/theme/{id}/set_system_dark` - Set as system dark theme (admin only)
|
||||
- `DELETE /api/v1/theme/unset_system_default` - Remove system default designation
|
||||
- `DELETE /api/v1/theme/unset_system_dark` - Remove system dark designation
|
||||
- `GET /api/v1/theme/export/` - Export themes as YAML
|
||||
- `POST /api/v1/theme/import/` - Import themes from YAML
|
||||
|
||||
These endpoints require appropriate permissions and are subject to RBAC controls.
|
||||
|
||||
:::resources
|
||||
- [Video: Live Demo — Theming Apache Superset](https://www.youtube.com/watch?v=XsZAsO9tC3o)
|
||||
- [CSS and Theming](https://docs.preset.io/docs/css-and-theming) - Additional theming techniques and CSS customization
|
||||
- [Blog: Customizing Apache Superset Dashboards with CSS](https://preset.io/blog/customizing-superset-dashboards-with-css/)
|
||||
- [Blog: Customizing Dashboards with CSS — Tips and Tricks](https://preset.io/blog/customizing-apache-superset-dashboards-with-css-additional-tips-and-tricks/)
|
||||
- [Blog: Customizing Chart Colors](https://preset.io/blog/customizing-chart-colors-with-superset-and-preset/)
|
||||
:::
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
title: Timezones
|
||||
hide_title: true
|
||||
sidebar_position: 6
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Timezones
|
||||
|
||||
There are four distinct timezone components which relate to Apache Superset,
|
||||
|
||||
1. The timezone that the underlying data is encoded in.
|
||||
2. The timezone of the database engine.
|
||||
3. The timezone of the Apache Superset backend.
|
||||
4. The timezone of the Apache Superset client.
|
||||
|
||||
where if a temporal field (`DATETIME`, `TIME`, `TIMESTAMP`, etc.) does not explicitly define a timezone it defaults to the underlying timezone of the component.
|
||||
|
||||
To help make the problem somewhat tractable—given that Apache Superset has no control on either how the data is ingested (1) or the timezone of the client (4)—from a consistency standpoint it is highly recommended that both (2) and (3) are configured to use the same timezone with a strong preference given to [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) to ensure temporal fields without an explicit timestamp are not incorrectly coerced into the wrong timezone. Actually Apache Superset currently has implicit assumptions that timestamps are in UTC and thus configuring (3) to a non-UTC timezone could be problematic.
|
||||
|
||||
To strive for data consistency (regardless of the timezone of the client) the Apache Superset backend tries to ensure that any timestamp sent to the client has an explicit (or semi-explicit as in the case with [Epoch time](https://en.wikipedia.org/wiki/Unix_time) which is always in reference to UTC) timezone encoded within.
|
||||
|
||||
The challenge however lies with the slew of [database engines](/docs/databases#installing-drivers-in-docker) which Apache Superset supports and various inconsistencies between their [Python Database API (DB-API)](https://www.python.org/dev/peps/pep-0249/) implementations combined with the fact that we use [Pandas](https://pandas.pydata.org/) to read SQL into a DataFrame prior to serializing to JSON. Regrettably Pandas ignores the DB-API [type_code](https://www.python.org/dev/peps/pep-0249/#type-objects) relying by default on the underlying Python type returned by the DB-API. Currently only a subset of the supported database engines work correctly with Pandas, i.e., ensuring timestamps without an explicit timestamp are serializd to JSON with the server timezone, thus guaranteeing the client will display timestamps in a consistent manner irrespective of the client's timezone.
|
||||
|
||||
For example the following is a comparison of MySQL and Presto,
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
pd.read_sql_query(
|
||||
sql="SELECT TIMESTAMP('2022-01-01 00:00:00') AS ts",
|
||||
con=create_engine("mysql://root@localhost:3360"),
|
||||
).to_json()
|
||||
|
||||
pd.read_sql_query(
|
||||
sql="SELECT TIMESTAMP '2022-01-01 00:00:00' AS ts",
|
||||
con=create_engine("presto://localhost:8080"),
|
||||
).to_json()
|
||||
```
|
||||
|
||||
which outputs `{"ts":{"0":1640995200000}}` (which infers the UTC timezone per the Epoch time definition) and `{"ts":{"0":"2022-01-01 00:00:00.000"}}` (without an explicit timezone) respectively and thus are treated differently in JavaScript:
|
||||
|
||||
```js
|
||||
new Date(1640995200000)
|
||||
> Sat Jan 01 2022 13:00:00 GMT+1300 (New Zealand Daylight Time)
|
||||
|
||||
new Date("2022-01-01 00:00:00.000")
|
||||
> Sat Jan 01 2022 00:00:00 GMT+1300 (New Zealand Daylight Time)
|
||||
```
|
||||
@@ -1,142 +0,0 @@
|
||||
---
|
||||
title: Contributing to Superset
|
||||
sidebar_position: 1
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Contributing to Superset
|
||||
|
||||
Superset is an [Apache Software foundation](https://www.apache.org/theapacheway/index.html) project.
|
||||
The core contributors (or committers) to Superset communicate primarily in the following channels (
|
||||
which can be joined by anyone):
|
||||
|
||||
- [Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org)
|
||||
- [Apache Superset Slack community](http://bit.ly/join-superset-slack)
|
||||
- [GitHub issues](https://github.com/apache/superset/issues)
|
||||
- [GitHub pull requests](https://github.com/apache/superset/pulls)
|
||||
- [GitHub discussions](https://github.com/apache/superset/discussions)
|
||||
- [Superset Community Calendar](https://superset.apache.org/community)
|
||||
|
||||
More references:
|
||||
|
||||
- [Superset Wiki (code guidelines and additional resources)](https://github.com/apache/superset/wiki)
|
||||
|
||||
## Orientation
|
||||
|
||||
Here's a list of repositories that contain Superset-related packages:
|
||||
|
||||
- [apache/superset](https://github.com/apache/superset)
|
||||
is the main repository containing the `apache_superset` Python package
|
||||
distributed on
|
||||
[pypi](https://pypi.org/project/apache_superset/). This repository
|
||||
also includes Superset's main TypeScript/JavaScript bundles and react apps under
|
||||
the [superset-frontend](https://github.com/apache/superset/tree/master/superset-frontend)
|
||||
folder.
|
||||
- [github.com/apache-superset](https://github.com/apache-superset) is the
|
||||
GitHub organization under which we manage Superset-related
|
||||
small tools, forks and Superset-related experimental ideas.
|
||||
|
||||
## Types of Contributions
|
||||
|
||||
### Report Bug
|
||||
|
||||
The best way to report a bug is to file an issue on GitHub. Please include:
|
||||
|
||||
- Your operating system name and version.
|
||||
- Superset version.
|
||||
- Detailed steps to reproduce the bug.
|
||||
- Any details about your local setup that might be helpful in troubleshooting.
|
||||
|
||||
When posting Python stack traces, please quote them using
|
||||
[Markdown blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/).
|
||||
|
||||
_Please note that feature requests opened as GitHub Issues will be moved to Discussions._
|
||||
|
||||
### Submit Ideas or Feature Requests
|
||||
|
||||
The best way is to start an ["Ideas" Discussion thread](https://github.com/apache/superset/discussions/categories/ideas) on GitHub:
|
||||
|
||||
- Explain in detail how it would work.
|
||||
- Keep the scope as narrow as possible, to make it easier to implement.
|
||||
- Remember that this is a volunteer-driven project, and that your contributions are as welcome as anyone's :)
|
||||
|
||||
To propose large features or major changes to codebase, and help usher in those changes, please create a **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602)
|
||||
|
||||
### Fix Bugs
|
||||
|
||||
Look through the GitHub issues. Issues tagged with `#bug` are
|
||||
open to whoever wants to implement them.
|
||||
|
||||
### Implement Features
|
||||
|
||||
Look through the GitHub issues. Issues tagged with
|
||||
`#feature` are open to whoever wants to implement them.
|
||||
|
||||
### Improve Documentation
|
||||
|
||||
Superset could always use better documentation,
|
||||
whether as part of the official Superset docs,
|
||||
in docstrings, `docs/*.rst` or even on the web as blog posts or
|
||||
articles. See [Documentation](/docs/contributing/howtos#contributing-to-documentation) for more details.
|
||||
|
||||
### Add Translations
|
||||
|
||||
If you are proficient in a non-English language, you can help translate
|
||||
text strings from Superset's UI. You can jump into the existing
|
||||
language dictionaries at
|
||||
`superset/translations/<language_code>/LC_MESSAGES/messages.po`, or
|
||||
even create a dictionary for a new language altogether.
|
||||
See [Translating](howtos#contributing-translations) for more details.
|
||||
|
||||
### Ask Questions
|
||||
|
||||
There is a dedicated [`apache-superset` tag](https://stackoverflow.com/questions/tagged/apache-superset) on [StackOverflow](https://stackoverflow.com/). Please use it when asking questions.
|
||||
|
||||
## Types of Contributors
|
||||
|
||||
Following the project governance model of the Apache Software Foundation (ASF), Apache Superset has a specific set of contributor roles:
|
||||
|
||||
### PMC Member
|
||||
|
||||
A Project Management Committee (PMC) member is a person who has been elected by the PMC to help manage the project. PMC members are responsible for the overall health of the project, including community development, release management, and project governance. PMC members are also responsible for the technical direction of the project.
|
||||
|
||||
For more information about Apache Project PMCs, please refer to https://www.apache.org/foundation/governance/pmcs.html
|
||||
|
||||
### Committer
|
||||
|
||||
A committer is a person who has been elected by the PMC to have write access (commit access) to the code repository. They can modify the code, documentation, and website and accept contributions from others.
|
||||
|
||||
The official list of committers and PMC members can be found [here](https://projects.apache.org/committee.html?superset).
|
||||
|
||||
### Contributor
|
||||
|
||||
A contributor is a person who has contributed to the project in any way, including but not limited to code, tests, documentation, issues, and discussions.
|
||||
|
||||
> You can also review the Superset project's guidelines for PMC member promotion here: https://github.com/apache/superset/wiki/Guidelines-for-promoting-Superset-Committers-to-the-Superset-PMC
|
||||
|
||||
### Security Team
|
||||
|
||||
The security team is a selected subset of PMC members, committers and non-committers who are responsible for handling security issues.
|
||||
|
||||
New members of the security team are selected by the PMC members in a vote. You can request to be added to the team by sending a message to private@superset.apache.org. However, the team should be small and focused on solving security issues, so the requests will be evaluated on a case-by-case basis and the team size will be kept relatively small, limited to only actively security-focused contributors.
|
||||
|
||||
This security team must follow the [ASF vulnerability handling process](https://apache.org/security/committers.html#asf-project-security-for-committers).
|
||||
|
||||
Each new security issue is tracked as a JIRA ticket on the [ASF's JIRA Superset security project](https://issues.apache.org/jira/secure/RapidBoard.jspa?rapidView=588&projectKey=SUPERSETSEC)
|
||||
|
||||
Security team members must:
|
||||
|
||||
- Have an [ICLA](https://www.apache.org/licenses/contributor-agreements.html) signed with Apache Software Foundation.
|
||||
- Not reveal information about pending and unfixed security issues to anyone (including their employers) unless specifically authorised by the security team members, e.g., if the security team agrees that diagnosing and solving an issue requires the involvement of external experts.
|
||||
|
||||
A release manager, the contributor overseeing the release of a specific version of Apache Superset, is by default a member of the security team. However, they are not expected to be active in assessing, discussing, and fixing security issues.
|
||||
|
||||
Security team members should also follow these general expectations:
|
||||
|
||||
- Actively participate in assessing, discussing, fixing, and releasing security issues in Superset.
|
||||
- Avoid discussing security fixes in public forums. Pull request (PR) descriptions should not contain any information about security issues. The corresponding JIRA ticket should contain a link to the PR.
|
||||
- Security team members who contribute to a fix may be listed as remediation developers in the CVE report, along with their job affiliation (if they choose to include it).
|
||||
|
||||
:::resources
|
||||
- [Blog: Comprehensive Tutorial for Contributing Code to Apache Superset](https://preset.io/blog/tutorial-contributing-code-to-apache-superset/)
|
||||
:::
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,254 +0,0 @@
|
||||
---
|
||||
title: Guidelines
|
||||
sidebar_position: 2
|
||||
version: 1
|
||||
---
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
A philosophy we would like to strongly encourage is
|
||||
|
||||
> Before creating a PR, create an issue.
|
||||
|
||||
The purpose is to separate problem from possible solutions.
|
||||
|
||||
**Bug fixes:** If you’re only fixing a small bug, it’s fine to submit a pull request right away but we highly recommend filing an issue detailing what you’re fixing. This is helpful in case we don’t accept that specific fix but want to keep track of the issue. Please keep in mind that the project maintainers reserve the rights to accept or reject incoming PRs, so it is better to separate the issue and the code to fix it from each other. In some cases, project maintainers may request you to create a separate issue from PR before proceeding.
|
||||
|
||||
**Refactor:** For small refactors, it can be a standalone PR itself detailing what you are refactoring and why. If there are concerns, project maintainers may request you to create a `#SIP` for the PR before proceeding.
|
||||
|
||||
**Feature/Large changes:** If you intend to change the public API, or make any non-trivial changes to the implementation, we require you to file a new issue as `#SIP` (Superset Improvement Proposal). This lets us reach an agreement on your proposal before you put significant effort into it. You are welcome to submit a PR along with the SIP (sometimes necessary for demonstration), but we will not review/merge the code until the SIP is approved.
|
||||
|
||||
In general, small PRs are always easier to review than large PRs. The best practice is to break your work into smaller independent PRs and refer to the same issue. This will greatly reduce turnaround time.
|
||||
|
||||
If you wish to share your work which is not ready to merge yet, create a [Draft PR](https://github.blog/2019-02-14-introducing-draft-pull-requests/). This will enable maintainers and the CI runner to prioritize mature PR's.
|
||||
|
||||
Finally, never submit a PR that will put master branch in broken state. If the PR is part of multiple PRs to complete a large feature and cannot work on its own, you can create a feature branch and merge all related PRs into the feature branch before creating a PR from feature branch to master.
|
||||
|
||||
### Protocol
|
||||
|
||||
#### Authoring
|
||||
|
||||
- Fill in all sections of the PR template.
|
||||
- Title the PR with one of the following semantic prefixes (inspired by [Karma](http://karma-runner.github.io/0.10/dev/git-commit-msg.html])):
|
||||
|
||||
- `feat` (new feature)
|
||||
- `fix` (bug fix)
|
||||
- `docs` (changes to the documentation)
|
||||
- `style` (formatting, missing semi colons, etc; no application logic change)
|
||||
- `refactor` (refactoring code)
|
||||
- `test` (adding missing tests, refactoring tests; no application logic change)
|
||||
- `chore` (updating tasks etc; no application logic change)
|
||||
- `perf` (performance-related change)
|
||||
- `build` (build tooling, Docker configuration change)
|
||||
- `ci` (test runner, GitHub Actions workflow changes)
|
||||
- `other` (changes that don't correspond to the above -- should be rare!)
|
||||
- Examples:
|
||||
- `feat: export charts as ZIP files`
|
||||
- `perf(api): improve API info performance`
|
||||
- `fix(chart-api): cached-indicator always shows value is cached`
|
||||
|
||||
- Add prefix `[WIP]` to title if not ready for review (WIP = work-in-progress). We recommend creating a PR with `[WIP]` first and remove it once you have passed CI test and read through your code changes at least once.
|
||||
- If you believe your PR contributes a potentially breaking change, put a `!` after the semantic prefix but before the colon in the PR title, like so: `feat!: Added foo functionality to bar`
|
||||
- **Screenshots/GIFs:** Changes to user interface require before/after screenshots, or GIF for interactions
|
||||
- Recommended capture tools ([Kap](https://getkap.co/), [LICEcap](https://www.cockos.com/licecap/), [Skitch](https://download.cnet.com/Skitch/3000-13455_4-189876.html))
|
||||
- If no screenshot is provided, the committers will mark the PR with `need:screenshot` label and will not review until screenshot is provided.
|
||||
- **Dependencies:** Be careful about adding new dependency and avoid unnecessary dependencies.
|
||||
- For Python, include it in `pyproject.toml` denoting any specific restrictions and
|
||||
in `requirements.txt` pinned to a specific version which ensures that the application
|
||||
build is deterministic.
|
||||
- For TypeScript/JavaScript, include new libraries in `package.json`
|
||||
- **Tests:** The pull request should include tests, either as doctests, unit tests, or both. Make sure to resolve all errors and test failures. See [Testing](/docs/contributing/howtos#testing) for how to run tests.
|
||||
- **Documentation:** If the pull request adds functionality, the docs should be updated as part of the same PR.
|
||||
- **CI:** Reviewers will not review the code until all CI tests are passed. Sometimes there can be flaky tests. You can close and open PR to re-run CI test. Please report if the issue persists. After the CI fix has been deployed to `master`, please rebase your PR.
|
||||
- **Code coverage:** Please ensure that code coverage does not decrease.
|
||||
- Remove `[WIP]` when ready for review. Please note that it may be merged soon after approved so please make sure the PR is ready to merge and do not expect more time for post-approval edits.
|
||||
- If the PR was not ready for review and inactive for > 30 days, we will close it due to inactivity. The author is welcome to re-open and update.
|
||||
|
||||
#### Reviewing
|
||||
|
||||
- Use constructive tone when writing reviews.
|
||||
- If there are changes required, state clearly what needs to be done before the PR can be approved.
|
||||
- If you are asked to update your pull request with some changes there's no need to create a new one. Push your changes to the same branch.
|
||||
- The committers reserve the right to reject any PR and in some cases may request the author to file an issue.
|
||||
|
||||
#### Test Environments
|
||||
|
||||
- Members of the Apache GitHub org can launch an ephemeral test environment directly on a pull request by creating a comment containing (only) the command `/testenv up`.
|
||||
- Note that org membership must be public in order for this validation to function properly.
|
||||
- Feature flags may be set for a test environment by specifying the flag name (prefixed with `FEATURE_`) and value after the command.
|
||||
- Format: `/testenv up FEATURE_<feature flag name>=true|false`
|
||||
- Example: `/testenv up FEATURE_DASHBOARD_NATIVE_FILTERS=true`
|
||||
- Multiple feature flags may be set in single command, separated by whitespace
|
||||
- A comment will be created by the workflow script with the address and login information for the ephemeral environment.
|
||||
- Test environments may be created once the Docker build CI workflow for the PR has completed successfully.
|
||||
- Test environments do not currently update automatically when new commits are added to a pull request.
|
||||
- Test environments do not currently support async workers, though this is planned.
|
||||
- Running test environments will be shutdown upon closing the pull request.
|
||||
|
||||
#### Merging
|
||||
|
||||
- At least one approval is required for merging a PR.
|
||||
- PR is usually left open for at least 24 hours before merging.
|
||||
- After the PR is merged, [close the corresponding issue(s)](https://help.github.com/articles/closing-issues-using-keywords/).
|
||||
|
||||
#### Post-merge Responsibility
|
||||
|
||||
- Project maintainers may contact the PR author if new issues are introduced by the PR.
|
||||
- Project maintainers may revert your changes if a critical issue is found, such as breaking master branch CI.
|
||||
|
||||
## Managing Issues and PRs
|
||||
|
||||
To handle issues and PRs that are coming in, committers read issues/PRs and flag them with labels to categorize and help contributors spot where to take actions, as contributors usually have different expertises.
|
||||
|
||||
Triaging goals
|
||||
|
||||
- **For issues:** Categorize, screen issues, flag required actions from authors.
|
||||
- **For PRs:** Categorize, flag required actions from authors. If PR is ready for review, flag required actions from reviewers.
|
||||
|
||||
First, add **Category labels (a.k.a. hash labels)**. Every issue/PR must have one hash label (except spam entry). Labels that begin with `#` defines issue/PR type:
|
||||
|
||||
| Label | for Issue | for PR |
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `#bug` | Bug report | Bug fix |
|
||||
| `#code-quality` | Describe problem with code, architecture or productivity | Refactor, tests, tooling |
|
||||
| `#feature` | New feature request | New feature implementation |
|
||||
| `#refine` | Propose improvement such as adjusting padding or refining UI style, excluding new features, bug fixes, and refactoring. | Implementation of improvement such as adjusting padding or refining UI style, excluding new features, bug fixes, and refactoring. |
|
||||
| `#doc` | Documentation | Documentation |
|
||||
| `#question` | Troubleshooting: Installation, Running locally, Ask how to do something. Can be changed to `#bug` later. | N/A |
|
||||
| `#SIP` | Superset Improvement Proposal | N/A |
|
||||
| `#ASF` | Tasks related to Apache Software Foundation policy | Tasks related to Apache Software Foundation policy |
|
||||
|
||||
Then add other types of labels as appropriate.
|
||||
|
||||
- **Descriptive labels (a.k.a. dot labels):** These labels that begin with `.` describe the details of the issue/PR, such as `.ui`, `.js`, `.install`, `.backend`, etc. Each issue/PR can have zero or more dot labels.
|
||||
- **Need labels:** These labels have pattern `need:xxx`, which describe the work required to progress, such as `need:rebase`, `need:update`, `need:screenshot`.
|
||||
- **Risk labels:** These labels have pattern `risk:xxx`, which describe the potential risk on adopting the work, such as `risk:db-migration`. The intention was to better understand the impact and create awareness for PRs that need more rigorous testing.
|
||||
- **Status labels:** These labels describe the status (`abandoned`, `wontfix`, `cant-reproduce`, etc.) Issue/PRs that are rejected or closed without completion should have one or more status labels.
|
||||
- **Version labels:** These have the pattern `vx.x` such as `v0.28`. Version labels on issues describe the version the bug was reported on. Version labels on PR describe the first release that will include the PR.
|
||||
|
||||
Committers may also update title to reflect the issue/PR content if the author-provided title is not descriptive enough.
|
||||
|
||||
If the PR passes CI tests and does not have any `need:` labels, it is ready for review, add label `review` and/or `design-review`.
|
||||
|
||||
If an issue/PR has been inactive for at least 30 days, it will be closed. If it does not have any status label, add `inactive`.
|
||||
|
||||
When creating a PR, if you're aiming to have it included in a specific release, please tag it with the version label. For example, to have a PR considered for inclusion in Superset 1.1 use the label `v1.1`.
|
||||
|
||||
## Revert Guidelines
|
||||
|
||||
Reverting changes that are causing issues in the master branch is a normal and expected part of the development process. In an open source community, the ramifications of a change cannot always be fully understood. With that in mind, here are some considerations to keep in mind when considering a revert:
|
||||
|
||||
- **Availability of the PR author:** If the original PR author or the engineer who merged the code is highly available and can provide a fix in a reasonable time frame, this would counter-indicate reverting.
|
||||
- **Severity of the issue:** How severe is the problem on master? Is it keeping the project from moving forward? Is there user impact? What percentage of users will experience a problem?
|
||||
- **Size of the change being reverted:** Reverting a single small PR is a much lower-risk proposition than reverting a massive, multi-PR change.
|
||||
- **Age of the change being reverted:** Reverting a recently-merged PR will be more acceptable than reverting an older PR. A bug discovered in an older PR is unlikely to be causing widespread serious issues.
|
||||
- **Risk inherent in reverting:** Will the reversion break critical functionality? Is the medicine more dangerous than the disease?
|
||||
- **Difficulty of crafting a fix:** In the case of issues with a clear solution, it may be preferable to implement and merge a fix rather than a revert.
|
||||
|
||||
Should you decide that reverting is desirable, it is the responsibility of the Contributor performing the revert to:
|
||||
|
||||
- **Contact the interested parties:** The PR's author and the engineer who merged the work should both be contacted and informed of the revert.
|
||||
- **Provide concise reproduction steps:** Ensure that the issue can be clearly understood and duplicated by the original author of the PR.
|
||||
- **Put the revert through code review:** The revert must be approved by another committer.
|
||||
|
||||
## Design Guidelines
|
||||
|
||||
### Capitalization guidelines
|
||||
|
||||
#### Sentence case
|
||||
|
||||
Use sentence-case capitalization for everything in the UI (except these \*\*).
|
||||
|
||||
Sentence case is predominantly lowercase. Capitalize only the initial character of the first word, and other words that require capitalization, like:
|
||||
|
||||
- **Proper nouns.** Objects in the product _are not_ considered proper nouns e.g. dashboards, charts, saved queries etc. Proprietary feature names eg. SQL Lab, Preset Manager _are_ considered proper nouns
|
||||
- **Acronyms** (e.g. CSS, HTML)
|
||||
- When referring to **UI labels that are themselves capitalized** from sentence case (e.g. page titles - Dashboards page, Charts page, Saved queries page, etc.)
|
||||
- User input that is reflected in the UI. E.g. a user-named a dashboard tab
|
||||
|
||||
**Sentence case vs. Title case:**
|
||||
Title case: "A Dog Takes a Walk in Paris"
|
||||
Sentence case: "A dog takes a walk in Paris"
|
||||
|
||||
**Why sentence case?**
|
||||
|
||||
- It’s generally accepted as the quickest to read
|
||||
- It’s the easiest form to distinguish between common and proper nouns
|
||||
|
||||
#### How to refer to UI elements
|
||||
|
||||
When writing about a UI element, use the same capitalization as used in the UI.
|
||||
|
||||
For example, if an input field is labeled “Name” then you refer to this as the “Name input field”. Similarly, if a button has the label “Save” in it, then it is correct to refer to the “Save button”.
|
||||
|
||||
Where a product page is titled “Settings”, you refer to this in writing as follows:
|
||||
“Edit your personal information on the Settings page”.
|
||||
|
||||
Often a product page will have the same title as the objects it contains. In this case, refer to the page as it appears in the UI, and the objects as common nouns:
|
||||
|
||||
- Upload a dashboard on the Dashboards page
|
||||
- Go to Dashboards
|
||||
- View dashboard
|
||||
- View all dashboards
|
||||
- Upload CSS templates on the CSS templates page
|
||||
- Queries that you save will appear on the Saved queries page
|
||||
- Create custom queries in SQL Lab then create dashboards
|
||||
|
||||
#### \*\*Exceptions to sentence case
|
||||
|
||||
- Input labels, buttons and UI tabs are all caps
|
||||
- User input values (e.g. column names, SQL Lab tab names) should be in their original case
|
||||
|
||||
## Programming Language Conventions
|
||||
|
||||
### Python
|
||||
|
||||
Parameters in the `config.py` (which are accessible via the Flask app.config dictionary) are
|
||||
assumed to always be defined and thus should be accessed directly via,
|
||||
|
||||
```python
|
||||
blueprints = app.config["BLUEPRINTS"]
|
||||
```
|
||||
|
||||
rather than,
|
||||
|
||||
```python
|
||||
blueprints = app.config.get("BLUEPRINTS")
|
||||
```
|
||||
|
||||
or similar as the later will cause typing issues. The former is of type `List[Callable]`
|
||||
whereas the later is of type `Optional[List[Callable]]`.
|
||||
|
||||
#### Typing / Types Hints
|
||||
|
||||
To ensure clarity, consistency, all readability, _all_ new functions should use
|
||||
[type hints](https://docs.python.org/3/library/typing.html) and include a
|
||||
docstring.
|
||||
|
||||
Note per [PEP-484](https://www.python.org/dev/peps/pep-0484/#exceptions) no
|
||||
syntax for listing explicitly raised exceptions is proposed and thus the
|
||||
recommendation is to put this information in a docstring, i.e.,
|
||||
|
||||
```python
|
||||
import math
|
||||
from typing import Union
|
||||
|
||||
|
||||
def sqrt(x: Union[float, int]) -> Union[float, int]:
|
||||
"""
|
||||
Return the square root of x.
|
||||
|
||||
:param x: A number
|
||||
:returns: The square root of the given number
|
||||
:raises ValueError: If the number is negative
|
||||
"""
|
||||
|
||||
return math.sqrt(x)
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
TypeScript is fully supported and is the recommended language for writing all new frontend
|
||||
components. When modifying existing functions/components, migrating to TypeScript is
|
||||
appreciated, but not required. Examples of migrating functions/components to TypeScript can be
|
||||
found in [#9162](https://github.com/apache/superset/pull/9162) and [#9180](https://github.com/apache/superset/pull/9180).
|
||||
@@ -1,720 +0,0 @@
|
||||
---
|
||||
title: Development How-tos
|
||||
hide_title: true
|
||||
sidebar_position: 4
|
||||
version: 1
|
||||
---
|
||||
# Development How-tos
|
||||
|
||||
## Contributing to Documentation
|
||||
|
||||
The latest documentation and tutorial are available at https://superset.apache.org/.
|
||||
|
||||
The documentation site is built using [Docusaurus 3](https://docusaurus.io/), a modern
|
||||
static website generator, the source for which resides in `./docs`.
|
||||
|
||||
### Local Development
|
||||
|
||||
To set up a local development environment with hot reloading for the documentation site:
|
||||
|
||||
```shell
|
||||
cd docs
|
||||
yarn install # Installs NPM dependencies
|
||||
yarn start # Starts development server at http://localhost:3000
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
To create and serve a production build of the documentation site:
|
||||
|
||||
```shell
|
||||
yarn build
|
||||
yarn serve
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
Commits to `master` trigger a rebuild and redeploy of the documentation site. Submit pull requests that modify the documentation with the `docs:` prefix.
|
||||
|
||||
## Creating Visualization Plugins
|
||||
|
||||
Visualizations in Superset are implemented in JavaScript or TypeScript. Superset
|
||||
comes preinstalled with several visualizations types (hereafter "viz plugins") that
|
||||
can be found under the `superset-frontend/plugins` directory. Viz plugins are added to
|
||||
the application in the `superset-frontend/src/visualizations/presets/MainPreset.js`.
|
||||
The Superset project is always happy to review proposals for new high quality viz
|
||||
plugins. However, for highly custom viz types it is recommended to maintain a fork
|
||||
of Superset, and add the custom built viz plugins by hand.
|
||||
|
||||
**Note:** Additional community-generated resources about creating and deploying custom visualization plugins can be found on the [Superset Wiki](https://github.com/apache/superset/wiki/Community-Resource-Library#creating-custom-data-visualizations)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
In order to create a new viz plugin, you need the following:
|
||||
|
||||
- Run MacOS or Linux (Windows is not officially supported, but may work)
|
||||
- Node.js 16
|
||||
- npm 7 or 8
|
||||
|
||||
A general familiarity with [React](https://reactjs.org/) and the npm/Node system is
|
||||
also recommended.
|
||||
|
||||
### Creating a simple Hello World viz plugin
|
||||
|
||||
To get started, you need the Superset Yeoman Generator. It is recommended to use the
|
||||
version of the template that ships with the version of Superset you are using. This
|
||||
can be installed by doing the following:
|
||||
|
||||
```bash
|
||||
npm i -g yo
|
||||
cd superset-frontend/packages/generator-superset
|
||||
npm i
|
||||
npm link
|
||||
```
|
||||
|
||||
After this you can proceed to create your viz plugin. Create a new directory for your
|
||||
viz plugin with the prefix `superset-plugin-chart` and run the Yeoman generator:
|
||||
|
||||
```bash
|
||||
mkdir /tmp/superset-plugin-chart-hello-world
|
||||
cd /tmp/superset-plugin-chart-hello-world
|
||||
```
|
||||
|
||||
Initialize the viz plugin:
|
||||
|
||||
```bash
|
||||
yo @superset-ui/superset
|
||||
```
|
||||
|
||||
After that the generator will ask a few questions (the defaults should be fine):
|
||||
|
||||
```bash
|
||||
$ yo @superset-ui/superset
|
||||
_-----_ ╭──────────────────────────╮
|
||||
| | │ Welcome to the │
|
||||
|--(o)--| │ generator-superset │
|
||||
`---------´ │ generator! │
|
||||
( _´U`_ ) ╰──────────────────────────╯
|
||||
/___A___\ /
|
||||
| ~ |
|
||||
__'.___.'__
|
||||
´ ` |° ´ Y `
|
||||
? Package name: superset-plugin-chart-hello-world
|
||||
? Description: Hello World
|
||||
? What type of chart would you like? Time-series chart
|
||||
create package.json
|
||||
create .gitignore
|
||||
create babel.config.js
|
||||
create jest.config.js
|
||||
create README.md
|
||||
create tsconfig.json
|
||||
create src/index.ts
|
||||
create src/plugin/buildQuery.ts
|
||||
create src/plugin/controlPanel.ts
|
||||
create src/plugin/index.ts
|
||||
create src/plugin/transformProps.ts
|
||||
create src/types.ts
|
||||
create src/SupersetPluginChartHelloWorld.tsx
|
||||
create test/index.test.ts
|
||||
create test/__mocks__/mockExportString.js
|
||||
create test/plugin/buildQuery.test.ts
|
||||
create test/plugin/transformProps.test.ts
|
||||
create types/external.d.ts
|
||||
create src/images/thumbnail.png
|
||||
```
|
||||
|
||||
To build the viz plugin, run the following commands:
|
||||
|
||||
```bash
|
||||
npm i --force
|
||||
npm run build
|
||||
```
|
||||
|
||||
Alternatively, to run the viz plugin in development mode (=rebuilding whenever changes
|
||||
are made), start the dev server with the following command:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
To add the package to Superset, go to the `superset-frontend` subdirectory in your
|
||||
Superset source folder run
|
||||
|
||||
```bash
|
||||
npm i -S /tmp/superset-plugin-chart-hello-world
|
||||
```
|
||||
|
||||
If you publish your package to npm, you can naturally install directly from there, too.
|
||||
After this edit the `superset-frontend/src/visualizations/presets/MainPreset.js`
|
||||
and make the following changes:
|
||||
|
||||
```js
|
||||
import { SupersetPluginChartHelloWorld } from 'superset-plugin-chart-hello-world';
|
||||
```
|
||||
|
||||
to import the viz plugin and later add the following to the array that's passed to the
|
||||
`plugins` property:
|
||||
|
||||
```js
|
||||
new SupersetPluginChartHelloWorld().configure({ key: 'ext-hello-world' }),
|
||||
```
|
||||
|
||||
After that the viz plugin should show up when you run Superset, e.g. the development
|
||||
server:
|
||||
|
||||
```bash
|
||||
npm run dev-server
|
||||
```
|
||||
|
||||
#### Deploying your visualization plugin
|
||||
|
||||
Once your plugin is complete, you will need to deploy it to your superset instance.
|
||||
|
||||
This step assumes you are running your own Docker image as described [here](https://superset.apache.org/docs/installation/docker-builds/#building-your-own-production-docker-image).
|
||||
Instructions may vary for other kinds of deployments.
|
||||
|
||||
If you have your own Superset Docker image, the first line is most likely:
|
||||
`FROM apache/superset:latest` or something similar. You will need to compile
|
||||
your own `"lean"` image and replace this FROM line with your own image.
|
||||
|
||||
1. Publish your chart plugin to npm: it makes the build process simpler.
|
||||
|
||||
Note: if your chart is not published to npm, then in the docker build below, you will need
|
||||
to edit the default Dockerfile to copy your plugin source code to the appropriate
|
||||
location in the container build environment.
|
||||
|
||||
2. Install your chart in the frontend with `npm i <your_chart_package>`.
|
||||
3. Start with a base superset release.
|
||||
|
||||
```bash
|
||||
git checkout tags/X.0.0
|
||||
```
|
||||
|
||||
4. Install your chart with the instructions you followed during development.
|
||||
5. Navigate to the root of your superset directory.
|
||||
6. Run `docker build -t apache/superset:mychart --target lean .`
|
||||
7. Rebuild your production container using `FROM apache/superset:mychart`.
|
||||
|
||||
This will create a new productized superset container with your new chart compiled in.
|
||||
Then you can recreate your custom production container based on a superset built with your chart.
|
||||
|
||||
##### Troubleshooting
|
||||
|
||||
|
||||
- If you get the following NPM error:
|
||||
|
||||
```
|
||||
npm error `npm ci` can only install packages when your package.json and package-lock.json
|
||||
```
|
||||
|
||||
It's because your local nodejs/npm version is different than the one being used inside docker.
|
||||
|
||||
You can resolve this by running npm install with the same version used by the container build process
|
||||
|
||||
Replace XYZ in the following command with the node tag used in the Dockerfile (search for "node:" in the Dockerfile to find the tag).
|
||||
```bash
|
||||
docker run --rm -v $PWD/superset-frontend:/app node:XYZ /bin/bash -c "cd /app && npm i"
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Python Testing
|
||||
|
||||
`pytest`, backend by docker-compose is how we recommend running tests locally.
|
||||
|
||||
For a more complex test matrix (against different database backends, python versions, ...) you
|
||||
can rely on our GitHub Actions by simply opening a draft pull request.
|
||||
|
||||
Note that the test environment uses a temporary directory for defining the
|
||||
SQLite databases which will be cleared each time before the group of test
|
||||
commands are invoked.
|
||||
|
||||
There is also a utility script included in the Superset codebase to run python integration tests. The [readme can be
|
||||
found here](https://github.com/apache/superset/tree/master/scripts/tests)
|
||||
|
||||
To run all integration tests for example, run this script from the root directory:
|
||||
|
||||
```bash
|
||||
scripts/tests/run.sh
|
||||
```
|
||||
|
||||
You can run unit tests found in './tests/unit_tests' for example with pytest. It is a simple way to run an isolated test that doesn't need any database setup
|
||||
|
||||
```bash
|
||||
pytest ./link_to_test.py
|
||||
```
|
||||
|
||||
#### Testing with local Presto connections
|
||||
|
||||
If you happen to change db engine spec for Presto/Trino, you can run a local Presto cluster with Docker:
|
||||
|
||||
```bash
|
||||
docker run -p 15433:15433 starburstdata/presto:350-e.6
|
||||
```
|
||||
|
||||
Then update `SUPERSET__SQLALCHEMY_EXAMPLES_URI` to point to local Presto cluster:
|
||||
|
||||
```bash
|
||||
export SUPERSET__SQLALCHEMY_EXAMPLES_URI=presto://localhost:15433/memory/default
|
||||
```
|
||||
|
||||
### Frontend Testing
|
||||
|
||||
We use [Jest](https://jestjs.io/) and [Enzyme](https://airbnb.io/enzyme/) to test TypeScript/JavaScript. Tests can be run with:
|
||||
|
||||
```bash
|
||||
cd superset-frontend
|
||||
npm run test
|
||||
```
|
||||
|
||||
To run a single test file:
|
||||
|
||||
```bash
|
||||
npm run test -- path/to/file.js
|
||||
```
|
||||
|
||||
### E2E Integration Testing
|
||||
|
||||
**Note: We are migrating from Cypress to Playwright. Use Playwright for new tests.**
|
||||
|
||||
#### Playwright (Recommended - NEW)
|
||||
|
||||
For E2E testing with Playwright, use the same `docker compose` backend:
|
||||
|
||||
```bash
|
||||
CYPRESS_CONFIG=true docker compose up --build
|
||||
```
|
||||
|
||||
The backend setup is identical - this exposes a test-ready Superset app on port 8081 with isolated database schema (`superset_cypress`), test data, and configurations.
|
||||
|
||||
Now in another terminal, run Playwright tests:
|
||||
|
||||
```bash
|
||||
# Navigate to frontend directory (Playwright config is here)
|
||||
cd superset-frontend
|
||||
|
||||
# Run all Playwright tests
|
||||
npm run playwright:test
|
||||
# or: npx playwright test
|
||||
|
||||
# Run with interactive UI for debugging
|
||||
npm run playwright:ui
|
||||
# or: npx playwright test --ui
|
||||
|
||||
# Run in headed mode (see browser)
|
||||
npm run playwright:headed
|
||||
# or: npx playwright test --headed
|
||||
|
||||
# Run specific test file
|
||||
npx playwright test tests/auth/login.spec.ts
|
||||
|
||||
# Run with debug mode (step through tests)
|
||||
npm run playwright:debug tests/auth/login.spec.ts
|
||||
# or: npx playwright test --debug tests/auth/login.spec.ts
|
||||
|
||||
# Generate test report
|
||||
npx playwright show-report
|
||||
```
|
||||
|
||||
Configuration is in `superset-frontend/playwright.config.ts`. Base URL is automatically set to `http://localhost:8088` but will use `PLAYWRIGHT_BASE_URL` if provided.
|
||||
|
||||
#### Cypress (DEPRECATED - will be removed in Phase 5)
|
||||
|
||||
:::warning
|
||||
Cypress is being phased out in favor of Playwright. Use Playwright for all new tests.
|
||||
:::
|
||||
|
||||
```bash
|
||||
# Set base URL for Cypress
|
||||
CYPRESS_BASE_URL=http://localhost:8081
|
||||
```
|
||||
|
||||
```bash
|
||||
# superset-frontend/cypress-base is the base folder for everything Cypress-related
|
||||
# It's essentially its own npm app, with its own dependencies, configurations and utilities
|
||||
cd superset-frontend/cypress-base
|
||||
npm install
|
||||
|
||||
# use interactive mode to run tests, while keeping memory usage contained
|
||||
# this will fire up an interactive Cypress UI
|
||||
# as you alter the code, the tests will re-run automatically, and you can visualize each
|
||||
# and every step for debugging purposes
|
||||
npx cypress open --config numTestsKeptInMemory=5
|
||||
|
||||
# to run the test suite on the command line using chrome (same as CI)
|
||||
npm run cypress-run-chrome
|
||||
|
||||
# run tests from a specific file
|
||||
npm run cypress-run-chrome -- --spec cypress/e2e/explore/link.test.ts
|
||||
|
||||
# run specific file with video capture
|
||||
npm run cypress-run-chrome -- --spec cypress/e2e/dashboard/index.test.js --config video=true
|
||||
|
||||
# to open the cypress ui
|
||||
npm run cypress-debug
|
||||
|
||||
```
|
||||
|
||||
See [`superset-frontend/cypress_build.sh`](https://github.com/apache/superset/blob/master/superset-frontend/cypress_build.sh).
|
||||
|
||||
As an alternative you can use docker compose environment for testing:
|
||||
|
||||
Make sure you have added below line to your /etc/hosts file:
|
||||
`127.0.0.1 db`
|
||||
|
||||
If you already have launched Docker environment please use the following command to assure a fresh database instance:
|
||||
`docker compose down -v`
|
||||
|
||||
Launch environment:
|
||||
|
||||
`CYPRESS_CONFIG=true docker compose up`
|
||||
|
||||
It will serve backend and frontend on port 8088.
|
||||
|
||||
Run Cypress tests:
|
||||
|
||||
```bash
|
||||
cd cypress-base
|
||||
npm install
|
||||
npm run cypress open
|
||||
```
|
||||
|
||||
### Debugging Server App
|
||||
|
||||
Follow these instructions to debug the Flask app running inside a docker container.
|
||||
|
||||
First add the following to the ./docker-compose.yaml file
|
||||
|
||||
```diff
|
||||
superset:
|
||||
env_file: docker/.env
|
||||
image: *superset-image
|
||||
container_name: superset_app
|
||||
command: ["/app/docker/docker-bootstrap.sh", "app"]
|
||||
restart: unless-stopped
|
||||
+ cap_add:
|
||||
+ - SYS_PTRACE
|
||||
ports:
|
||||
- 8088:8088
|
||||
+ - 5678:5678
|
||||
user: "root"
|
||||
depends_on: *superset-depends-on
|
||||
volumes: *superset-volumes
|
||||
environment:
|
||||
CYPRESS_CONFIG: "${CYPRESS_CONFIG}"
|
||||
```
|
||||
|
||||
Start Superset as usual
|
||||
|
||||
```bash
|
||||
docker compose up
|
||||
```
|
||||
|
||||
Install the required libraries and packages to the docker container
|
||||
|
||||
Enter the superset_app container
|
||||
|
||||
```bash
|
||||
docker exec -it superset_app /bin/bash
|
||||
root@39ce8cf9d6ab:/app#
|
||||
```
|
||||
|
||||
Run the following commands inside the container
|
||||
|
||||
```bash
|
||||
apt update
|
||||
apt install -y gdb
|
||||
apt install -y net-tools
|
||||
pip install debugpy
|
||||
```
|
||||
|
||||
Find the PID for the Flask process. Make sure to use the first PID. The Flask app will re-spawn a sub-process every time you change any of the python code. So it's important to use the first PID.
|
||||
|
||||
```bash
|
||||
ps -ef
|
||||
|
||||
UID PID PPID C STIME TTY TIME CMD
|
||||
root 1 0 0 14:09 ? 00:00:00 bash /app/docker/docker-bootstrap.sh app
|
||||
root 6 1 4 14:09 ? 00:00:04 /usr/local/bin/python /usr/bin/flask run -p 8088 --with-threads --reload --debugger --host=0.0.0.0
|
||||
root 10 6 7 14:09 ? 00:00:07 /usr/local/bin/python /usr/bin/flask run -p 8088 --with-threads --reload --debugger --host=0.0.0.0
|
||||
```
|
||||
|
||||
Inject debugpy into the running Flask process. In this case PID 6.
|
||||
|
||||
```bash
|
||||
python3 -m debugpy --listen 0.0.0.0:5678 --pid 6
|
||||
```
|
||||
|
||||
Verify that debugpy is listening on port 5678
|
||||
|
||||
```bash
|
||||
netstat -tunap
|
||||
|
||||
Active Internet connections (servers and established)
|
||||
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
|
||||
tcp 0 0 0.0.0.0:5678 0.0.0.0:* LISTEN 462/python
|
||||
tcp 0 0 0.0.0.0:8088 0.0.0.0:* LISTEN 6/python
|
||||
```
|
||||
|
||||
You are now ready to attach a debugger to the process. Using VSCode you can configure a launch configuration file .vscode/launch.json like so.
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach to Superset App in Docker Container",
|
||||
"type": "python",
|
||||
"request": "attach",
|
||||
"connect": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 5678
|
||||
},
|
||||
"pathMappings": [
|
||||
{
|
||||
"localRoot": "${workspaceFolder}",
|
||||
"remoteRoot": "/app"
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
VSCode will not stop on breakpoints right away. We've attached to PID 6 however it does not yet know of any sub-processes. In order to "wakeup" the debugger you need to modify a python file. This will trigger Flask to reload the code and create a new sub-process. This new sub-process will be detected by VSCode and breakpoints will be activated.
|
||||
|
||||
### Debugging Server App in Kubernetes Environment
|
||||
|
||||
To debug Flask running in POD inside a kubernetes cluster, you'll need to make sure the pod runs as root and is granted the `SYS_TRACE` capability. These settings should not be used in production environments.
|
||||
|
||||
```yaml
|
||||
securityContext:
|
||||
capabilities:
|
||||
add: ["SYS_PTRACE"]
|
||||
```
|
||||
|
||||
See [set capabilities for a container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-capabilities-for-a-container) for more details.
|
||||
|
||||
Once the pod is running as root and has the `SYS_PTRACE` capability it will be able to debug the Flask app.
|
||||
|
||||
You can follow the same instructions as in `docker compose`. Enter the pod and install the required library and packages: gdb, netstat and debugpy.
|
||||
|
||||
Often in a Kubernetes environment nodes are not addressable from outside the cluster. VSCode will thus be unable to remotely connect to port 5678 on a Kubernetes node. In order to do this you need to create a tunnel that port forwards 5678 to your local machine.
|
||||
|
||||
```bash
|
||||
kubectl port-forward pod/superset-<some random id> 5678:5678
|
||||
```
|
||||
|
||||
You can now launch your VSCode debugger with the same config as above. VSCode will connect to to 127.0.0.1:5678 which is forwarded by kubectl to your remote kubernetes POD.
|
||||
|
||||
### Storybook
|
||||
|
||||
Superset includes a [Storybook](https://storybook.js.org/) to preview the layout/styling of various Superset components, and variations thereof. To open and view the Storybook:
|
||||
|
||||
```bash
|
||||
cd superset-frontend
|
||||
npm run storybook
|
||||
```
|
||||
|
||||
When contributing new React components to Superset, please try to add a Story alongside the component's `jsx/tsx` file.
|
||||
|
||||
## Contributing Translations
|
||||
|
||||
We use [Flask-Babel](https://python-babel.github.io/flask-babel/) to translate Superset.
|
||||
In Python files, we use the following
|
||||
[translation functions](https://python-babel.github.io/flask-babel/#using-translations)
|
||||
from `Flask-Babel`:
|
||||
|
||||
- `gettext` and `lazy_gettext` (usually aliased to `_`): for translating singular
|
||||
strings.
|
||||
- `ngettext`: for translating strings that might become plural.
|
||||
|
||||
```python
|
||||
from flask_babel import lazy_gettext as _
|
||||
```
|
||||
|
||||
then wrap the translatable strings with it, e.g. `_('Translate me')`.
|
||||
During extraction, string literals passed to `_` will be added to the
|
||||
generated `.po` file for each language for later translation.
|
||||
|
||||
At runtime, the `_` function will return the translation of the given
|
||||
string for the current language, or the given string itself
|
||||
if no translation is available.
|
||||
|
||||
In TypeScript/JavaScript, the technique is similar:
|
||||
we import `t` (simple translation), `tn` (translation containing a number).
|
||||
|
||||
```javascript
|
||||
import { t, tn } from "@superset-ui/translation";
|
||||
```
|
||||
|
||||
### Enabling language selection
|
||||
|
||||
Add the `LANGUAGES` variable to your `superset_config.py`. Having more than one
|
||||
option inside will add a language selection dropdown to the UI on the right side
|
||||
of the navigation bar.
|
||||
|
||||
```python
|
||||
LANGUAGES = {
|
||||
'en': {'flag': 'us', 'name': 'English'},
|
||||
'fr': {'flag': 'fr', 'name': 'French'},
|
||||
'zh': {'flag': 'cn', 'name': 'Chinese'},
|
||||
}
|
||||
```
|
||||
|
||||
### Creating a new language dictionary
|
||||
|
||||
First check if the language code for your target language already exists. Check if the
|
||||
[two letter ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
|
||||
for your target language already exists in the `superset/translations` directory:
|
||||
|
||||
```bash
|
||||
ls superset/translations | grep -E "^[a-z]{2}\/"
|
||||
```
|
||||
|
||||
If your language already has a preexisting translation, skip to the next section
|
||||
|
||||
The following languages are already supported by Flask AppBuilder, and will make it
|
||||
easier to translate the application to your target language:
|
||||
[Flask AppBuilder i18n documentation](https://flask-appbuilder.readthedocs.io/en/latest/i18n.html)
|
||||
|
||||
To create a dictionary for a new language, first make sure the necessary dependencies are installed:
|
||||
|
||||
```bash
|
||||
pip install -r superset/translations/requirements.txt
|
||||
```
|
||||
|
||||
Then run the following, where `LANGUAGE_CODE` is replaced with the language code for your target
|
||||
language:
|
||||
|
||||
```bash
|
||||
pybabel init -i superset/translations/messages.pot -d superset/translations -l LANGUAGE_CODE
|
||||
```
|
||||
|
||||
For instance, to add a translation for Finnish (language code `fi`), run the following:
|
||||
|
||||
```bash
|
||||
pybabel init -i superset/translations/messages.pot -d superset/translations -l fi
|
||||
```
|
||||
|
||||
### Extracting new strings for translation
|
||||
|
||||
Periodically, when working on translations, we need to extract the strings from both the
|
||||
backend and the frontend to compile a list of all strings to be translated. It doesn't
|
||||
happen automatically and is a required step to gather the strings and get them into the
|
||||
`.po` files where they can be translated, so that they can then be compiled.
|
||||
|
||||
This script does just that:
|
||||
|
||||
```bash
|
||||
./scripts/translations/babel_update.sh
|
||||
```
|
||||
|
||||
### Updating language files
|
||||
|
||||
Run the following command to update the language files with the new extracted strings.
|
||||
|
||||
```bash
|
||||
pybabel update -i superset/translations/messages.pot -d superset/translations --ignore-obsolete
|
||||
```
|
||||
|
||||
You can then translate the strings gathered in files located under
|
||||
`superset/translation`, where there's one folder per language. You can use [Poedit](https://poedit.net/features)
|
||||
to translate the `po` file more conveniently.
|
||||
Here is [a tutorial](https://web.archive.org/web/20220517065036/https://wiki.lxde.org/en/Translate_*.po_files_with_Poedit).
|
||||
|
||||
To perform the translation on MacOS, you can install `poedit` via Homebrew:
|
||||
|
||||
```bash
|
||||
brew install poedit
|
||||
```
|
||||
|
||||
After this, just start the `poedit` application and open the `messages.po` file. In the
|
||||
case of the Finnish translation, this would be `superset/translations/fi/LC_MESSAGES/messages.po`.
|
||||
|
||||
### Applying translations
|
||||
|
||||
To make the translations available on the frontend, we need to convert the PO file into
|
||||
a collection of JSON files. To convert all PO files to formatted JSON files you can use
|
||||
the `build-translation` script
|
||||
|
||||
```bash
|
||||
# Install dependencies if you haven't already
|
||||
cd superset-frontend/ && npm ci
|
||||
# Compile translations for the frontend
|
||||
npm run build-translation
|
||||
```
|
||||
|
||||
Finally, for the translations to take effect we need to compile translation catalogs into
|
||||
binary MO files for the backend using `pybabel`.
|
||||
|
||||
```bash
|
||||
# inside the project root
|
||||
pybabel compile -d superset/translations
|
||||
```
|
||||
|
||||
## Linting
|
||||
|
||||
### Python
|
||||
|
||||
We use [ruff](https://github.com/astral-sh/ruff) for linting which can be invoked via:
|
||||
|
||||
```
|
||||
# auto-reformat using ruff
|
||||
ruff format
|
||||
|
||||
# lint check with ruff
|
||||
ruff check
|
||||
|
||||
# lint fix with ruff
|
||||
ruff check --fix
|
||||
```
|
||||
|
||||
Ruff configuration is located in our
|
||||
(pyproject.toml)[https://github.com/apache/superset/blob/master/pyproject.toml] file
|
||||
|
||||
All this is configured to run in pre-commit hooks, which we encourage you to setup
|
||||
with `pre-commit install`
|
||||
|
||||
### TypeScript
|
||||
|
||||
```bash
|
||||
cd superset-frontend
|
||||
npm ci
|
||||
# run linting checks
|
||||
npm run lint
|
||||
# run tsc (typescript) checks
|
||||
npm run type
|
||||
```
|
||||
|
||||
If using the eslint extension with vscode, put the following in your workspace `settings.json` file:
|
||||
|
||||
```json
|
||||
"eslint.workingDirectories": [
|
||||
"superset-frontend"
|
||||
]
|
||||
```
|
||||
|
||||
## GitHub Ephemeral Environments
|
||||
|
||||
On any given pull request on GitHub, it's possible to create a temporary environment/deployment
|
||||
by simply adding the label `testenv-up` to the PR. Once you add the `testenv-up` label, a
|
||||
GitHub Action will be triggered that will:
|
||||
|
||||
- build a docker image
|
||||
- deploy it in EC2 (sponsored by the folks at [Preset](https://preset.io))
|
||||
- write a comment on the PR with a link to the ephemeral environment
|
||||
|
||||
For more advanced use cases, it's possible to set a feature flag on the PR body, which will
|
||||
take effect on the ephemeral environment. For example, if you want to set the `TAGGING_SYSTEM`
|
||||
feature flag to `true`, you can add the following line to the PR body/description:
|
||||
|
||||
```
|
||||
FEATURE_TAGGING_SYSTEM=true
|
||||
```
|
||||
|
||||
Similarly, it's possible to disable feature flags with:
|
||||
|
||||
```
|
||||
FEATURE_TAGGING_SYSTEM=false
|
||||
```
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Miscellaneous
|
||||
|
||||
## Reporting a Security Vulnerability
|
||||
|
||||
Please report security vulnerabilities to private@superset.apache.org.
|
||||
|
||||
In the event a community member discovers a security flaw in Superset, it is important to follow the [Apache Security Guidelines](https://www.apache.org/security/committers.html) and release a fix as quickly as possible before public disclosure. Reporting security vulnerabilities through the usual GitHub Issues channel is not ideal as it will publicize the flaw before a fix can be applied.
|
||||
|
||||
## SQL Lab Async
|
||||
|
||||
It's possible to configure a local database to operate in `async` mode,
|
||||
to work on `async` related features.
|
||||
|
||||
To do this, you'll need to:
|
||||
|
||||
- Add an additional database entry. We recommend you copy the connection
|
||||
string from the database labeled `main`, and then enable `SQL Lab` and the
|
||||
features you want to use. Don't forget to check the `Async` box
|
||||
- Configure a results backend, here's a local `FileSystemCache` example,
|
||||
not recommended for production,
|
||||
but perfect for testing (stores cache in `/tmp`)
|
||||
|
||||
```python
|
||||
from flask_caching.backends.filesystemcache import FileSystemCache
|
||||
RESULTS_BACKEND = FileSystemCache('/tmp/sqllab')
|
||||
```
|
||||
|
||||
- Start up a celery worker
|
||||
|
||||
```shell script
|
||||
celery --app=superset.tasks.celery_app:app worker -O fair
|
||||
```
|
||||
|
||||
Note that:
|
||||
|
||||
- for changes that affect the worker logic, you'll have to
|
||||
restart the `celery worker` process for the changes to be reflected.
|
||||
- The message queue used is a `sqlite` database using the `SQLAlchemy`
|
||||
experimental broker. Ok for testing, but not recommended in production
|
||||
- In some cases, you may want to create a context that is more aligned
|
||||
to your production environment, and use the similar broker as well as
|
||||
results backend configuration
|
||||
|
||||
## Async Chart Queries
|
||||
|
||||
It's possible to configure database queries for charts to operate in `async` mode. This is especially useful for dashboards with many charts that may otherwise be affected by browser connection limits. To enable async queries for dashboards and Explore, the following dependencies are required:
|
||||
|
||||
- Redis 5.0+ (the feature utilizes [Redis Streams](https://redis.io/topics/streams-intro))
|
||||
- Cache backends enabled via the `CACHE_CONFIG` and `DATA_CACHE_CONFIG` config settings
|
||||
- Celery workers configured and running to process async tasks
|
||||
@@ -1,101 +0,0 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
# pkg_resources Deprecation and Migration Guide
|
||||
|
||||
## Background
|
||||
|
||||
As of setuptools 81.0.0 (scheduled for removal around 2025-11-30), the `pkg_resources` API is deprecated and will be removed. This affects several packages in the Python ecosystem.
|
||||
|
||||
## Current Status
|
||||
|
||||
### Superset Codebase ✅
|
||||
The Superset codebase has already migrated away from `pkg_resources` to the modern `importlib.metadata` API:
|
||||
|
||||
- `superset/db_engine_specs/__init__.py:36` - Uses `from importlib.metadata import entry_points`
|
||||
- All entry point loading uses the modern API
|
||||
|
||||
### Production Dependencies ⚠️
|
||||
Some third-party dependencies may still use `pkg_resources`:
|
||||
|
||||
- **`clients` package** (Preset-specific): Uses `pkg_resources` in `const.py`
|
||||
- Error path: `/usr/local/lib/python3.10/site-packages/clients/const.py:1`
|
||||
|
||||
## Migration Path
|
||||
|
||||
### Short-term Solution (Current)
|
||||
Pin setuptools to version 80.x to prevent breaking changes:
|
||||
|
||||
```python
|
||||
# requirements/base.in
|
||||
setuptools<81
|
||||
```
|
||||
|
||||
This prevents the removal of `pkg_resources` while dependent packages are updated.
|
||||
|
||||
### Long-term Solution
|
||||
Update all dependencies to use `importlib.metadata` instead of `pkg_resources`:
|
||||
|
||||
#### Migration Example
|
||||
**Old (deprecated):**
|
||||
```python
|
||||
import pkg_resources
|
||||
|
||||
version = pkg_resources.get_distribution("package_name").version
|
||||
entry_points = pkg_resources.iter_entry_points("group_name")
|
||||
```
|
||||
|
||||
**New (recommended):**
|
||||
```python
|
||||
from importlib.metadata import version, entry_points
|
||||
|
||||
pkg_version = version("package_name")
|
||||
eps = entry_points(group="group_name")
|
||||
```
|
||||
|
||||
## Action Items
|
||||
|
||||
### For Preset Team
|
||||
1. **Update `clients` package** to use `importlib.metadata` instead of `pkg_resources`
|
||||
2. **Review other internal packages** for `pkg_resources` usage
|
||||
3. **Test with setuptools >= 81.0.0** once all packages are migrated
|
||||
4. **Monitor Datadog logs** for similar deprecation warnings
|
||||
|
||||
### For Superset Maintainers
|
||||
1. ✅ Already using `importlib.metadata`
|
||||
2. Monitor third-party dependencies for updates
|
||||
3. Update setuptools pin once ecosystem is ready
|
||||
|
||||
## Timeline
|
||||
|
||||
- **2025-11-30**: Expected removal of `pkg_resources` from setuptools
|
||||
- **Before then**: All dependencies must migrate to `importlib.metadata`
|
||||
|
||||
## References
|
||||
|
||||
- [setuptools pkg_resources deprecation notice](https://setuptools.pypa.io/en/latest/pkg_resources.html)
|
||||
- [importlib.metadata documentation](https://docs.python.org/3/library/importlib.metadata.html)
|
||||
- [Migration guide](https://setuptools.pypa.io/en/latest/deprecated/pkg_resources.html)
|
||||
|
||||
## Monitoring
|
||||
|
||||
Track this issue in production using Datadog:
|
||||
- Warning pattern: `pkg_resources is deprecated as an API`
|
||||
- Component: `@component:app`
|
||||
- Environment: `environment:production`
|
||||
@@ -1,104 +0,0 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
version: 1
|
||||
---
|
||||
|
||||
import InteractiveSVG from '../../src/components/InteractiveERDSVG';
|
||||
import Mermaid from '@theme/Mermaid';
|
||||
|
||||
# Resources
|
||||
|
||||
## High Level Architecture
|
||||
<div style={{ maxWidth: "600px", margin: "0 auto", marginLeft: 0, marginRight: "auto" }}>
|
||||
```mermaid
|
||||
flowchart TD
|
||||
|
||||
%% Top Level
|
||||
LB["<b>Load Balancer(s)</b><br/>(optional)"]
|
||||
LB -.-> WebServers
|
||||
|
||||
%% Web Servers
|
||||
subgraph WebServers ["<b>Web Server(s)</b>"]
|
||||
WS1["<b>Frontend</b><br/>(React, AntD, ECharts, AGGrid)"]
|
||||
WS2["<b>Backend</b><br/>(Python, Flask, SQLAlchemy, Pandas, ...)"]
|
||||
end
|
||||
|
||||
%% Infra
|
||||
subgraph InfraServices ["<b>Infra</b>"]
|
||||
DB[("<b>Metadata Database</b><br/>(Postgres / MySQL)")]
|
||||
|
||||
subgraph Caching ["<b>Caching Subservices<br/></b>(Redis, memcache, S3, ...)"]
|
||||
direction LR
|
||||
DummySpace[" "]:::invisible
|
||||
QueryCache["<b>Query Results Cache</b><br/>(Accelerated Dashboards)"]
|
||||
CsvCache["<b>CSV Exports Cache</b>"]
|
||||
ThumbnailCache["<b>Thumbnails Cache</b>"]
|
||||
AlertImageCache["<b>Alert/Report Images Cache</b>"]
|
||||
QueryCache -- " " --> CsvCache
|
||||
linkStyle 1 stroke:transparent;
|
||||
ThumbnailCache -- " " --> AlertImageCache
|
||||
linkStyle 2 stroke:transparent;
|
||||
end
|
||||
|
||||
Broker(("<b>Message Queue</b><br/>(Redis / RabbitMQ / SQS)"))
|
||||
end
|
||||
|
||||
AsyncBackend["<b>Async Workers (Celery)</b><br>required for Alerts & Reports, thumbnails, CSV exports, long-running workloads, ..."]
|
||||
|
||||
%% External DBs
|
||||
subgraph ExternalDatabases ["<b>Analytics Databases</b>"]
|
||||
direction LR
|
||||
BigQuery[(BigQuery)]
|
||||
Snowflake[(Snowflake)]
|
||||
Redshift[(Redshift)]
|
||||
Postgres[(Postgres)]
|
||||
Postgres[(... any ...)]
|
||||
end
|
||||
|
||||
%% Connections
|
||||
LB -.-> WebServers
|
||||
WebServers --> DB
|
||||
WebServers -.-> Caching
|
||||
WebServers -.-> Broker
|
||||
WebServers -.-> ExternalDatabases
|
||||
|
||||
Broker -.-> AsyncBackend
|
||||
|
||||
AsyncBackend -.-> ExternalDatabases
|
||||
AsyncBackend -.-> Caching
|
||||
|
||||
|
||||
|
||||
%% Legend styling
|
||||
classDef requiredNode stroke-width:2px,stroke:black;
|
||||
class Required requiredNode;
|
||||
class Optional optionalNode;
|
||||
|
||||
%% Hide real arrow
|
||||
linkStyle 0 stroke:transparent;
|
||||
|
||||
%% Styling
|
||||
classDef optionalNode stroke-dasharray: 5 5, opacity:0.9;
|
||||
class LB optionalNode;
|
||||
class Caching optionalNode;
|
||||
class AsyncBackend optionalNode;
|
||||
class Broker optionalNode;
|
||||
class QueryCache optionalNode;
|
||||
class CsvCache optionalNode;
|
||||
class ThumbnailCache optionalNode;
|
||||
class AlertImageCache optionalNode;
|
||||
class Celery optionalNode;
|
||||
|
||||
classDef invisible fill:transparent,stroke:transparent;
|
||||
```
|
||||
</div>
|
||||
|
||||
## Entity-Relationship Diagram
|
||||
|
||||
Here is our interactive ERD:
|
||||
|
||||
<InteractiveSVG />
|
||||
|
||||
<br />
|
||||
|
||||
[Download the .svg](https://github.com/apache/superset/tree/master/docs/static/img/erd.svg)
|
||||
@@ -107,11 +107,11 @@ multiple tables as long as your database account has access to the tables.
|
||||
## How do I create my own visualization?
|
||||
|
||||
We recommend reading the instructions in
|
||||
[Creating Visualization Plugins](/docs/contributing/howtos#creating-visualization-plugins).
|
||||
[Creating Visualization Plugins](/developer-docs/contributing/howtos#creating-visualization-plugins).
|
||||
|
||||
## Can I upload and visualize CSV data?
|
||||
|
||||
Absolutely! Read the instructions [here](/docs/using-superset/exploring-data) to learn
|
||||
Absolutely! Read the instructions [here](/user-docs/using-superset/exploring-data) to learn
|
||||
how to enable and use CSV upload.
|
||||
|
||||
## Why are my queries timing out?
|
||||
@@ -198,7 +198,7 @@ SQLALCHEMY_DATABASE_URI = 'sqlite:////new/location/superset.db?check_same_thread
|
||||
```
|
||||
|
||||
You can read more about customizing Superset using the configuration file
|
||||
[here](/docs/configuration/configuring-superset).
|
||||
[here](/admin-docs/configuration/configuring-superset).
|
||||
|
||||
## What if the table schema changed?
|
||||
|
||||
@@ -213,7 +213,7 @@ table afterwards to configure the Columns tab, check the appropriate boxes and s
|
||||
|
||||
To clarify, the database backend is an OLTP database used by Superset to store its internal
|
||||
information like your list of users and dashboard definitions. While Superset supports a
|
||||
[variety of databases as data _sources_](/docs/databases#installing-database-drivers),
|
||||
[variety of databases as data _sources_](/user-docs/databases/#installing-database-drivers),
|
||||
only a few database engines are supported for use as the OLTP backend / metadata store.
|
||||
|
||||
Superset is tested using MySQL, PostgreSQL, and SQLite backends. It’s recommended you install
|
||||
@@ -246,7 +246,7 @@ second etc). Example:
|
||||
|
||||
## Does Superset work with [insert database engine here]?
|
||||
|
||||
The [Connecting to Databases section](/docs/databases) provides the best
|
||||
The [Connecting to Databases section](/user-docs/databases/) provides the best
|
||||
overview for supported databases. Database engines not listed on that page may work too. We rely on
|
||||
the community to contribute to this knowledge base.
|
||||
|
||||
@@ -282,7 +282,7 @@ are typical in basic SQL:
|
||||
## Does Superset offer a public API?
|
||||
|
||||
Yes, a public REST API, and the surface of that API formal is expanding steadily. You can read more about this API and
|
||||
interact with it using Swagger [here](/docs/api).
|
||||
interact with it using Swagger [here](/developer-docs/api).
|
||||
|
||||
Some of the
|
||||
original vision for the collection of endpoints under **/api/v1** was originally specified in
|
||||
@@ -322,7 +322,7 @@ Superset uses [Scarf](https://about.scarf.sh/) by default to collect basic telem
|
||||
We use the [Scarf Gateway](https://docs.scarf.sh/gateway/) to sit in front of container registries, the [scarf-js](https://about.scarf.sh/package-sdks) package to track `npm` installations, and a Scarf pixel to gather anonymous analytics on Superset page views.
|
||||
Scarf purges PII and provides aggregated statistics. Superset users can easily opt out of analytics in various ways documented [here](https://docs.scarf.sh/gateway/#do-not-track) and [here](https://docs.scarf.sh/package-analytics/#as-a-user-of-a-package-using-scarf-js-how-can-i-opt-out-of-analytics).
|
||||
Superset maintainers can also opt out of telemetry data collection by setting the `SCARF_ANALYTICS` environment variable to `false` in the Superset container (or anywhere Superset/webpack are run).
|
||||
Additional opt-out instructions for Docker users are available on the [Docker Installation](/docs/installation/docker-compose) page.
|
||||
Additional opt-out instructions for Docker users are available on the [Docker Installation](/admin-docs/installation/docker-compose) page.
|
||||
|
||||
## Does Superset have an archive panel or trash bin from which a user can recover deleted assets?
|
||||
|
||||
|
||||
269
docs/docs/index.mdx
Normal file
269
docs/docs/index.mdx
Normal file
@@ -0,0 +1,269 @@
|
||||
---
|
||||
hide_title: true
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
import DatabaseLogoWall from '@site/src/components/databases/DatabaseLogoWall';
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
# Superset
|
||||
|
||||
[](https://opensource.org/license/apache-2-0)
|
||||
[](https://github.com/apache/superset/releases/latest)
|
||||
[](https://github.com/apache/superset/actions)
|
||||
[](https://badge.fury.io/py/apache_superset)
|
||||
[](https://pypi.python.org/pypi/apache_superset)
|
||||
[](https://github.com/apache/superset/stargazers)
|
||||
[](https://github.com/apache/superset/graphs/contributors)
|
||||
[](https://github.com/apache/superset/commits/master)
|
||||
[](https://github.com/apache/superset/issues)
|
||||
[](https://github.com/apache/superset/pulls)
|
||||
[](http://bit.ly/join-superset-slack)
|
||||
[](https://superset.apache.org)
|
||||
|
||||
<picture width="500">
|
||||
<source
|
||||
width="600"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
src="https://superset.apache.org/img/superset-logo-horiz-dark.svg"
|
||||
alt="Superset logo (dark)"
|
||||
/>
|
||||
<img
|
||||
width="600"
|
||||
src="https://superset.apache.org/img/superset-logo-horiz-apache.svg"
|
||||
alt="Superset logo (light)"
|
||||
/>
|
||||
</picture>
|
||||
|
||||
A modern, enterprise-ready business intelligence web application.
|
||||
|
||||
[**Why Superset?**](#why-superset) |
|
||||
[**Supported Databases**](#supported-databases) |
|
||||
[**Installation and Configuration**](#installation-and-configuration) |
|
||||
[**Release Notes**](https://github.com/apache/superset/blob/master/RELEASING/README.md#release-notes-for-recent-releases) |
|
||||
[**Get Involved**](#get-involved) |
|
||||
[**Contributor Guide**](#contributor-guide) |
|
||||
[**Resources**](#resources) |
|
||||
[**Organizations Using Superset**](https://superset.apache.org/inTheWild)
|
||||
|
||||
## Why Superset?
|
||||
|
||||
Superset is a modern data exploration and data visualization platform. Superset can replace or augment proprietary business intelligence tools for many teams. Superset integrates well with a variety of data sources.
|
||||
|
||||
Superset provides:
|
||||
|
||||
- A **no-code interface** for building charts quickly
|
||||
- A powerful, web-based **SQL Editor** for advanced querying
|
||||
- A **lightweight semantic layer** for quickly defining custom dimensions and metrics
|
||||
- Out of the box support for **nearly any SQL** database or data engine
|
||||
- A wide array of **beautiful visualizations** to showcase your data, ranging from simple bar charts to geospatial visualizations
|
||||
- Lightweight, configurable **caching layer** to help ease database load
|
||||
- Highly extensible **security roles and authentication** options
|
||||
- An **API** for programmatic customization
|
||||
- A **cloud-native architecture** designed from the ground up for scale
|
||||
|
||||
## Screenshots & Gifs
|
||||
|
||||
**Video Overview**
|
||||
|
||||
<!-- File hosted here https://github.com/apache/superset-site/raw/lfs/superset-video-4k.mp4 -->
|
||||
|
||||
[superset-video-1080p.webm](https://github.com/user-attachments/assets/b37388f7-a971-409c-96a7-90c4e31322e6)
|
||||
|
||||
<br/>
|
||||
|
||||
**Large Gallery of Visualizations**
|
||||
|
||||
<kbd><img title="Gallery" src="https://superset.apache.org/img/screenshots/gallery.jpg"/></kbd><br/>
|
||||
|
||||
**Craft Beautiful, Dynamic Dashboards**
|
||||
|
||||
<kbd><img title="View Dashboards" src="https://superset.apache.org/img/screenshots/dashboard.jpg"/></kbd><br/>
|
||||
|
||||
**No-Code Chart Builder**
|
||||
|
||||
<kbd><img title="Slice & dice your data" src="https://superset.apache.org/img/screenshots/explore.jpg"/></kbd><br/>
|
||||
|
||||
**Powerful SQL Editor**
|
||||
|
||||
<kbd><img title="SQL Lab" src="https://superset.apache.org/img/screenshots/sql_lab.jpg"/></kbd><br/>
|
||||
|
||||
## Supported Databases
|
||||
|
||||
Superset can query data from any SQL-speaking datastore or data engine (Presto, Trino, Athena, [and more](/user-docs/databases/)) that has a Python DB-API driver and a SQLAlchemy dialect.
|
||||
|
||||
Here are some of the major database solutions that are supported:
|
||||
|
||||
<DatabaseLogoWall />
|
||||
|
||||
<!--
|
||||
SUPPORTED_DATABASES block removed — logos are now rendered dynamically
|
||||
by the DatabaseLogoWall component above, using databases.json as the
|
||||
single source of truth. The README.md retains its own static copy
|
||||
(maintained by generate-database-docs.mjs --update-readme).
|
||||
-->
|
||||
|
||||
<!--
|
||||
<p align="center">
|
||||
<a href="/user-docs/databases/supported/amazon-athena" title="Amazon Athena"><img src="/img/databases/amazon-athena.jpg" alt="Amazon Athena" width="76" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/amazon-dynamodb" title="Amazon DynamoDB"><img src="/img/databases/aws.png" alt="Amazon DynamoDB" width="40" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/amazon-redshift" title="Amazon Redshift"><img src="/img/databases/redshift.png" alt="Amazon Redshift" width="100" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-doris" title="Apache Doris"><img src="/img/databases/doris.png" alt="Apache Doris" width="103" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-drill" title="Apache Drill"><img src="/img/databases/apache-drill.png" alt="Apache Drill" width="81" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-druid" title="Apache Druid"><img src="/img/databases/druid.png" alt="Apache Druid" width="117" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-hive" title="Apache Hive"><img src="/img/databases/apache-hive.svg" alt="Apache Hive" width="44" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-impala" title="Apache Impala"><img src="/img/databases/apache-impala.png" alt="Apache Impala" width="21" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-kylin" title="Apache Kylin"><img src="/img/databases/apache-kylin.png" alt="Apache Kylin" width="44" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-pinot" title="Apache Pinot"><img src="/img/databases/apache-pinot.svg" alt="Apache Pinot" width="76" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-solr" title="Apache Solr"><img src="/img/databases/apache-solr.png" alt="Apache Solr" width="79" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/apache-spark-sql" title="Apache Spark SQL"><img src="/img/databases/apache-spark.png" alt="Apache Spark SQL" width="75" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/ascend" title="Ascend"><img src="/img/databases/ascend.webp" alt="Ascend" width="117" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/aurora-mysql-data-api" title="Aurora MySQL (Data API)"><img src="/img/databases/mysql.png" alt="Aurora MySQL (Data API)" width="77" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/aurora-postgresql-data-api" title="Aurora PostgreSQL (Data API)"><img src="/img/databases/postgresql.svg" alt="Aurora PostgreSQL (Data API)" width="76" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/azure-data-explorer" title="Azure Data Explorer"><img src="/img/databases/kusto.png" alt="Azure Data Explorer" width="40" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/azure-synapse" title="Azure Synapse"><img src="/img/databases/azure.svg" alt="Azure Synapse" width="40" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/clickhouse" title="ClickHouse"><img src="/img/databases/clickhouse.png" alt="ClickHouse" width="150" height="37" /></a>
|
||||
<a href="/user-docs/databases/supported/cloudflare-d1" title="Cloudflare D1"><img src="/img/databases/cloudflare.png" alt="Cloudflare D1" width="40" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/cockroachdb" title="CockroachDB"><img src="/img/databases/cockroachdb.png" alt="CockroachDB" width="150" height="24" /></a>
|
||||
<a href="/user-docs/databases/supported/couchbase" title="Couchbase"><img src="/img/databases/couchbase.svg" alt="Couchbase" width="150" height="35" /></a>
|
||||
<a href="/user-docs/databases/supported/cratedb" title="CrateDB"><img src="/img/databases/cratedb.svg" alt="CrateDB" width="180" height="24" /></a>
|
||||
<a href="/user-docs/databases/supported/databend" title="Databend"><img src="/img/databases/databend.png" alt="Databend" width="100" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/databricks" title="Databricks"><img src="/img/databases/databricks.png" alt="Databricks" width="152" height="24" /></a>
|
||||
<a href="/user-docs/databases/supported/denodo" title="Denodo"><img src="/img/databases/denodo.png" alt="Denodo" width="138" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/dremio" title="Dremio"><img src="/img/databases/dremio.png" alt="Dremio" width="126" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/duckdb" title="DuckDB"><img src="/img/databases/duckdb.png" alt="DuckDB" width="52" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/elasticsearch" title="Elasticsearch"><img src="/img/databases/elasticsearch.png" alt="Elasticsearch" width="40" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/exasol" title="Exasol"><img src="/img/databases/exasol.png" alt="Exasol" width="72" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/firebird" title="Firebird"><img src="/img/databases/firebird.png" alt="Firebird" width="100" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/firebolt" title="Firebolt"><img src="/img/databases/firebolt.png" alt="Firebolt" width="100" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/google-bigquery" title="Google BigQuery"><img src="/img/databases/google-big-query.svg" alt="Google BigQuery" width="76" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/google-sheets" title="Google Sheets"><img src="/img/databases/google-sheets.svg" alt="Google Sheets" width="76" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/greenplum" title="Greenplum"><img src="/img/databases/greenplum.png" alt="Greenplum" width="124" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/hologres" title="Hologres"><img src="/img/databases/hologres.png" alt="Hologres" width="44" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/ibm-db2" title="IBM Db2"><img src="/img/databases/ibm-db2.svg" alt="IBM Db2" width="91" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/ibm-netezza-performance-server" title="IBM Netezza Performance Server"><img src="/img/databases/netezza.png" alt="IBM Netezza Performance Server" width="40" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/mariadb" title="MariaDB"><img src="/img/databases/mariadb.png" alt="MariaDB" width="150" height="37" /></a>
|
||||
<a href="/user-docs/databases/supported/microsoft-sql-server" title="Microsoft SQL Server"><img src="/img/databases/msql.png" alt="Microsoft SQL Server" width="50" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/monetdb" title="MonetDB"><img src="/img/databases/monet-db.png" alt="MonetDB" width="100" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/mongodb" title="MongoDB"><img src="/img/databases/mongodb.png" alt="MongoDB" width="150" height="38" /></a>
|
||||
<a href="/user-docs/databases/supported/motherduck" title="MotherDuck"><img src="/img/databases/motherduck.png" alt="MotherDuck" width="40" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/oceanbase" title="OceanBase"><img src="/img/databases/oceanbase.svg" alt="OceanBase" width="175" height="24" /></a>
|
||||
<a href="/user-docs/databases/supported/oracle" title="Oracle"><img src="/img/databases/oraclelogo.png" alt="Oracle" width="111" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/presto" title="Presto"><img src="/img/databases/presto-og.png" alt="Presto" width="127" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/risingwave" title="RisingWave"><img src="/img/databases/risingwave.svg" alt="RisingWave" width="147" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/sap-hana" title="SAP HANA"><img src="/img/databases/sap-hana.png" alt="SAP HANA" width="137" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/sap-sybase" title="SAP Sybase"><img src="/img/databases/sybase.png" alt="SAP Sybase" width="100" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/shillelagh" title="Shillelagh"><img src="/img/databases/shillelagh.png" alt="Shillelagh" width="40" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/singlestore" title="SingleStore"><img src="/img/databases/singlestore.png" alt="SingleStore" width="150" height="31" /></a>
|
||||
<a href="/user-docs/databases/supported/snowflake" title="Snowflake"><img src="/img/databases/snowflake.svg" alt="Snowflake" width="76" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/sqlite" title="SQLite"><img src="/img/databases/sqlite.png" alt="SQLite" width="84" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/starrocks" title="StarRocks"><img src="/img/databases/starrocks.png" alt="StarRocks" width="149" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/superset-meta-database" title="Superset meta database"><img src="/img/databases/superset.svg" alt="Superset meta database" width="150" height="39" /></a>
|
||||
<a href="/user-docs/databases/supported/tdengine" title="TDengine"><img src="/img/databases/tdengine.png" alt="TDengine" width="140" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/teradata" title="Teradata"><img src="/img/databases/teradata.png" alt="Teradata" width="124" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/timescaledb" title="TimescaleDB"><img src="/img/databases/timescale.png" alt="TimescaleDB" width="150" height="36" /></a>
|
||||
<a href="/user-docs/databases/supported/trino" title="Trino"><img src="/img/databases/trino.png" alt="Trino" width="89" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/vertica" title="Vertica"><img src="/img/databases/vertica.png" alt="Vertica" width="128" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/ydb" title="YDB"><img src="/img/databases/ydb.svg" alt="YDB" width="110" height="40" /></a>
|
||||
<a href="/user-docs/databases/supported/yugabytedb" title="YugabyteDB"><img src="/img/databases/yugabyte.png" alt="YugabyteDB" width="150" height="26" /></a>
|
||||
</p>
|
||||
SUPPORTED_DATABASES_END -->
|
||||
|
||||
**A more comprehensive list of supported databases** along with the configuration instructions can be found [here](/user-docs/databases/).
|
||||
|
||||
Want to add support for your datastore or data engine? Read more [here](/user-docs/faq#does-superset-work-with-insert-database-engine-here) about the technical requirements.
|
||||
|
||||
## Installation and Configuration
|
||||
|
||||
Try out Superset's [quickstart](/user-docs/quickstart) guide or learn about [the options for production deployments](/admin-docs/installation/installation-methods).
|
||||
|
||||
## Get Involved
|
||||
|
||||
- Ask and answer questions on [StackOverflow](https://stackoverflow.com/questions/tagged/apache-superset) using the **apache-superset** tag
|
||||
- [Join our community's Slack](http://bit.ly/join-superset-slack)
|
||||
and please read our [Slack Community Guidelines](https://github.com/apache/superset/blob/master/CODE_OF_CONDUCT.md#slack-community-guidelines)
|
||||
- [Join our dev@superset.apache.org Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org). To join, simply send an email to [dev-subscribe@superset.apache.org](mailto:dev-subscribe@superset.apache.org)
|
||||
- If you want to help troubleshoot GitHub Issues involving the numerous database drivers that Superset supports, please consider adding your name and the databases you have access to on the [Superset Database Familiarity Rolodex](https://docs.google.com/spreadsheets/d/1U1qxiLvOX0kBTUGME1AHHi6Ywel6ECF8xk_Qy-V9R8c/edit#gid=0)
|
||||
- Join Superset's Town Hall and [Operational Model](https://preset.io/blog/the-superset-operational-model-wants-you/) recurring meetings. Meeting info is available on the [Superset Community Calendar](https://superset.apache.org/community)
|
||||
|
||||
## Contributor Guide
|
||||
|
||||
Interested in contributing? Check out our
|
||||
[Developer Docs](https://superset.apache.org/developer-docs/)
|
||||
to find resources around contributing along with a detailed guide on
|
||||
how to set up a development environment.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Superset "In the Wild"](https://superset.apache.org/inTheWild) - see who's using Superset, and [add your organization](https://github.com/apache/superset/edit/master/RESOURCES/INTHEWILD.yaml) to the list!
|
||||
- [Feature Flags](/admin-docs/configuration/feature-flags) - the status of Superset's Feature Flags.
|
||||
- [Standard Roles](https://github.com/apache/superset/blob/master/RESOURCES/STANDARD_ROLES.md) - How RBAC permissions map to roles.
|
||||
- [Superset Wiki](https://github.com/apache/superset/wiki) - Tons of additional community resources: best practices, community content and other information.
|
||||
- [Superset SIPs](https://github.com/orgs/apache/projects/170) - The status of Superset's SIPs (Superset Improvement Proposals) for both consensus and implementation status.
|
||||
|
||||
Understanding the Superset Points of View
|
||||
|
||||
- [The Case for Dataset-Centric Visualization](https://preset.io/blog/dataset-centric-visualization/)
|
||||
- [Understanding the Superset Semantic Layer](https://preset.io/blog/understanding-superset-semantic-layer/)
|
||||
|
||||
- Getting Started with Superset
|
||||
- [Superset in 2 Minutes using Docker Compose](/admin-docs/installation/docker-compose#installing-superset-locally-using-docker-compose)
|
||||
- [Installing Database Drivers](/admin-docs/configuration/configuring-superset#installing-database-drivers)
|
||||
- [Building New Database Connectors](https://preset.io/blog/building-database-connector/)
|
||||
- [Create Your First Dashboard](/user-docs/using-superset/creating-your-first-dashboard)
|
||||
- [Comprehensive Tutorial for Contributing Code to Apache Superset
|
||||
](https://preset.io/blog/tutorial-contributing-code-to-apache-superset/)
|
||||
- [Resources to master Superset by Preset](https://preset.io/resources/)
|
||||
|
||||
- Deploying Superset
|
||||
|
||||
- [Official Docker image](https://hub.docker.com/r/apache/superset)
|
||||
- [Helm Chart](https://github.com/apache/superset/tree/master/helm/superset)
|
||||
|
||||
- Recordings of Past [Superset Community Events](https://preset.io/events)
|
||||
|
||||
- [Mixed Time Series Charts](https://preset.io/events/mixed-time-series-visualization-in-superset-workshop/)
|
||||
- [How the Bing Team Customized Superset for the Internal Self-Serve Data & Analytics Platform](https://preset.io/events/how-the-bing-team-heavily-customized-superset-for-their-internal-data/)
|
||||
- [Live Demo: Visualizing MongoDB and Pinot Data using Trino](https://preset.io/events/2021-04-13-visualizing-mongodb-and-pinot-data-using-trino/)
|
||||
- [Introduction to the Superset API](https://preset.io/events/introduction-to-the-superset-api/)
|
||||
- [Building a Database Connector for Superset](https://preset.io/events/2021-02-16-building-a-database-connector-for-superset/)
|
||||
|
||||
- Visualizations
|
||||
|
||||
- [Creating Viz Plugins](https://superset.apache.org/developer-docs/contributing/howtos#creating-visualization-plugins)
|
||||
- [Managing and Deploying Custom Viz Plugins](https://medium.com/nmc-techblog/apache-superset-manage-custom-viz-plugins-in-production-9fde1a708e55)
|
||||
- [Why Apache Superset is Betting on Apache ECharts](https://preset.io/blog/2021-4-1-why-echarts/)
|
||||
|
||||
- [Superset API](/developer-docs/api)
|
||||
|
||||
## Repo Activity
|
||||
|
||||
<a href="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats?repo_id=39464018" target="_blank" align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=39464018&image_size=auto&color_scheme=dark" width="655" height="auto" />
|
||||
<img alt="Performance Stats of apache/superset - Last 28 days" src="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=39464018&image_size=auto&color_scheme=light" width="655" height="auto" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
|
||||
|
||||
<!-- telemetry/analytics pixel: -->
|
||||
<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=bc1c90cd-bc04-4e11-8c7b-289fb2839492" />
|
||||
@@ -1,72 +0,0 @@
|
||||
---
|
||||
title: Architecture
|
||||
hide_title: true
|
||||
sidebar_position: 1
|
||||
version: 1
|
||||
---
|
||||
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
|
||||
# Architecture
|
||||
|
||||
This page is meant to give new administrators an understanding of Superset's components.
|
||||
|
||||
## Components
|
||||
|
||||
A Superset installation is made up of these components:
|
||||
|
||||
1. The Superset application itself
|
||||
2. A metadata database
|
||||
3. A caching layer (optional, but necessary for some features)
|
||||
4. A worker & beat (optional, but necessary for some features)
|
||||
|
||||
### Optional components and associated features
|
||||
|
||||
The optional components above are necessary to enable these features:
|
||||
|
||||
- [Alerts and Reports](/docs/configuration/alerts-reports)
|
||||
- [Caching](/docs/configuration/cache)
|
||||
- [Async Queries](/docs/configuration/async-queries-celery/)
|
||||
- [Dashboard Thumbnails](/docs/configuration/cache/#caching-thumbnails)
|
||||
|
||||
If you install with Kubernetes or Docker Compose, all of these components will be created.
|
||||
|
||||
However, installing from PyPI only creates the application itself. Users installing from PyPI will need to configure a caching layer, worker, and beat on their own if they wish to enable the above features. Configuration of those components for a PyPI install is not currently covered in this documentation.
|
||||
|
||||
Here are further details on each component.
|
||||
|
||||
### The Superset Application
|
||||
|
||||
This is the core application. Superset operates like this:
|
||||
|
||||
- A user visits a chart or dashboard
|
||||
- That triggers a SQL query to the data warehouse holding the underlying dataset
|
||||
- The resulting data is served up in a data visualization
|
||||
- The Superset application is comprised of the Python (Flask) backend application (server), API layer, and the React frontend, built via Webpack, and static assets needed for the application to work
|
||||
|
||||
### Metadata Database
|
||||
|
||||
This is where chart and dashboard definitions, user information, logs, etc. are stored. Superset is tested to work with PostgreSQL and MySQL databases as the metadata database (not be confused with a data source like your data warehouse, which could be a much greater variety of options like Snowflake, Redshift, etc.).
|
||||
|
||||
Some installation methods like our Quickstart and PyPI come configured by default to use a SQLite on-disk database. And in a Docker Compose installation, the data would be stored in a PostgreSQL container volume. Neither of these cases are recommended for production instances of Superset.
|
||||
|
||||
For production, a properly-configured, managed, standalone database is recommended. No matter what database you use, you should plan to back it up regularly.
|
||||
|
||||
### Caching Layer
|
||||
|
||||
The caching layer serves two main functions:
|
||||
|
||||
- Store the results of queries to your data warehouse so that when a chart is loaded twice, it pulls from the cache the second time, speeding up the application and reducing load on your data warehouse.
|
||||
- Act as a message broker for the worker, enabling the Alerts & Reports, async queries, and thumbnail caching features.
|
||||
|
||||
Most people use Redis for their cache, but Superset supports other options too. See the [cache docs](/docs/configuration/cache/) for more.
|
||||
|
||||
### Worker and Beat
|
||||
|
||||
This is one or more workers who execute tasks like run async queries or take snapshots of reports and send emails, and a "beat" that acts as the scheduler and tells workers when to perform their tasks. Most installations use Celery for these components.
|
||||
|
||||
## Other components
|
||||
|
||||
Other components can be incorporated into Superset. The best place to learn about additional configurations is the [Configuration page](/docs/configuration/configuring-superset). For instance, you could set up a load balancer or reverse proxy to implement HTTPS in front of your Superset application, or specify a Mapbox URL to enable geospatial charts, etc.
|
||||
|
||||
Superset won't even start without certain configuration settings established, so it's essential to review that page.
|
||||
@@ -1,173 +0,0 @@
|
||||
---
|
||||
title: Docker Builds
|
||||
hide_title: true
|
||||
sidebar_position: 7
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Docker builds, images and tags
|
||||
|
||||
The Apache Superset community extensively uses Docker for development, release,
|
||||
and productionizing Superset. This page details our Docker builds and tag naming
|
||||
schemes to help users navigate our offerings.
|
||||
|
||||
Images are built and pushed to the [Superset Docker Hub repository](
|
||||
https://hub.docker.com/r/apache/superset) using GitHub Actions.
|
||||
Different sets of images are built and/or published at different times:
|
||||
|
||||
- **Published releases** (`release`): published using
|
||||
tags like `5.0.0` and the `latest` tag.
|
||||
- **Pull request iterations** (`pull_request`): for each pull request, while
|
||||
we actively build the docker to validate the build, we do
|
||||
not publish those images for security reasons, we simply `docker build --load`
|
||||
- **Merges to the main branch** (`push`): resulting in new SHAs, with tags
|
||||
prefixed with `master` for the latest `master` version.
|
||||
|
||||
## Build presets
|
||||
|
||||
We have a set of build "presets" that each represent a combination of
|
||||
parameters for the build, mostly pointing to either different target layer
|
||||
for the build, and/or base image.
|
||||
|
||||
Here are the build presets that are exposed through the `supersetbot docker` utility:
|
||||
|
||||
- `lean`: The default Docker image, including both frontend and backend. Tags
|
||||
without a build_preset are lean builds (ie: `latest`, `5.0.0`, `4.1.2`, ...). `lean`
|
||||
builds do not contain database
|
||||
drivers, meaning you need to install your own. That applies to analytics databases **AND
|
||||
the metadata database**. You'll likely want to layer either `mysqlclient` or `psycopg2-binary`
|
||||
depending on the metadata database you choose for your installation, plus the required
|
||||
drivers to connect to your analytics database(s).
|
||||
- `dev`: For development, with a headless browser, dev-related utilities and root access. This
|
||||
includes some commonly used database drivers like `mysqlclient`, `psycopg2-binary` and
|
||||
some other used for development/CI
|
||||
- `py311`, e.g., Py311: Similar to lean but with a different Python version (in this example, 3.11).
|
||||
- `ci`: For certain CI workloads.
|
||||
- `websocket`: For Superset clusters supporting advanced features.
|
||||
- `dockerize`: Used by Helm in initContainers to wait for database dependencies to be available.
|
||||
|
||||
## Key tags examples
|
||||
|
||||
- `latest`: The latest official release build
|
||||
- `latest-dev`: the `-dev` image of the latest official release build, with a
|
||||
headless browser and root access.
|
||||
- `master`: The latest build from the `master` branch, implicitly the lean build
|
||||
preset
|
||||
- `master-dev`: Similar to `master` but includes a headless browser and root access.
|
||||
- `pr-5252`: The latest commit in PR 5252.
|
||||
- `30948dc401b40982cb7c0dbf6ebbe443b2748c1b-dev`: A build for
|
||||
this specific SHA, which could be from a `master` merge, or release.
|
||||
- `websocket-latest`: The WebSocket image for use in a Superset cluster.
|
||||
|
||||
For insights or modifications to the build matrix and tagging conventions,
|
||||
check the [supersetbot docker](https://github.com/apache-superset/supersetbot)
|
||||
subcommand and the [docker.yml](https://github.com/apache/superset/blob/master/.github/workflows/docker.yml)
|
||||
GitHub action.
|
||||
|
||||
## Building your own production Docker image
|
||||
|
||||
Every Superset deployment will require its own set of drivers depending on the data warehouse(s),
|
||||
etc. so we recommend that users build their own Docker image by extending the `lean` image.
|
||||
|
||||
Here's an example Dockerfile that does this. Follow the in-line comments to customize it for
|
||||
your desired Superset version and database drivers. The comments also note that a certain feature flag will
|
||||
have to be enabled in your config file.
|
||||
|
||||
You would build the image with `docker build -t mysuperset:latest .` or `docker build -t ourcompanysuperset:5.0.0 .`
|
||||
|
||||
```Dockerfile
|
||||
# change this to apache/superset:5.0.0 or whatever version you want to build from;
|
||||
# otherwise the default is the latest commit on GitHub master branch
|
||||
FROM apache/superset:master
|
||||
|
||||
USER root
|
||||
|
||||
# Set environment variable for Playwright
|
||||
ENV PLAYWRIGHT_BROWSERS_PATH=/usr/local/share/playwright-browsers
|
||||
|
||||
# Install packages using uv into the virtual environment
|
||||
RUN . /app/.venv/bin/activate && \
|
||||
uv pip install \
|
||||
# install psycopg2 for using PostgreSQL metadata store - could be a MySQL package if using that backend:
|
||||
psycopg2-binary \
|
||||
# add the driver(s) for your data warehouse(s), in this example we're showing for Microsoft SQL Server:
|
||||
pymssql \
|
||||
# package needed for using single-sign on authentication:
|
||||
Authlib \
|
||||
# openpyxl to be able to upload Excel files
|
||||
openpyxl \
|
||||
# Pillow for Alerts & Reports to generate PDFs of dashboards
|
||||
Pillow \
|
||||
# install Playwright for taking screenshots for Alerts & Reports. This assumes the feature flag PLAYWRIGHT_REPORTS_AND_THUMBNAILS is enabled
|
||||
# That feature flag will default to True starting in 6.0.0
|
||||
# Playwright works only with Chrome.
|
||||
# If you are still using Selenium instead of Playwright, you would instead install here the selenium package and a headless browser & webdriver
|
||||
playwright \
|
||||
&& playwright install-deps \
|
||||
&& PLAYWRIGHT_BROWSERS_PATH=/usr/local/share/playwright-browsers playwright install chromium
|
||||
|
||||
# Switch back to the superset user
|
||||
USER superset
|
||||
|
||||
CMD ["/app/docker/entrypoints/run-server.sh"]
|
||||
```
|
||||
|
||||
## Key ARGs in Dockerfile
|
||||
|
||||
- `BUILD_TRANSLATIONS`: whether to build the translations into the image. For the
|
||||
frontend build this tells webpack to strip out all locales other than `en` from
|
||||
the `moment-timezone` library. For the backendthis skips compiling the
|
||||
`*.po` translation files
|
||||
- `DEV_MODE`: whether to skip the frontend build, this is used by our `docker-compose` dev setup
|
||||
where we mount the local volume and build using `webpack` in `--watch` mode, meaning as you
|
||||
alter the code in the local file system, webpack, from within a docker image used for this
|
||||
purpose, will constantly rebuild the frontend as you go. This ARG enables the initial
|
||||
`docker-compose` build to take much less time and resources
|
||||
- `INCLUDE_CHROMIUM`: whether to include chromium in the backend build so that it can be
|
||||
used as a headless browser for workloads related to "Alerts & Reports" and thumbnail generation
|
||||
- `INCLUDE_FIREFOX`: same as above, but for firefox
|
||||
- `PY_VER`: specifying the base image for the python backend, we don't recommend altering
|
||||
this setting if you're not working on forwards or backwards compatibility
|
||||
|
||||
## Caching
|
||||
|
||||
To accelerate builds, we follow Docker best practices and use `apache/superset-cache`.
|
||||
|
||||
## About database drivers
|
||||
|
||||
Our docker images come with little to zero database driver support since
|
||||
each environment requires different drivers, and maintaining a build with
|
||||
wide database support would be both challenging (dozens of databases,
|
||||
python drivers, and os dependencies) and inefficient (longer
|
||||
build times, larger images, lower layer cache hit rate, ...).
|
||||
|
||||
For production use cases, we recommend that you derive our `lean` image(s) and
|
||||
add database support for the database you need.
|
||||
|
||||
## On supporting different platforms (namely arm64 AND amd64)
|
||||
|
||||
Currently all automated builds are multi-platform, supporting both `linux/arm64`
|
||||
and `linux/amd64`. This enables higher level constructs like `helm` and
|
||||
`docker compose` to point to these images and effectively be multi-platform
|
||||
as well.
|
||||
|
||||
Pull requests and master builds
|
||||
are one-image-per-platform so that they can be parallelized and the
|
||||
build matrix for those is more sparse as we don't need to build every
|
||||
build preset on every platform, and generally can be more selective here.
|
||||
For those builds, we suffix tags with `-arm` where it applies.
|
||||
|
||||
### Working with Apple silicon
|
||||
|
||||
Apple's current generation of computers uses ARM-based CPUs, and Docker
|
||||
running on MACs seem to require `linux/arm64/v8` (at least one user's M2 was
|
||||
configured in that way). Setting the environment
|
||||
variable `DOCKER_DEFAULT_PLATFORM` to `linux/amd64` seems to function in
|
||||
term of leveraging, and building upon the Superset builds provided here.
|
||||
|
||||
```bash
|
||||
export DOCKER_DEFAULT_PLATFORM=linux/amd64
|
||||
```
|
||||
|
||||
Presumably, `linux/arm64/v8` would be more optimized for this generation
|
||||
of chips, but less compatible across the ARM ecosystem.
|
||||
@@ -1,286 +0,0 @@
|
||||
---
|
||||
title: Docker Compose
|
||||
hide_title: true
|
||||
sidebar_position: 5
|
||||
version: 1
|
||||
---
|
||||
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
|
||||
# Using Docker Compose
|
||||
|
||||
<img src={useBaseUrl("/img/docker-compose.webp" )} width="150" />
|
||||
<br /><br />
|
||||
|
||||
:::caution
|
||||
Since `docker compose` is primarily designed to run a set of containers on **a single host**
|
||||
and can't support requirements for **high availability**, we do not support nor recommend
|
||||
using our `docker compose` constructs to support production-type use-cases. For single host
|
||||
environments, we recommend using [minikube](https://minikube.sigs.k8s.io/docs/start/) along
|
||||
with our [installing on k8s](https://superset.apache.org/docs/installation/running-on-kubernetes)
|
||||
documentation.
|
||||
:::
|
||||
|
||||
As mentioned in our [quickstart guide](/docs/quickstart), the fastest way to try
|
||||
Superset locally is using Docker Compose on a Linux or Mac OSX
|
||||
computer. Superset does not have official support for Windows. It's also the easiest
|
||||
way to launch a fully functioning **development environment** quickly.
|
||||
|
||||
Note that there are 4 major ways we support to run `docker compose`:
|
||||
|
||||
1. **docker-compose.yml:** for interactive development, where we mount your local folder with the
|
||||
frontend/backend files that you can edit and experience the changes you
|
||||
make in the app in real time
|
||||
1. **docker-compose-light.yml:** a lightweight configuration with minimal services (database,
|
||||
Superset app, and frontend dev server) for development. Uses in-memory caching instead of Redis
|
||||
and is designed for running multiple instances simultaneously
|
||||
1. **docker-compose-non-dev.yml** where we just build a more immutable image based on the
|
||||
local branch and get all the required images running. Changes in the local branch
|
||||
at the time you fire this up will be reflected, but changes to the code
|
||||
while `up` won't be reflected in the app
|
||||
1. **docker-compose-image-tag.yml** where we fetch an image from docker-hub say for the
|
||||
`5.0.0` release for instance, and fire it up so you can try it. Here what's in
|
||||
the local branch has no effects on what's running, we just fetch and run
|
||||
pre-built images from docker-hub. For `docker compose` to work along with the
|
||||
Postgres image it boots up, you'll want to point to a `-dev`-suffixed TAG, as in
|
||||
`export TAG=5.0.0-dev` or `export TAG=4.1.2-dev`, with `latest-dev` being the default.
|
||||
The `dev` builds include the `psycopg2-binary` required to connect
|
||||
to the Postgres database launched as part of the `docker compose` builds.
|
||||
|
||||
More on these approaches after setting up the requirements for either.
|
||||
|
||||
## Requirements
|
||||
|
||||
Note that this documentation assumes that you have [Docker](https://www.docker.com) and
|
||||
[git](https://git-scm.com/) installed. Note also that we used to use `docker-compose` but that
|
||||
is on the path to deprecation so we now use `docker compose` instead.
|
||||
|
||||
## 1. Clone Superset's GitHub repository
|
||||
|
||||
[Clone Superset's repo](https://github.com/apache/superset) in your terminal with the
|
||||
following command:
|
||||
|
||||
```bash
|
||||
git clone --depth=1 https://github.com/apache/superset.git
|
||||
```
|
||||
|
||||
Once that command completes successfully, you should see a new `superset` folder in your
|
||||
current directory.
|
||||
|
||||
## 2. Launch Superset Through Docker Compose
|
||||
|
||||
First let's assume you're familiar with `docker compose` mechanics. Here we'll refer generally
|
||||
to `docker compose up` even though in some cases you may want to force a check for newer remote
|
||||
images using `docker compose pull`, force a build with `docker compose build` or force a build
|
||||
on latest base images using `docker compose build --pull`. In most cases though, the simple
|
||||
`up` command should do just fine. Refer to docker compose docs for more information on the topic.
|
||||
|
||||
### Option #1 - for an interactive development environment
|
||||
|
||||
```bash
|
||||
# The --build argument insures all the layers are up-to-date
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
:::tip
|
||||
When running in development mode the `superset-node`
|
||||
container needs to finish building assets in order for the UI to render properly. If you would just
|
||||
like to try out Superset without making any code changes follow the steps documented for
|
||||
`production` or a specific version below.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
By default, we mount the local superset-frontend folder here and run `npm install` as well
|
||||
as `npm run dev` which triggers webpack to compile/bundle the frontend code. Depending
|
||||
on your local setup, especially if you have less than 16GB of memory, it may be very slow to
|
||||
perform those operations. In this case, we recommend you set the env var
|
||||
`BUILD_SUPERSET_FRONTEND_IN_DOCKER` to `false`, and to run this locally instead in a terminal.
|
||||
Simply trigger `npm i && npm run dev`, this should be MUCH faster.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
Sometimes, your npm-related state can get out-of-wack, running `npm run prune` from
|
||||
the `superset-frontend/` folder will nuke the various' packages `node_module/` folders
|
||||
and help you start fresh. In the context of `docker compose` setting
|
||||
`export NPM_RUN_PRUNE=true` prior to running `docker compose up` will trigger that
|
||||
from within docker. This will slow down the startup, but will fix various npm-related issues.
|
||||
:::
|
||||
|
||||
### Option #2 - lightweight development with multiple instances
|
||||
|
||||
For a lighter development setup that uses fewer resources and supports running multiple instances:
|
||||
|
||||
```bash
|
||||
# Single lightweight instance (default port 9001)
|
||||
docker compose -f docker-compose-light.yml up
|
||||
|
||||
# Multiple instances with different ports
|
||||
NODE_PORT=9001 docker compose -p superset-1 -f docker-compose-light.yml up
|
||||
NODE_PORT=9002 docker compose -p superset-2 -f docker-compose-light.yml up
|
||||
NODE_PORT=9003 docker compose -p superset-3 -f docker-compose-light.yml up
|
||||
```
|
||||
|
||||
This configuration includes:
|
||||
- PostgreSQL database (internal network only)
|
||||
- Superset application server
|
||||
- Frontend development server with webpack hot reloading
|
||||
- In-memory caching (no Redis)
|
||||
- Isolated volumes and networks per instance
|
||||
|
||||
Access each instance at `http://localhost:{NODE_PORT}` (e.g., `http://localhost:9001`).
|
||||
|
||||
### Option #3 - build a set of immutable images from the local branch
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose-non-dev.yml up
|
||||
```
|
||||
|
||||
### Option #4 - boot up an official release
|
||||
|
||||
```bash
|
||||
# Set the version you want to run
|
||||
export TAG=5.0.0
|
||||
# Fetch the tag you're about to check out (assuming you shallow-cloned the repo)
|
||||
git fetch --depth=1 origin tag $TAG
|
||||
# Could also fetch all tags too if you've got bandwidth to spare
|
||||
# git fetch --tags
|
||||
# Checkout the corresponding git ref
|
||||
git checkout $TAG
|
||||
# Fire up docker compose
|
||||
docker compose -f docker-compose-image-tag.yml up
|
||||
```
|
||||
|
||||
Here various release tags, github SHA, and latest `master` can be referenced by the TAG env var.
|
||||
Refer to the docker-related documentation to learn more about existing tags you can point to
|
||||
from Docker Hub.
|
||||
|
||||
:::note
|
||||
For option #2 and #3, we recommend checking out the release tag from the git repository
|
||||
(ie: `git checkout 5.0.0`) for more guaranteed results. This ensures that the `docker-compose.*.yml`
|
||||
configurations and that the mounted `docker/` scripts are in sync with the image you are
|
||||
looking to fire up.
|
||||
:::
|
||||
|
||||
## `docker compose` tips & configuration
|
||||
|
||||
:::caution
|
||||
All of the content belonging to a Superset instance - charts, dashboards, users, etc. - is stored in
|
||||
its metadata database. In production, this database should be backed up. The default installation
|
||||
with docker compose will store that data in a PostgreSQL database contained in a Docker
|
||||
[volume](https://docs.docker.com/storage/volumes/), which is not backed up.
|
||||
|
||||
Again, **THE DOCKER-COMPOSE INSTALLATION IS NOT PRODUCTION-READY OUT OF THE BOX.**
|
||||
|
||||
:::
|
||||
|
||||
You should see a stream of logging output from the containers being launched on your machine. Once
|
||||
this output slows, you should have a running instance of Superset on your local machine! To avoid
|
||||
the wall of text on future runs, add the `-d` option to the end of the `docker compose up` command.
|
||||
|
||||
### Configuring Further
|
||||
|
||||
The following is for users who want to configure how Superset runs in Docker Compose; otherwise, you
|
||||
can skip to the next section.
|
||||
|
||||
You can install additional python packages and apply config overrides by following the steps
|
||||
mentioned in [docker/README.md](https://github.com/apache/superset/tree/master/docker#configuration)
|
||||
|
||||
Note that `docker/.env` sets the default environment variables for all the docker images
|
||||
used by `docker compose`, and that `docker/.env-local` can be used to override those defaults.
|
||||
Also note that `docker/.env-local` is referenced in our `.gitignore`,
|
||||
preventing developers from risking committing potentially sensitive configuration to the repository.
|
||||
|
||||
One important variable is `SUPERSET_LOAD_EXAMPLES` which determines whether the `superset_init`
|
||||
container will populate example data and visualizations into the metadata database. These examples
|
||||
are helpful for learning and testing out Superset but unnecessary for experienced users and
|
||||
production deployments. The loading process can sometimes take a few minutes and a good amount of
|
||||
CPU, so you may want to disable it on a resource-constrained device.
|
||||
|
||||
For more advanced or dynamic configurations that are typically managed in a `superset_config.py` file
|
||||
located in your `PYTHONPATH`, note that it can be done by providing a
|
||||
`docker/pythonpath_dev/superset_config_docker.py` that will be ignored by git
|
||||
(preventing you to commit/push your local configuration back to the repository).
|
||||
The mechanics of this are in `docker/pythonpath_dev/superset_config.py` where you can see
|
||||
that the logic runs a `from superset_config_docker import *`
|
||||
|
||||
:::note
|
||||
Users often want to connect to other databases from Superset. Currently, the easiest way to
|
||||
do this is to modify the `docker-compose-non-dev.yml` file and add your database as a service that
|
||||
the other services depend on (via `x-superset-depends-on`). Others have attempted to set
|
||||
`network_mode: host` on the Superset services, but these generally break the installation,
|
||||
because the configuration requires use of the Docker Compose DNS resolver for the service names.
|
||||
If you have a good solution for this, let us know!
|
||||
:::
|
||||
|
||||
:::note
|
||||
Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry
|
||||
data. Knowing the installation counts for different Superset versions informs the project's
|
||||
decisions about patching and long-term support. Scarf purges personally identifiable information
|
||||
(PII) and provides only aggregated statistics.
|
||||
|
||||
To opt-out of this data collection for packages downloaded through the Scarf Gateway by your docker
|
||||
compose based installation, edit the `x-superset-image:` line in your `docker-compose.yml` and
|
||||
`docker-compose-non-dev.yml` files, replacing `apachesuperset.docker.scarf.sh/apache/superset` with
|
||||
`apache/superset` to pull the image directly from Docker Hub.
|
||||
|
||||
To disable the Scarf telemetry pixel, set the `SCARF_ANALYTICS` environment variable to `False` in
|
||||
your terminal and/or in your `docker/.env` file.
|
||||
:::
|
||||
|
||||
## 3. Log in to Superset
|
||||
|
||||
Your local Superset instance also includes a Postgres server to store your data and is already
|
||||
pre-loaded with some example datasets that ship with Superset. You can access Superset now via your
|
||||
web browser by visiting `http://localhost:8088`. Note that many browsers now default to `https` - if
|
||||
yours is one of them, please make sure it uses `http`.
|
||||
|
||||
Log in with the default username and password:
|
||||
|
||||
```bash
|
||||
username: admin
|
||||
```
|
||||
|
||||
```bash
|
||||
password: admin
|
||||
```
|
||||
|
||||
## 4. Connecting Superset to your local database instance
|
||||
|
||||
When running Superset using `docker` or `docker compose` it runs in its own docker container, as if
|
||||
the Superset was running in a separate machine entirely. Therefore attempts to connect to your local
|
||||
database with the hostname `localhost` won't work as `localhost` refers to the docker container
|
||||
Superset is running in, and not your actual host machine. Fortunately, docker provides an easy way
|
||||
to access network resources in the host machine from inside a container, and we will leverage this
|
||||
capability to connect to our local database instance.
|
||||
|
||||
Here the instructions are for connecting to postgresql (which is running on your host machine) from
|
||||
Superset (which is running in its docker container). Other databases may have slightly different
|
||||
configurations but gist would be same and boils down to 2 steps -
|
||||
|
||||
1. **(Mac users may skip this step)** Configuring the local postgresql/database instance to accept
|
||||
public incoming connections. By default, postgresql only allows incoming connections from
|
||||
`localhost` and under Docker, unless you use `--network=host`, `localhost` will refer to different
|
||||
endpoints on the host machine and in a docker container respectively. Allowing postgresql to accept
|
||||
connections from the Docker involves making one-line changes to the files `postgresql.conf` and
|
||||
`pg_hba.conf`; you can find helpful links tailored to your OS / PG version on the web easily for
|
||||
this task. For Docker it suffices to only whitelist IPs `172.0.0.0/8` instead of `*`, but in any
|
||||
case you are _warned_ that doing this in a production database _may_ have disastrous consequences as
|
||||
you are opening your database to the public internet.
|
||||
1. Instead of `localhost`, try using `host.docker.internal` (Mac users, Ubuntu) or `172.18.0.1`
|
||||
(Linux users) as the hostname when attempting to connect to the database. This is a Docker internal
|
||||
detail -- what is happening is that, in Mac systems, Docker Desktop creates a dns entry for the
|
||||
hostname `host.docker.internal` which resolves to the correct address for the host machine, whereas
|
||||
in Linux this is not the case (at least by default). If neither of these 2 hostnames work then you
|
||||
may want to find the exact hostname you want to use, for that you can do `ifconfig` or
|
||||
`ip addr show` and look at the IP address of `docker0` interface that must have been created by
|
||||
Docker for you. Alternately if you don't even see the `docker0` interface try (if needed with sudo)
|
||||
`docker network inspect bridge` and see if there is an entry for `"Gateway"` and note the IP
|
||||
address.
|
||||
|
||||
## 4. To build or not to build
|
||||
|
||||
When running `docker compose up`, docker will build what is required behind the scene, but
|
||||
may use the docker cache if assets already exist. Running `docker compose build` prior to
|
||||
`docker compose up` or the equivalent shortcut `docker compose up --build` ensures that your
|
||||
docker images match the definition in the repository. This should only apply to the main
|
||||
docker-compose.yml file (default) and not to the alternative methods defined above.
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
title: Installation Methods
|
||||
hide_title: true
|
||||
sidebar_position: 2
|
||||
version: 1
|
||||
---
|
||||
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
|
||||
# Installation Methods
|
||||
|
||||
How should you install Superset? Here's a comparison of the different options. It will help if you've first read the [Architecture](/docs/installation/architecture.mdx) page to understand Superset's different components.
|
||||
|
||||
The fundamental trade-off is between you needing to do more of the detail work yourself vs. using a more complex deployment route that handles those details.
|
||||
|
||||
## [Docker Compose](/docs/installation/docker-compose.mdx)
|
||||
|
||||
**Summary:** This takes advantage of containerization while remaining simpler than Kubernetes. This is the best way to try out Superset; it's also useful for developing & contributing back to Superset.
|
||||
|
||||
If you're not just demoing the software, you'll need a moderate understanding of Docker to customize your deployment and avoid a few risks. Even when fully-optimized this is not as robust a method as Kubernetes when it comes to large-scale production deployments.
|
||||
|
||||
You manage a superset-config.py file and a docker-compose.yml file. Docker Compose brings up all the needed services - the Superset application, a Postgres metadata DB, Redis cache, Celery worker and beat. They are automatically connected to each other.
|
||||
|
||||
**Responsibilities**
|
||||
|
||||
You will need to back up your metadata DB. That could mean backing up the service running as a Docker container and its volume; ideally you are running Postgres as a service outside of that container and backing up that service.
|
||||
|
||||
You will also need to extend the Superset docker image. The default `lean` images do not contain drivers needed to access your metadata database (Postgres or MySQL), nor to access your data warehouse, nor the headless browser needed for Alerts & Reports. You could run a `-dev` image while demoing Superset, which has some of this, but you'll still need to install the driver for your data warehouse. The `-dev` images run as root, which is not recommended for production.
|
||||
|
||||
Ideally you will build your own image of Superset that extends `lean`, adding what your deployment needs. See [Building your own production Docker image](/docs/installation/docker-builds/#building-your-own-production-docker-image).
|
||||
|
||||
## [Kubernetes (K8s)](/docs/installation/kubernetes.mdx)
|
||||
|
||||
**Summary:** This is the best-practice way to deploy a production instance of Superset, but has the steepest skill requirement - someone who knows Kubernetes.
|
||||
|
||||
You will deploy Superset into a K8s cluster. The most common method is using the community-maintained Helm chart, though work is now underway to implement [SIP-149 - a Kubernetes Operator for Superset](https://github.com/apache/superset/issues/31408).
|
||||
|
||||
A K8s deployment can scale up and down based on usage and deploy rolling updates with zero downtime - features that big deployments appreciate.
|
||||
|
||||
**Responsibilities**
|
||||
|
||||
You will need to build your own Docker image, and back up your metadata DB, both as described in Docker Compose above. You'll also need to customize your Helm chart values and deploy and maintain your Kubernetes cluster.
|
||||
|
||||
## [PyPI (Python)](/docs/installation/pypi.mdx)
|
||||
|
||||
**Summary:** This is the only method that requires no knowledge of containers. It requires the most hands-on work to deploy, connect, and maintain each component.
|
||||
|
||||
You install Superset as a Python package and run it that way, providing your own metadata database. Superset has documentation on how to install this way, but it is updated infrequently.
|
||||
|
||||
If you want caching, you'll set up Redis or RabbitMQ. If you want Alerts & Reports, you'll set up Celery.
|
||||
|
||||
**Responsibilities**
|
||||
|
||||
You will need to get the component services running and communicating with each other. You'll need to arrange backups of your metadata database.
|
||||
|
||||
When upgrading, you'll need to manage the system environment and packages and ensure all components have functional dependencies.
|
||||
@@ -1,451 +0,0 @@
|
||||
---
|
||||
title: Kubernetes
|
||||
hide_title: true
|
||||
sidebar_position: 3
|
||||
version: 1
|
||||
---
|
||||
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
|
||||
# Installing on Kubernetes
|
||||
|
||||
<img src={useBaseUrl("/img/k8s.png" )} width="150" />
|
||||
<br /><br />
|
||||
|
||||
Running Superset on Kubernetes is supported with the provided [Helm](https://helm.sh/) chart
|
||||
found in the official [Superset helm repository](https://apache.github.io/superset/index.yaml).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Kubernetes cluster
|
||||
- Helm installed
|
||||
|
||||
:::note
|
||||
For simpler, single host environments, we recommend using
|
||||
[minikube](https://minikube.sigs.k8s.io/docs/start/) which is easy to setup on many platforms
|
||||
and works fantastically well with the Helm chart referenced here.
|
||||
:::
|
||||
|
||||
## Running
|
||||
|
||||
1. Add the Superset helm repository
|
||||
|
||||
```sh
|
||||
helm repo add superset https://apache.github.io/superset
|
||||
"superset" has been added to your repositories
|
||||
```
|
||||
|
||||
2. View charts in repo
|
||||
|
||||
```sh
|
||||
helm search repo superset
|
||||
NAME CHART VERSION APP VERSION DESCRIPTION
|
||||
superset/superset 0.1.1 1.0 Apache Superset is a modern, enterprise-ready b...
|
||||
```
|
||||
|
||||
3. Configure your setting overrides
|
||||
|
||||
Just like any typical Helm chart, you'll need to craft a `values.yaml` file that would define/override any of the values exposed into the default [values.yaml](https://github.com/apache/superset/tree/master/helm/superset/values.yaml), or from any of the dependent charts it depends on:
|
||||
|
||||
- [bitnami/redis](https://artifacthub.io/packages/helm/bitnami/redis)
|
||||
- [bitnami/postgresql](https://artifacthub.io/packages/helm/bitnami/postgresql)
|
||||
|
||||
More info down below on some important overrides you might need.
|
||||
|
||||
4. Install and run
|
||||
|
||||
```sh
|
||||
helm upgrade --install --values my-values.yaml superset superset/superset
|
||||
```
|
||||
|
||||
You should see various pods popping up, such as:
|
||||
|
||||
```sh
|
||||
kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
superset-celerybeat-7cdcc9575f-k6xmc 1/1 Running 0 119s
|
||||
superset-f5c9c667-dw9lp 1/1 Running 0 4m7s
|
||||
superset-f5c9c667-fk8bk 1/1 Running 0 4m11s
|
||||
superset-init-db-zlm9z 0/1 Completed 0 111s
|
||||
superset-postgresql-0 1/1 Running 0 6d20h
|
||||
superset-redis-master-0 1/1 Running 0 6d20h
|
||||
superset-worker-75b48bbcc-jmmjr 1/1 Running 0 4m8s
|
||||
superset-worker-75b48bbcc-qrq49 1/1 Running 0 4m12s
|
||||
```
|
||||
|
||||
The exact list will depend on some of your specific configuration overrides but you should generally expect:
|
||||
|
||||
- N `superset-xxxx-yyyy` and `superset-worker-xxxx-yyyy` pods (depending on your `supersetNode.replicaCount` and `supersetWorker.replicaCount` values)
|
||||
- 1 `superset-postgresql-0` depending on your postgres settings
|
||||
- 1 `superset-redis-master-0` depending on your redis settings
|
||||
- 1 `superset-celerybeat-xxxx-yyyy` pod if you have `supersetCeleryBeat.enabled = true` in your values overrides
|
||||
|
||||
1. Access it
|
||||
|
||||
The chart will publish appropriate services to expose the Superset UI internally within your k8s cluster. To access it externally you will have to either:
|
||||
|
||||
- Configure the Service as a `LoadBalancer` or `NodePort`
|
||||
- Set up an `Ingress` for it - the chart includes a definition, but will need to be tuned to your needs (hostname, tls, annotations etc...)
|
||||
- Run `kubectl port-forward superset-xxxx-yyyy :8088` to directly tunnel one pod's port into your localhost
|
||||
|
||||
Depending how you configured external access, the URL will vary. Once you've identified the appropriate URL you can log in with:
|
||||
|
||||
- user: `admin`
|
||||
- password: `admin`
|
||||
|
||||
## Important settings
|
||||
|
||||
### Security settings
|
||||
|
||||
Default security settings and passwords are included but you **MUST** update them to run `prod` instances, in particular:
|
||||
|
||||
```yaml
|
||||
postgresql:
|
||||
postgresqlPassword: superset
|
||||
```
|
||||
|
||||
Make sure, you set a unique strong complex alphanumeric string for your SECRET_KEY and use a tool to help you generate
|
||||
a sufficiently random sequence.
|
||||
|
||||
- To generate a good key you can run, `openssl rand -base64 42`
|
||||
|
||||
```yaml
|
||||
configOverrides:
|
||||
secret: |
|
||||
SECRET_KEY = 'YOUR_OWN_RANDOM_GENERATED_SECRET_KEY'
|
||||
```
|
||||
|
||||
If you want to change the previous secret key then you should rotate the keys.
|
||||
Default secret key for kubernetes deployment is `thisISaSECRET_1234`
|
||||
|
||||
```yaml
|
||||
configOverrides:
|
||||
my_override: |
|
||||
PREVIOUS_SECRET_KEY = 'YOUR_PREVIOUS_SECRET_KEY'
|
||||
SECRET_KEY = 'YOUR_OWN_RANDOM_GENERATED_SECRET_KEY'
|
||||
init:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
. {{ .Values.configMountPath }}/superset_bootstrap.sh
|
||||
superset re-encrypt-secrets
|
||||
. {{ .Values.configMountPath }}/superset_init.sh
|
||||
```
|
||||
|
||||
:::note
|
||||
Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics.
|
||||
|
||||
To opt-out of this data collection in your Helm-based installation, edit the `repository:` line in your `helm/superset/values.yaml` file, replacing `apachesuperset.docker.scarf.sh/apache/superset` with `apache/superset` to pull the image directly from Docker Hub.
|
||||
:::
|
||||
|
||||
### Dependencies
|
||||
|
||||
Install additional packages and do any other bootstrap configuration in the bootstrap script.
|
||||
For production clusters it's recommended to build own image with this step done in CI.
|
||||
|
||||
:::note
|
||||
|
||||
Superset requires a Python DB-API database driver and a SQLAlchemy
|
||||
dialect to be installed for each datastore you want to connect to.
|
||||
|
||||
See [Install Database Drivers](/docs/databases#installing-database-drivers) for more information.
|
||||
It is recommended that you refer to versions listed in
|
||||
[pyproject.toml](https://github.com/apache/superset/blob/master/pyproject.toml)
|
||||
instead of hard-coding them in your bootstrap script, as seen below.
|
||||
|
||||
:::
|
||||
|
||||
The following example installs the drivers for BigQuery and Elasticsearch, allowing you to connect to these data sources within your Superset setup:
|
||||
|
||||
```yaml
|
||||
bootstrapScript: |
|
||||
#!/bin/bash
|
||||
uv pip install .[postgres] \
|
||||
.[bigquery] \
|
||||
.[elasticsearch] &&\
|
||||
if [ ! -f ~/bootstrap ]; then echo "Running Superset with uid {{ .Values.runAsUser }}" > ~/bootstrap; fi
|
||||
```
|
||||
|
||||
### superset_config.py
|
||||
|
||||
The default `superset_config.py` is fairly minimal and you will very likely need to extend it. This is done by specifying one or more key/value entries in `configOverrides`, e.g.:
|
||||
|
||||
```yaml
|
||||
configOverrides:
|
||||
my_override: |
|
||||
# This will make sure the redirect_uri is properly computed, even with SSL offloading
|
||||
ENABLE_PROXY_FIX = True
|
||||
FEATURE_FLAGS = {
|
||||
"DYNAMIC_PLUGINS": True
|
||||
}
|
||||
```
|
||||
|
||||
Those will be evaluated as Helm templates and therefore will be able to reference other `values.yaml` variables e.g. `{{ .Values.ingress.hosts[0] }}` will resolve to your ingress external domain.
|
||||
|
||||
The entire `superset_config.py` will be installed as a secret, so it is safe to pass sensitive parameters directly... however it might be more readable to use secret env variables for that.
|
||||
|
||||
Full python files can be provided by running `helm upgrade --install --values my-values.yaml --set-file configOverrides.oauth=set_oauth.py`
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Those can be passed as key/values either with `extraEnv` or `extraSecretEnv` if they're sensitive. They can then be referenced from `superset_config.py` using e.g. `os.environ.get("VAR")`.
|
||||
|
||||
```yaml
|
||||
extraEnv:
|
||||
SMTP_HOST: smtp.gmail.com
|
||||
SMTP_USER: user@gmail.com
|
||||
SMTP_PORT: "587"
|
||||
SMTP_MAIL_FROM: user@gmail.com
|
||||
|
||||
extraSecretEnv:
|
||||
SMTP_PASSWORD: xxxx
|
||||
|
||||
configOverrides:
|
||||
smtp: |
|
||||
import ast
|
||||
SMTP_HOST = os.getenv("SMTP_HOST","localhost")
|
||||
SMTP_STARTTLS = ast.literal_eval(os.getenv("SMTP_STARTTLS", "True"))
|
||||
SMTP_SSL = ast.literal_eval(os.getenv("SMTP_SSL", "False"))
|
||||
SMTP_USER = os.getenv("SMTP_USER","superset")
|
||||
SMTP_PORT = os.getenv("SMTP_PORT",25)
|
||||
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD","superset")
|
||||
```
|
||||
|
||||
### System packages
|
||||
|
||||
If new system packages are required, they can be installed before application startup by overriding the container's `command`, e.g.:
|
||||
|
||||
```yaml
|
||||
supersetWorker:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
apt update
|
||||
apt install -y somepackage
|
||||
apt autoremove -yqq --purge
|
||||
apt clean
|
||||
|
||||
# Run celery worker
|
||||
. {{ .Values.configMountPath }}/superset_bootstrap.sh; celery --app=superset.tasks.celery_app:app worker
|
||||
```
|
||||
|
||||
### Data sources
|
||||
|
||||
Data source definitions can be automatically declared by providing key/value yaml definitions in `extraConfigs`:
|
||||
|
||||
```yaml
|
||||
extraConfigs:
|
||||
import_datasources.yaml: |
|
||||
databases:
|
||||
- allow_file_upload: true
|
||||
allow_ctas: true
|
||||
allow_cvas: true
|
||||
database_name: example-db
|
||||
extra: "{\r\n \"metadata_params\": {},\r\n \"engine_params\": {},\r\n \"\
|
||||
metadata_cache_timeout\": {},\r\n \"schemas_allowed_for_file_upload\": []\r\n\
|
||||
}"
|
||||
sqlalchemy_uri: example://example-db.local
|
||||
tables: []
|
||||
```
|
||||
|
||||
Those will also be mounted as secrets and can include sensitive parameters.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Setting up OAuth
|
||||
|
||||
:::note
|
||||
|
||||
OAuth setup requires that the [authlib](https://authlib.org/) Python library is installed. This can
|
||||
be done using `pip` by updating the `bootstrapScript`. See the [Dependencies](#dependencies) section
|
||||
for more information.
|
||||
|
||||
:::
|
||||
|
||||
```yaml
|
||||
extraEnv:
|
||||
AUTH_DOMAIN: example.com
|
||||
|
||||
extraSecretEnv:
|
||||
GOOGLE_KEY: xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
|
||||
GOOGLE_SECRET: xxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
configOverrides:
|
||||
enable_oauth: |
|
||||
# This will make sure the redirect_uri is properly computed, even with SSL offloading
|
||||
ENABLE_PROXY_FIX = True
|
||||
|
||||
from flask_appbuilder.security.manager import AUTH_OAUTH
|
||||
AUTH_TYPE = AUTH_OAUTH
|
||||
OAUTH_PROVIDERS = [
|
||||
{
|
||||
"name": "google",
|
||||
"icon": "fa-google",
|
||||
"token_key": "access_token",
|
||||
"remote_app": {
|
||||
"client_id": os.getenv("GOOGLE_KEY"),
|
||||
"client_secret": os.getenv("GOOGLE_SECRET"),
|
||||
"api_base_url": "https://www.googleapis.com/oauth2/v2/",
|
||||
"client_kwargs": {"scope": "email profile"},
|
||||
"request_token_url": None,
|
||||
"access_token_url": "https://accounts.google.com/o/oauth2/token",
|
||||
"authorize_url": "https://accounts.google.com/o/oauth2/auth",
|
||||
"authorize_params": {"hd": os.getenv("AUTH_DOMAIN", "")}
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
# Map Authlib roles to superset roles
|
||||
AUTH_ROLE_ADMIN = 'Admin'
|
||||
AUTH_ROLE_PUBLIC = 'Public'
|
||||
|
||||
# Will allow user self registration, allowing to create Flask users from Authorized User
|
||||
AUTH_USER_REGISTRATION = True
|
||||
|
||||
# The default user self registration role
|
||||
AUTH_USER_REGISTRATION_ROLE = "Admin"
|
||||
```
|
||||
|
||||
### Enable Alerts and Reports
|
||||
|
||||
For this, as per the [Alerts and Reports doc](/docs/configuration/alerts-reports), you will need to:
|
||||
|
||||
#### Install a supported webdriver in the Celery worker
|
||||
|
||||
This is done either by using a custom image that has the webdriver pre-installed, or installing at startup time by overriding the `command`. Here's a working example for `chromedriver`:
|
||||
|
||||
```yaml
|
||||
supersetWorker:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
# Install chrome webdriver
|
||||
# See https://github.com/apache/superset/blob/4fa3b6c7185629b87c27fc2c0e5435d458f7b73d/docs/src/pages/docs/installation/email_reports.mdx
|
||||
apt-get update
|
||||
apt-get install -y wget
|
||||
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
apt-get install -y --no-install-recommends ./google-chrome-stable_current_amd64.deb
|
||||
wget https://chromedriver.storage.googleapis.com/88.0.4324.96/chromedriver_linux64.zip
|
||||
apt-get install -y zip
|
||||
unzip chromedriver_linux64.zip
|
||||
chmod +x chromedriver
|
||||
mv chromedriver /usr/bin
|
||||
apt-get autoremove -yqq --purge
|
||||
apt-get clean
|
||||
rm -f google-chrome-stable_current_amd64.deb chromedriver_linux64.zip
|
||||
|
||||
# Run
|
||||
. {{ .Values.configMountPath }}/superset_bootstrap.sh; celery --app=superset.tasks.celery_app:app worker
|
||||
```
|
||||
|
||||
#### Run the Celery beat
|
||||
|
||||
This pod will trigger the scheduled tasks configured in the alerts and reports UI section:
|
||||
|
||||
```yaml
|
||||
supersetCeleryBeat:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
#### Configure the appropriate Celery jobs and SMTP/Slack settings
|
||||
|
||||
```yaml
|
||||
extraEnv:
|
||||
SMTP_HOST: smtp.gmail.com
|
||||
SMTP_USER: user@gmail.com
|
||||
SMTP_PORT: "587"
|
||||
SMTP_MAIL_FROM: user@gmail.com
|
||||
|
||||
extraSecretEnv:
|
||||
SLACK_API_TOKEN: xoxb-xxxx-yyyy
|
||||
SMTP_PASSWORD: xxxx-yyyy
|
||||
|
||||
configOverrides:
|
||||
feature_flags: |
|
||||
import ast
|
||||
|
||||
FEATURE_FLAGS = {
|
||||
"ALERT_REPORTS": True
|
||||
}
|
||||
|
||||
SMTP_HOST = os.getenv("SMTP_HOST","localhost")
|
||||
SMTP_STARTTLS = ast.literal_eval(os.getenv("SMTP_STARTTLS", "True"))
|
||||
SMTP_SSL = ast.literal_eval(os.getenv("SMTP_SSL", "False"))
|
||||
SMTP_USER = os.getenv("SMTP_USER","superset")
|
||||
SMTP_PORT = os.getenv("SMTP_PORT",25)
|
||||
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD","superset")
|
||||
SMTP_MAIL_FROM = os.getenv("SMTP_MAIL_FROM","superset@superset.com")
|
||||
|
||||
SLACK_API_TOKEN = os.getenv("SLACK_API_TOKEN",None)
|
||||
celery_conf: |
|
||||
from celery.schedules import crontab
|
||||
|
||||
class CeleryConfig:
|
||||
broker_url = f"redis://{env('REDIS_HOST')}:{env('REDIS_PORT')}/0"
|
||||
imports = (
|
||||
"superset.sql_lab",
|
||||
"superset.tasks.cache",
|
||||
"superset.tasks.scheduler",
|
||||
)
|
||||
result_backend = f"redis://{env('REDIS_HOST')}:{env('REDIS_PORT')}/0"
|
||||
task_annotations = {
|
||||
"sql_lab.get_sql_results": {
|
||||
"rate_limit": "100/s",
|
||||
},
|
||||
}
|
||||
beat_schedule = {
|
||||
"reports.scheduler": {
|
||||
"task": "reports.scheduler",
|
||||
"schedule": crontab(minute="*", hour="*"),
|
||||
},
|
||||
"reports.prune_log": {
|
||||
"task": "reports.prune_log",
|
||||
'schedule': crontab(minute=0, hour=0),
|
||||
},
|
||||
'cache-warmup-hourly': {
|
||||
"task": "cache-warmup",
|
||||
"schedule": crontab(minute="*/30", hour="*"),
|
||||
"kwargs": {
|
||||
"strategy_name": "top_n_dashboards",
|
||||
"top_n": 10,
|
||||
"since": "7 days ago",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
CELERY_CONFIG = CeleryConfig
|
||||
reports: |
|
||||
EMAIL_PAGE_RENDER_WAIT = 60
|
||||
WEBDRIVER_BASEURL = "http://{{ template "superset.fullname" . }}:{{ .Values.service.port }}/"
|
||||
WEBDRIVER_BASEURL_USER_FRIENDLY = "https://www.example.com/"
|
||||
WEBDRIVER_TYPE= "chrome"
|
||||
WEBDRIVER_OPTION_ARGS = [
|
||||
"--force-device-scale-factor=2.0",
|
||||
"--high-dpi-support=2.0",
|
||||
"--headless",
|
||||
"--disable-gpu",
|
||||
"--disable-dev-shm-usage",
|
||||
# This is required because our process runs as root (in order to install pip packages)
|
||||
"--no-sandbox",
|
||||
"--disable-setuid-sandbox",
|
||||
"--disable-extensions",
|
||||
]
|
||||
```
|
||||
|
||||
### Load the Examples data and dashboards
|
||||
|
||||
If you are trying Superset out and want some data and dashboards to explore, you can load some examples by creating a `my_values.yaml` and deploying it as described above in the **Configure your setting overrides** step of the **Running** section.
|
||||
To load the examples, add the following to the `my_values.yaml` file:
|
||||
|
||||
```yaml
|
||||
init:
|
||||
loadExamples: true
|
||||
```
|
||||
|
||||
:::resources
|
||||
- [Tutorial: Mastering Data Visualization — Installing Superset on Kubernetes with Helm Chart](https://mahira-technology.medium.com/mastering-data-visualization-installing-superset-on-kubernetes-cluster-using-helm-chart-e4ec99199e1e)
|
||||
- [Tutorial: Installing Apache Superset in Kubernetes](https://aws.plainenglish.io/installing-apache-superset-in-kubernetes-1aec192ac495)
|
||||
:::
|
||||
@@ -1,164 +0,0 @@
|
||||
---
|
||||
title: PyPI
|
||||
hide_title: true
|
||||
sidebar_position: 4
|
||||
version: 1
|
||||
---
|
||||
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
|
||||
# Installing Superset from PyPI
|
||||
|
||||
<img src={useBaseUrl("/img/pypi.png" )} width="150" />
|
||||
<br /><br />
|
||||
|
||||
This page describes how to install Superset using the `apache_superset` package [published on PyPI](https://pypi.org/project/apache_superset/).
|
||||
|
||||
## OS Dependencies
|
||||
|
||||
Superset stores database connection information in its metadata database. For that purpose, we use
|
||||
the cryptography Python library to encrypt connection passwords. Unfortunately, this library has OS
|
||||
level dependencies.
|
||||
|
||||
**Debian and Ubuntu**
|
||||
|
||||
Ubuntu **24.04** uses python 3.12 per default, which currently is not supported by Superset. You need to add a second python installation of 3.11 and install the required additional dependencies.
|
||||
```bash
|
||||
sudo add-apt-repository ppa:deadsnakes/ppa
|
||||
sudo apt update
|
||||
sudo apt install python3.11 python3.11-dev python3.11-venv build-essential libssl-dev libffi-dev libsasl2-dev libldap2-dev default-libmysqlclient-dev
|
||||
```
|
||||
|
||||
In Ubuntu **20.04 and 22.04** the following command will ensure that the required dependencies are installed:
|
||||
|
||||
```bash
|
||||
sudo apt-get install build-essential libssl-dev libffi-dev python3-dev python3-pip libsasl2-dev libldap2-dev default-libmysqlclient-dev
|
||||
```
|
||||
|
||||
In Ubuntu **before 20.04** the following command will ensure that the required dependencies are installed:
|
||||
|
||||
```bash
|
||||
sudo apt-get install build-essential libssl-dev libffi-dev python-dev python-pip libsasl2-dev libldap2-dev default-libmysqlclient-dev
|
||||
```
|
||||
|
||||
**Fedora and RHEL-derivative Linux distributions**
|
||||
|
||||
Install the following packages using the `yum` package manager:
|
||||
|
||||
```bash
|
||||
sudo yum install gcc gcc-c++ libffi-devel python-devel python-pip python-wheel openssl-devel cyrus-sasl-devel openldap-devel
|
||||
```
|
||||
|
||||
In more recent versions of CentOS and Fedora, you may need to install a slightly different set of packages using `dnf`:
|
||||
|
||||
```bash
|
||||
sudo dnf install gcc gcc-c++ libffi-devel python3-devel python3-pip python3-wheel openssl-devel cyrus-sasl-devel openldap-devel
|
||||
```
|
||||
|
||||
Also, on CentOS, you may need to upgrade pip for the install to work:
|
||||
|
||||
```bash
|
||||
pip3 install --upgrade pip
|
||||
```
|
||||
|
||||
**Mac OS X**
|
||||
|
||||
If you're not on the latest version of OS X, we recommend upgrading because we've found that many
|
||||
issues people have run into are linked to older versions of Mac OS X. After updating, install the
|
||||
latest version of XCode command line tools:
|
||||
|
||||
```bash
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
We don't recommend using the system installed Python. Instead, first install the
|
||||
[homebrew](https://brew.sh/) manager and then run the following commands:
|
||||
|
||||
```bash
|
||||
brew install readline pkg-config libffi openssl mysql postgresql@14
|
||||
```
|
||||
|
||||
You should install a recent version of Python. Refer to the
|
||||
[pyproject.toml](https://github.com/apache/superset/blob/master/pyproject.toml) file for a list of Python
|
||||
versions officially supported by Superset. We'd recommend using a Python version manager
|
||||
like [pyenv](https://github.com/pyenv/pyenv)
|
||||
(and also [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv)).
|
||||
|
||||
Let's also make sure we have the latest version of `pip` and `setuptools`:
|
||||
|
||||
```bash
|
||||
pip install --upgrade setuptools pip
|
||||
```
|
||||
|
||||
Lastly, you may need to set LDFLAGS and CFLAGS for certain Python packages to properly build. You can export these variables with:
|
||||
|
||||
```bash
|
||||
export LDFLAGS="-L$(brew --prefix openssl)/lib"
|
||||
export CFLAGS="-I$(brew --prefix openssl)/include"
|
||||
```
|
||||
|
||||
These will now be available when pip installing requirements.
|
||||
|
||||
## Python Virtual Environment
|
||||
|
||||
We highly recommend installing Superset inside of a virtual environment.
|
||||
|
||||
You can create and activate a virtual environment using the following commands. Ensure you are using a compatible version of python. You might have to explicitly use for example `python3.11` instead of `python3`.
|
||||
|
||||
```bash
|
||||
# virtualenv is shipped in Python 3.6+ as venv instead of pyvenv.
|
||||
# See https://docs.python.org/3.6/library/venv.html
|
||||
python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
```
|
||||
|
||||
Or with pyenv-virtualenv:
|
||||
|
||||
```bash
|
||||
# Here we name the virtual env 'superset'
|
||||
pyenv virtualenv superset
|
||||
pyenv activate superset
|
||||
```
|
||||
|
||||
Once you activated your virtual environment, all of the Python packages you install or uninstall
|
||||
will be confined to this environment. You can exit the environment by running `deactivate` on the
|
||||
command line.
|
||||
|
||||
### Installing and Initializing Superset
|
||||
|
||||
First, start by installing `apache_superset`:
|
||||
|
||||
```bash
|
||||
pip install apache_superset
|
||||
```
|
||||
|
||||
Then, define mandatory configurations, SECRET_KEY and FLASK_APP:
|
||||
```bash
|
||||
export SUPERSET_SECRET_KEY=YOUR-SECRET-KEY # For production use, make sure this is a strong key, for example generated using `openssl rand -base64 42`. See https://superset.apache.org/docs/configuration/configuring-superset#specifying-a-secret_key
|
||||
export FLASK_APP=superset
|
||||
```
|
||||
|
||||
Then, you need to initialize the database:
|
||||
|
||||
```bash
|
||||
superset db upgrade
|
||||
```
|
||||
|
||||
Finish installing by running through the following commands:
|
||||
|
||||
```bash
|
||||
# Create an admin user in your metadata database (use `admin` as username to be able to load the examples)
|
||||
superset fab create-admin
|
||||
|
||||
# Load some data to play with
|
||||
superset load_examples
|
||||
|
||||
# Create default roles and permissions
|
||||
superset init
|
||||
|
||||
# To start a development web server on port 8088, use -p to bind to another port
|
||||
superset run -p 8088 --with-threads --reload --debugger
|
||||
```
|
||||
|
||||
If everything worked, you should be able to navigate to `hostname:port` in your browser (e.g.
|
||||
locally by default at `localhost:8088`) and login using the username and password you created.
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
title: Upgrading Superset
|
||||
hide_title: true
|
||||
sidebar_position: 6
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Upgrading Superset
|
||||
|
||||
## Docker Compose
|
||||
|
||||
First, make sure to shut down the running containers in Docker Compose:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
Next, update the folder that mirrors the `superset` repo through git:
|
||||
|
||||
```bash
|
||||
git pull origin master
|
||||
```
|
||||
|
||||
Then, restart the containers and any changed Docker images will be automatically pulled down:
|
||||
|
||||
```bash
|
||||
docker compose up
|
||||
```
|
||||
|
||||
## Updating Superset Manually
|
||||
|
||||
To upgrade superset in a native installation, run the following commands:
|
||||
|
||||
```bash
|
||||
pip install apache_superset --upgrade
|
||||
```
|
||||
|
||||
## Upgrading the Metadata Database
|
||||
|
||||
Migrate the metadata database by running:
|
||||
|
||||
```bash
|
||||
superset db upgrade
|
||||
superset init
|
||||
```
|
||||
|
||||
While upgrading superset should not delete your charts and dashboards, we recommend following best
|
||||
practices and to backup your metadata database before upgrading. Before upgrading production, we
|
||||
recommend upgrading in a staging environment and upgrading production finally during off-peak usage.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
For a detailed list of breaking changes and migration notes for each version, see
|
||||
[UPDATING.md](https://github.com/apache/superset/blob/master/UPDATING.md).
|
||||
|
||||
This file documents backwards-incompatible changes and provides guidance for migrating between
|
||||
major versions, including:
|
||||
- Configuration changes
|
||||
- API changes
|
||||
- Database migrations
|
||||
- Deprecated features
|
||||
@@ -15,7 +15,7 @@ Although we recommend using `Docker Compose` for a quick start in a sandbox-type
|
||||
environment and for other development-type use cases, **we
|
||||
do not recommend this setup for production**. For this purpose please
|
||||
refer to our
|
||||
[Installing on Kubernetes](/docs/installation/kubernetes/)
|
||||
[Installing on Kubernetes](/admin-docs/installation/kubernetes)
|
||||
page.
|
||||
:::
|
||||
|
||||
@@ -73,16 +73,16 @@ processes by running Docker Compose `stop` command. By doing so, you can avoid d
|
||||
|
||||
From this point on, you can head on to:
|
||||
|
||||
- [Create your first Dashboard](/docs/using-superset/creating-your-first-dashboard)
|
||||
- [Connect to a Database](/docs/databases)
|
||||
- [Using Docker Compose](/docs/installation/docker-compose)
|
||||
- [Configure Superset](/docs/configuration/configuring-superset/)
|
||||
- [Installing on Kubernetes](/docs/installation/kubernetes/)
|
||||
- [Create your first Dashboard](/user-docs/using-superset/creating-your-first-dashboard)
|
||||
- [Connect to a Database](/user-docs/databases/)
|
||||
- [Using Docker Compose](/admin-docs/installation/docker-compose)
|
||||
- [Configure Superset](/admin-docs/configuration/configuring-superset)
|
||||
- [Installing on Kubernetes](/admin-docs/installation/kubernetes)
|
||||
|
||||
Or just explore our [Documentation](https://superset.apache.org/docs/intro)!
|
||||
|
||||
:::resources
|
||||
- [Video: Superset in 2 Minutes](https://www.youtube.com/watch?v=AqousXQ7YHw)
|
||||
- [Video: Superset 101](https://www.youtube.com/watch?v=mAIH3hUoxEE)
|
||||
- [Tutorial: Creating Your First Dashboard](/docs/using-superset/creating-your-first-dashboard)
|
||||
- [Tutorial: Creating Your First Dashboard](/user-docs/using-superset/creating-your-first-dashboard)
|
||||
:::
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
---
|
||||
title: CVEs fixed by release
|
||||
sidebar_position: 2
|
||||
---
|
||||
#### Version 5.0.0
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:-----------------------------------------------------------------------------------|---------:|
|
||||
| CVE-2025-55673 | Exposure of Sensitive Information to an Unauthorized Actor | < 5.0.0 |
|
||||
| CVE-2025-55674 | Improper Neutralization of Special Elements used in an SQL Command | < 5.0.0 |
|
||||
| CVE-2025-55675 | Improper Access Control leading to Information Disclosure | < 5.0.0 |
|
||||
|
||||
#### Version 4.1.3
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:-----------------------------------------------------------------------------------|---------:|
|
||||
| CVE-2025-55672 | Improper Neutralization of Input During Web Page Generation | < 4.1.3 |
|
||||
|
||||
#### Version 4.1.2
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:-----------------------------------------------------------------------------------|---------:|
|
||||
| CVE-2025-27696 | Improper authorization leading to resource ownership takeover | < 4.1.2 |
|
||||
| CVE-2025-48912 | Improper authorization bypass on row level security via SQL Injection | < 4.1.2 |
|
||||
|
||||
#### Version 4.1.0
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:-----------------------------------------------------------------------------------|---------:|
|
||||
| CVE-2024-53947 | Improper SQL authorisation, parse for specific postgres functions | < 4.1.0 |
|
||||
| CVE-2024-53948 | Error verbosity exposes metadata in analytics databases | < 4.1.0 |
|
||||
| CVE-2024-53949 | Lower privilege users are able to create Role when FAB_ADD_SECURITY_API is enabled | < 4.1.0 |
|
||||
| CVE-2024-55633 | SQLLab Improper readonly query validation allows unauthorized write access | < 4.1.0 |
|
||||
|
||||
#### Version 4.0.2
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:----------------------------|---------:|
|
||||
| CVE-2024-39887 | Improper SQL authorization | < 4.0.1 |
|
||||
|
||||
#### Version 3.1.3, 4.0.1
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:----------------------------|----------------------------:|
|
||||
| CVE-2024-34693 | Server arbitrary file read | < 3.1.3, >= 4.0.0, < 4.0.1 |
|
||||
|
||||
#### Version 3.1.2
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:--------------------------------------------------------|---------:|
|
||||
| CVE-2024-28148 | Incorrect datasource authorization on explore REST API | < 3.1.2 |
|
||||
|
||||
#### Version 3.0.4, 3.1.1
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:-----------------------------------------------------------------------------|----------------------------:|
|
||||
| CVE-2024-27315 | Improper error handling on alerts | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
| CVE-2024-24773 | Improper validation of SQL statements allows for unauthorized access to data | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
| CVE-2024-24772 | Improper Neutralisation of custom SQL on embedded context | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
| CVE-2024-24779 | Improper data authorization when creating a new dataset | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
| CVE-2024-26016 | Improper authorization validation on dashboards and charts import | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
|
||||
#### Version 3.0.3
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:----------------------------------------------|---------:|
|
||||
| CVE-2023-49657 | Stored XSS in Dashboard Title and Chart Title | < 3.0.3 |
|
||||
|
||||
#### Version 3.0.2, 2.1.3
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:------------------------------------------------------------|---------------------------:|
|
||||
| CVE-2023-46104 | Allows for uncontrolled resource consumption via a ZIP bomb | < 2.1.3, >= 3.0.0, < 3.0.2 |
|
||||
| CVE-2023-49736 | SQL Injection on where_in JINJA macro | < 2.1.3, >= 3.0.0, < 3.0.2 |
|
||||
| CVE-2023-49734 | Privilege Escalation Vulnerability | < 2.1.3, >= 3.0.0, < 3.0.2 |
|
||||
|
||||
#### Version 3.0.0
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:------------------------------------------------------------------------|---------:|
|
||||
| CVE-2023-42502 | Open Redirect Vulnerability | < 3.0.0 |
|
||||
| CVE-2023-42505 | Sensitive information disclosure on db connection details | < 3.0.0 |
|
||||
|
||||
#### Version 2.1.3
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:------------------------------------------------------------------------|---------:|
|
||||
| CVE-2023-42504 | Lack of rate limiting allows for possible denial of service | < 2.1.3 |
|
||||
|
||||
#### Version 2.1.2
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:------------------------------------------------------------------------|---------:|
|
||||
| CVE-2023-40610 | Privilege escalation with default examples database | < 2.1.2 |
|
||||
| CVE-2023-42501 | Unnecessary read permissions within the Gamma role | < 2.1.2 |
|
||||
| CVE-2023-43701 | Stored XSS on API endpoint | < 2.1.2 |
|
||||
|
||||
#### Version 2.1.1
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:------------------------------------------------------------------------|---------:|
|
||||
| CVE-2023-36387 | Improper API permission for low privilege users | < 2.1.1 |
|
||||
| CVE-2023-36388 | Improper API permission for low privilege users allows for SSRF | < 2.1.1 |
|
||||
| CVE-2023-27523 | Improper data permission validation on Jinja templated queries | < 2.1.1 |
|
||||
| CVE-2023-27526 | Improper Authorization check on import charts | < 2.1.1 |
|
||||
| CVE-2023-39264 | Stack traces enabled by default | < 2.1.1 |
|
||||
| CVE-2023-39265 | Possible Unauthorized Registration of SQLite Database Connections | < 2.1.1 |
|
||||
| CVE-2023-37941 | Metadata db write access can lead to remote code execution | < 2.1.1 |
|
||||
| CVE-2023-32672 | SQL parser edge case bypasses data access authorization | < 2.1.1 |
|
||||
|
||||
#### Version 2.1.0
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:------------------------------------------------------------------------|---------:|
|
||||
| CVE-2023-25504 | Possible SSRF on import datasets | < 2.1.0 |
|
||||
| CVE-2023-27524 | Session validation vulnerability when using provided default SECRET_KEY | < 2.1.0 |
|
||||
| CVE-2023-27525 | Incorrect default permissions for Gamma role | < 2.1.0 |
|
||||
| CVE-2023-30776 | Database connection password leak | < 2.1.0 |
|
||||
|
||||
#### Version 2.0.1
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:------------------------------------------------------------|------------------: |
|
||||
| CVE-2022-41703 | SQL injection vulnerability in adhoc clauses | < 2.0.1 or < 1.5.2 |
|
||||
| CVE-2022-43717 | Cross-Site Scripting on dashboards | < 2.0.1 or < 1.5.2 |
|
||||
| CVE-2022-43718 | Cross-Site Scripting vulnerability on upload forms | < 2.0.1 or < 1.5.2 |
|
||||
| CVE-2022-43719 | Cross Site Request Forgery (CSRF) on accept, request access | < 2.0.1 or < 1.5.2 |
|
||||
| CVE-2022-43720 | Improper rendering of user input | < 2.0.1 or < 1.5.2 |
|
||||
| CVE-2022-43721 | Open Redirect Vulnerability | < 2.0.1 or < 1.5.2 |
|
||||
| CVE-2022-45438 | Dashboard metadata information leak | < 2.0.1 or < 1.5.2 |
|
||||
@@ -1,179 +0,0 @@
|
||||
---
|
||||
title: Securing Your Superset Installation for Production
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
> *This guide applies to Apache Superset version 4.0 and later and is an evolving set of best practices that administrators should adapt to their specific deployment architecture.*
|
||||
|
||||
The default Apache Superset configuration is optimized for ease of use and development, not for security. For any production deployment, it is **critical** that you review and apply the following security configurations to harden your instance, protect user data, and prevent unauthorized access.
|
||||
|
||||
This guide provides a comprehensive checklist of essential security configurations and best practices.
|
||||
|
||||
### **Critical Prerequisites: HTTPS/TLS Configuration**
|
||||
|
||||
Running Superset without HTTPS (TLS) is not secure. Without it, all network traffic—including user credentials, session tokens, and sensitive data—is sent in cleartext and can be easily intercepted.
|
||||
|
||||
* **Use a Reverse Proxy:** Your Superset instance should always be deployed behind a reverse proxy (e.g., Nginx, Traefik) or a load balancer (e.g., AWS ALB, Google Cloud Load Balancer) that is configured to handle HTTPS termination.
|
||||
* **Enforce Modern TLS:** Configure your proxy to enforce TLS 1.2 or higher with strong, industry-standard cipher suites.
|
||||
* **Implement HSTS:** Use the HTTP Strict Transport Security (HSTS) header to ensure browsers only connect to your Superset instance over HTTPS. This can be configured in your reverse proxy or within Superset's Talisman settings.
|
||||
|
||||
### **`SUPERSET_SECRET_KEY` Management (CRITICAL)**
|
||||
|
||||
This is the most critical security setting for your Superset instance. It is used to sign all session cookies and encrypt sensitive information in the metadata database, such as database connection credentials.
|
||||
|
||||
* **Generate a Unique, Strong Key:** A unique key must be generated for every Superset instance. Use a cryptographically secure method to create it.
|
||||
```bash
|
||||
# Example using openssl to generate a strong key
|
||||
openssl rand -base64 42
|
||||
```
|
||||
* **Store the Key Securely:** The key must be kept confidential. The recommended approach is to store it as an environment variable or in a secrets management system (e.g., AWS Secrets Manager, HashiCorp Vault). **Do not hardcode the key in `superset_config.py` or commit it to version control.**
|
||||
```python
|
||||
# In superset_config.py
|
||||
import os
|
||||
SECRET_KEY = os.environ.get('SUPERSET_SECRET_KEY')
|
||||
```
|
||||
|
||||
> #### ⚠️ Warning: Your `SUPERSET_SECRET_KEY` Must Be Unique
|
||||
>
|
||||
> **NEVER** reuse the same `SUPERSET_SECRET_KEY` across different environments (e.g., development, staging, production) or different Superset instances. Reusing a key allows cryptographically signed session cookies to be used across those instances, which can lead to a full authentication bypass if a cookie is compromised. Treat this key like a master password.
|
||||
|
||||
### **Session Management Security (CRITICAL)**
|
||||
|
||||
Properly configuring user sessions is essential to prevent session hijacking and ensure that sessions are terminated correctly.
|
||||
|
||||
#### **Use a Server-Side Session Backend (Strongly Recommended for Production)**
|
||||
|
||||
The default stateless cookie-based session handling presents challenges for immediate session invalidation upon logout. For all production deployments, we strongly recommend configuring an optional server-side session backend like Redis, Memcached, or a database. This ensures that session data is stored securely on the server and can be instantly destroyed upon logout, rendering any copied session cookies immediately useless.
|
||||
|
||||
**Example `superset_config.py` for Redis:**
|
||||
|
||||
```python
|
||||
# superset_config.py
|
||||
from redis import Redis
|
||||
import os
|
||||
|
||||
# 1. Enable server-side sessions
|
||||
SESSION_SERVER_SIDE = True
|
||||
|
||||
# 2. Choose your backend (e.g., 'redis', 'memcached', 'filesystem', 'sqlalchemy')
|
||||
SESSION_TYPE = 'redis'
|
||||
|
||||
# 3. Configure your Redis connection
|
||||
# Use environment variables for sensitive details
|
||||
SESSION_REDIS = Redis(
|
||||
host=os.environ.get('REDIS_HOST', 'localhost'),
|
||||
port=int(os.environ.get('REDIS_PORT', 6379)),
|
||||
password=os.environ.get('REDIS_PASSWORD'),
|
||||
db=int(os.environ.get('REDIS_DB', 0)),
|
||||
ssl=os.environ.get('REDIS_SSL_ENABLED', 'True').lower() == 'true',
|
||||
ssl_cert_reqs='required' # Or another appropriate SSL setting
|
||||
)
|
||||
|
||||
# 4. Ensure the session cookie is signed for integrity
|
||||
SESSION_USE_SIGNER = True
|
||||
```
|
||||
|
||||
#### **Configure Session Lifetime and Cookie Security Flags**
|
||||
|
||||
This is mandatory for *all* deployments, whether stateless or server-side.
|
||||
|
||||
```python
|
||||
# superset_config.py
|
||||
from datetime import timedelta
|
||||
|
||||
# Set a short absolute session timeout
|
||||
# The default is 31 days, which is NOT recommended for production.
|
||||
PERMANENT_SESSION_LIFETIME = timedelta(hours=8)
|
||||
|
||||
# Enforce secure cookie flags to prevent browser-based attacks
|
||||
SESSION_COOKIE_SECURE = True # Transmit cookie only over HTTPS
|
||||
SESSION_COOKIE_HTTPONLY = True # Prevent client-side JS from accessing the cookie
|
||||
SESSION_COOKIE_SAMESITE = 'Lax' # Provide protection against CSRF attacks
|
||||
```
|
||||
|
||||
> ##### Note on iFrame Embedding and `SESSION_COOKIE_SAMESITE`
|
||||
>The recommended default setting `'Lax'` provides good CSRF protection for most use cases. However, if you need to embed Superset dashboards into other applications using an iFrame, you will need to change this setting to `'None'`.
|
||||
|
||||
SESSION_COOKIE_SAMESITE = 'None'
|
||||
|
||||
Setting SameSite to 'None' requires that SESSION_COOKIE_SECURE is also set to True. Be aware that this configuration disables some of the browser's built-in CSRF protections to allow for cross-domain functionality, so it should only be used when iFrame embedding is necessary.
|
||||
|
||||
### **Authentication and Authorization**
|
||||
|
||||
While Superset's built-in database authentication is convenient, for production it's highly recommended to integrate with an enterprise-grade identity provider (IdP).
|
||||
|
||||
* **Use an Enterprise IdP:** Configure authentication via OAuth or LDAP to leverage your organization's existing identity management system. This provides benefits like Single Sign-On (SSO), Multi-Factor Authentication (MFA), and centralized user provisioning/deprovisioning.
|
||||
* **Principle of Least Privilege:** Assign users to the most restrictive roles necessary for their jobs. Avoid over-provisioning users with Admin or Alpha roles, and ensure row-level security is applied where appropriate.
|
||||
* **Admin Accounts:** Delete or disable the default admin user after a new administrative account has been configured.
|
||||
|
||||
### **Content Security Policy (CSP) and Other Headers**
|
||||
|
||||
Superset can use Flask-Talisman to set security headers. However, it must be explicitly enabled.
|
||||
|
||||
> #### ⚠️ Important: Talisman is Disabled by Default
|
||||
>
|
||||
> In Superset 4.0 and later, Talisman is disabled by default (`TALISMAN_ENABLED = False`). You **must** explicitly enable it in your `superset_config.py` for the security headers defined in `TALISMAN_CONFIG` to take effect.
|
||||
|
||||
Here's the documentation section how how to set up Talisman: https://superset.apache.org/docs/security/#content-security-policy-csp
|
||||
|
||||
### **Database Security**
|
||||
|
||||
> #### ❗ Superset is Not a Database Firewall
|
||||
>
|
||||
> It is essential to understand that **Apache Superset is a data visualization and exploration platform, not a database firewall or a comprehensive security solution for your data warehouse.** While Superset provides features to help manage data access, the ultimate responsibility for securing your underlying databases lies with your database administrators (DBAs) and security teams. This includes managing network access, user privileges, and fine-grained permissions directly within the database. The configurations below are an important secondary layer of security but should not be your only line of defense.
|
||||
|
||||
* **Use a Dedicated Database User:** The database connection configured in Superset should use a dedicated, limited-privilege database user. This user should only have the minimum required permissions (e.g., `SELECT` on specific schemas) for the data sources it needs to query. It should **not** have `INSERT`, `UPDATE`, `DELETE`, or administrative privileges.
|
||||
* **Restrict Dangerous SQL Functions:** To mitigate potential SQL injection risks, configure the `DISALLOWED_SQL_FUNCTIONS` list in your `superset_config.py`. Be aware that this is a defense-in-depth measure, not a substitute for proper database permissions.
|
||||
|
||||
### **Additional Security Layers**
|
||||
|
||||
* **Web Application Firewall (WAF):** Deploying Superset behind a WAF (e.g., Cloudflare, AWS WAF) is strongly recommended. A WAF with a standard ruleset (like the OWASP Core Rule Set) provides a critical layer of defense against common attacks like SQL Injection, XSS, and remote code execution.
|
||||
|
||||
### **Monitoring and Logging**
|
||||
|
||||
* **Configure Structured Logging:** Set up a robust logging configuration to capture important security events.
|
||||
* **Centralize Logs:** Ship logs from all Superset components (frontend, worker, etc.) to a centralized SIEM (Security Information and Event Management) system for analysis and alerting.
|
||||
* **Monitor Key Events:** Create alerts for suspicious activities, including:
|
||||
* Multiple failed login attempts for a single user or from a single IP address.
|
||||
* Changes to user roles or permissions.
|
||||
* Creation or deletion of high-privilege users.
|
||||
* Attempts to use disallowed SQL functions.
|
||||
|
||||
-----
|
||||
|
||||
### **Appendix A: Production Deployment Checklist**
|
||||
|
||||
#### **Initial Setup:**
|
||||
|
||||
- [ ] HTTPS/TLS is configured and enforced via a reverse proxy.
|
||||
- [ ] A unique, strong `SUPERSET_SECRET_KEY` is generated and secured in an environment variable or secrets vault.
|
||||
- [ ] Server-side session management is configured (e.g., Redis).
|
||||
- [ ] `PERMANENT_SESSION_LIFETIME` is set to a short duration (e.g., 8 hours).
|
||||
- [ ] All session cookie security flags (`Secure`, `HttpOnly`, `SameSite`) are enabled.
|
||||
- [ ] `DEBUG` mode is set to `False`.
|
||||
- [ ] Talisman is explicitly enabled and configured with a strict Content Security Policy.
|
||||
- [ ] Database connections use dedicated, limited-privilege accounts.
|
||||
- [ ] Authentication is integrated with an enterprise identity provider (OAuth/LDAP).
|
||||
- [ ] A Web Application Firewall (WAF) is deployed in front of Superset.
|
||||
- [ ] Logging is configured and logs are shipped to a central monitoring system.
|
||||
|
||||
#### **Ongoing Maintenance:**
|
||||
|
||||
- [ ] Regularly update to the latest major or minor versions of Superset. Those versions receive up-to-date security patches.
|
||||
- [ ] Rotate the `SUPERSET_SECRET_KEY` periodically (e.g., quarterly) and after any potential security incident.
|
||||
- [ ] Conduct quarterly access reviews for all users.
|
||||
- [ ] Assuming logging and monitoring is in place, review security monitoring alerts weekly.
|
||||
|
||||
### **Appendix B: `SECRET_KEY` Rotation and Compromise Response**
|
||||
|
||||
**Why and When to Rotate the `SECRET_KEY`**
|
||||
Rotating the `SUPERSET_SECRET_KEY` is a critical security procedure. It is mandatory after a known or suspected compromise and is a best practice when an employee with access to the key departs. While periodic rotation can limit the window of exposure for an unknown leak, it is a high-impact operation that will invalidate all user sessions and requires careful execution to avoid breaking your instance. The principles behind managing this key align with general best practices for cryptographic storage, which are further detailed in the OWASP Cryptographic Storage Cheat Sheet here: https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html
|
||||
|
||||
**Procedure for Rotating the Key**
|
||||
The procedure for safely rotating the SECRET_KEY must be followed precisely to avoid locking yourself out of your instance. The official Apache Superset documentation maintains the correct, up-to-date procedure. Please follow the official guide here:
|
||||
https://superset.apache.org/docs/configuration/configuring-superset/#rotating-to-a-newer-secret_key
|
||||
|
||||
:::resources
|
||||
- [Blog: Running Apache Superset on the Open Internet](https://preset.io/blog/running-apache-superset-on-the-open-internet-a-report-from-the-fireline/)
|
||||
- [Blog: How Security Vulnerabilities are Reported & Handled in Apache Superset](https://preset.io/blog/how-security-vulnerabilities-are-reported-and-handled-in-apache-superset/)
|
||||
:::
|
||||
@@ -1,452 +0,0 @@
|
||||
---
|
||||
title: Security Configurations
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
Authentication and authorization in Superset is handled by Flask AppBuilder (FAB), an application development framework
|
||||
built on top of Flask. FAB provides authentication, user management, permissions and roles.
|
||||
Please read its [Security documentation](https://flask-appbuilder.readthedocs.io/en/latest/security.html).
|
||||
|
||||
### Provided Roles
|
||||
|
||||
Superset ships with a set of roles that are handled by Superset itself. You can assume
|
||||
that these roles will stay up-to-date as Superset evolves (and as you update Superset versions).
|
||||
|
||||
Even though **Admin** users have the ability, we don't recommend altering the
|
||||
permissions associated with each role (e.g. by removing or adding permissions to them). The permissions
|
||||
associated with each role will be re-synchronized to their original values when you run
|
||||
the **superset init** command (often done between Superset versions).
|
||||
|
||||
A table with the permissions for these roles can be found at [/RESOURCES/STANDARD_ROLES.md](https://github.com/apache/superset/blob/master/RESOURCES/STANDARD_ROLES.md).
|
||||
|
||||
### Admin
|
||||
|
||||
Admins have all possible rights, including granting or revoking rights from other
|
||||
users and altering other people’s slices and dashboards.
|
||||
|
||||
### Alpha
|
||||
|
||||
Alpha users have access to all data sources, but they cannot grant or revoke access
|
||||
from other users. They are also limited to altering the objects that they own. Alpha users can add and alter data sources.
|
||||
|
||||
### Gamma
|
||||
|
||||
Gamma users have limited access. They can only consume data coming from data sources
|
||||
they have been given access to through another complementary role. They only have access to
|
||||
view the slices and dashboards made from data sources that they have access to. Currently Gamma
|
||||
users are not able to alter or add data sources. We assume that they are mostly content consumers, though they can create slices and dashboards.
|
||||
|
||||
Also note that when Gamma users look at the dashboards and slices list view, they will
|
||||
only see the objects that they have access to.
|
||||
|
||||
### sql_lab
|
||||
|
||||
The **sql_lab** role grants access to SQL Lab. Note that while **Admin** users have access
|
||||
to all databases by default, both **Alpha** and **Gamma** users need to be given access on a per database basis.
|
||||
|
||||
### Public
|
||||
|
||||
The **Public** role is the most restrictive built-in role, designed specifically for anonymous/unauthenticated
|
||||
users who need to view dashboards. It provides minimal read-only access for:
|
||||
|
||||
- Viewing dashboards and charts
|
||||
- Using interactive dashboard filters
|
||||
- Accessing dashboard and chart permalinks
|
||||
- Reading embedded dashboards
|
||||
- Viewing annotations on charts
|
||||
|
||||
The Public role explicitly excludes:
|
||||
- Any write permissions on dashboards, charts, or datasets
|
||||
- SQL Lab access
|
||||
- Share functionality
|
||||
- User profile or admin features
|
||||
- Menu access to most Superset features
|
||||
|
||||
Anonymous users are automatically assigned the Public role when `AUTH_ROLE_PUBLIC` is configured
|
||||
(a Flask-AppBuilder setting). The `PUBLIC_ROLE_LIKE` setting is **optional** and controls what
|
||||
permissions are synced to the Public role when you run `superset init`:
|
||||
|
||||
```python
|
||||
# Optional: Sync sensible default permissions to the Public role
|
||||
PUBLIC_ROLE_LIKE = "Public"
|
||||
|
||||
# Alternative: Copy permissions from Gamma for broader access
|
||||
# PUBLIC_ROLE_LIKE = "Gamma"
|
||||
```
|
||||
|
||||
If you prefer to manually configure the Public role's permissions (or use `DASHBOARD_RBAC` to
|
||||
grant access at the dashboard level), you do not need to set `PUBLIC_ROLE_LIKE`.
|
||||
|
||||
**Important notes:**
|
||||
|
||||
- **Data access is still required:** The Public role only grants UI/API permissions. You must
|
||||
also grant access to specific datasets necessary to view a dashboard. As with other roles,
|
||||
this can be done in two ways:
|
||||
|
||||
- **Without `DASHBOARD_RBAC`:** Dashboards only appear in the list and are accessible if
|
||||
the user has permission to at least one of their datasets. Grant dataset access by editing
|
||||
the Public role in the Superset UI (Menu → Security → List Roles → Public) and adding the
|
||||
relevant data sources. All published dashboards using those datasets become visible.
|
||||
|
||||
- **With `DASHBOARD_RBAC` enabled:** Anonymous users will only see dashboards where the
|
||||
"Public" role has been explicitly added in the dashboard's properties. Dataset permissions
|
||||
are not required—DASHBOARD_RBAC handles the cascading permissions check. This provides
|
||||
fine-grained control over which dashboards are publicly visible.
|
||||
|
||||
- **Role synchronization:** Built-in role permissions (Admin, Alpha, Gamma, sql_lab, and Public
|
||||
when `PUBLIC_ROLE_LIKE = "Public"`) are synchronized when you run `superset init`. Any manual
|
||||
permission edits to these roles may be overwritten during upgrades. To customize the Public
|
||||
role permissions, you can either:
|
||||
- Edit the Public role directly and avoid setting `PUBLIC_ROLE_LIKE` (permissions won't be
|
||||
overwritten by `superset init`)
|
||||
- Copy the Public role via "Copy Role" in the Superset web UI, save it under a different name
|
||||
(e.g., "Public_Custom"), customize the permissions, then update **both** configs:
|
||||
`PUBLIC_ROLE_LIKE = "Public_Custom"` and `AUTH_ROLE_PUBLIC = "Public_Custom"`
|
||||
|
||||
### Managing Data Source Access for Gamma Roles
|
||||
|
||||
Here’s how to provide users access to only specific datasets. First make sure the users with
|
||||
limited access have [only] the Gamma role assigned to them. Second, create a new role (Menu -> Security -> List Roles) and click the + sign.
|
||||
|
||||
This new window allows you to give this new role a name, attribute it to users and select the
|
||||
tables in the **Permissions** dropdown. To select the data sources you want to associate with this role, simply click on the dropdown and use the typeahead to search for your table names.
|
||||
|
||||
You can then confirm with users assigned to the **Gamma** role that they see the
|
||||
objects (dashboards and slices) associated with the tables you just extended them.
|
||||
|
||||
### Dashboard Access Control
|
||||
|
||||
Access to dashboards is managed via owners (users that have edit permissions to the dashboard).
|
||||
Non-owner user access can be managed in two ways. Note that dashboards must be published to be
|
||||
visible to other users.
|
||||
|
||||
#### Dataset-Based Access (Default)
|
||||
|
||||
By default, users can view published dashboards if they have access to at least one dataset
|
||||
used in that dashboard. Grant dataset access by adding the relevant data source permissions
|
||||
to a role (Menu → Security → List Roles).
|
||||
|
||||
This is the simplest approach but provides all-or-nothing access based on dataset permissions—
|
||||
if a user has access to a dataset, they can see all published dashboards using that dataset.
|
||||
|
||||
#### Dashboard-Level Access (DASHBOARD_RBAC)
|
||||
|
||||
For fine-grained control over which dashboards specific roles can access, enable the
|
||||
`DASHBOARD_RBAC` feature flag:
|
||||
|
||||
```python
|
||||
FEATURE_FLAGS = {
|
||||
"DASHBOARD_RBAC": True,
|
||||
}
|
||||
```
|
||||
|
||||
With this enabled, you can assign specific roles to each dashboard in its properties. Users
|
||||
will only see dashboards where their role is explicitly added.
|
||||
|
||||
**Important considerations:**
|
||||
- Dashboard access **bypasses** dataset-level checks—granting a role access to a dashboard
|
||||
implicitly grants read access to all charts and datasets in that dashboard
|
||||
- Dashboards without any assigned roles fall back to dataset-based access
|
||||
- The dashboard must still be published to be visible
|
||||
|
||||
This feature is particularly useful for:
|
||||
- Making specific dashboards public while keeping others private
|
||||
- Granting access to dashboards without exposing the underlying datasets for other uses
|
||||
- Creating dashboard-specific access patterns that don't align with dataset ownership
|
||||
|
||||
### SQL Execution Security Considerations
|
||||
|
||||
Apache Superset includes features designed to provide safeguards when interacting with connected databases, such as the `DISALLOWED_SQL_FUNCTIONS` configuration setting. This aims to prevent the execution of potentially harmful database functions or system variables directly from Superset interfaces like SQL Lab.
|
||||
|
||||
However, it is crucial to understand the following:
|
||||
|
||||
**Superset is Not a Database Firewall**: Superset's built-in checks, like `DISALLOWED_SQL_FUNCTIONS`, provide a layer of protection but cannot guarantee complete security against all database-level threats or advanced bypass techniques (like specific comment injection methods). They should be viewed as a supplement to, not a replacement for, robust database security.
|
||||
|
||||
**Configuration is Key**: The effectiveness of Superset's safeguards heavily depends on proper configuration by the Superset administrator. This includes maintaining the `DISALLOWED_SQL_FUNCTIONS` list, carefully managing feature flags (like `ENABLE_TEMPLATE_PROCESSING`), and configuring other security settings appropriately.
|
||||
|
||||
**Database Security is Paramount**: The ultimate responsibility for securing database access, controlling permissions, and preventing unauthorized function execution lies with the database administrators (DBAs) and security teams managing the underlying database instance.
|
||||
|
||||
**Recommended Database Practices**: We strongly recommend implementing security best practices at the database level, including:
|
||||
* **Least Privilege**: Connecting Superset using dedicated database user accounts with the minimum permissions required for Superset's operation (typically read-only access to necessary schemas/tables).
|
||||
* **Database Roles & Permissions**: Utilizing database-native roles and permissions to restrict access to sensitive functions, system variables (like `@@hostname`), schemas, or tables.
|
||||
* **Network Security**: Employing network-level controls like database firewalls or proxies to restrict connections.
|
||||
* **Auditing**: Enabling database-level auditing to monitor executed queries and access patterns.
|
||||
|
||||
By combining Superset's configurable safeguards with strong database-level security practices, you can achieve a more robust and layered security posture.
|
||||
|
||||
### REST API for user & role management
|
||||
|
||||
Flask-AppBuilder supports a REST API for user CRUD,
|
||||
but this feature is in beta and is not enabled by default in Superset.
|
||||
To enable this feature, set the following in your Superset configuration:
|
||||
|
||||
```python
|
||||
FAB_ADD_SECURITY_API = True
|
||||
```
|
||||
|
||||
Once configured, the documentation for additional "Security" endpoints will be visible in Swagger for you to explore.
|
||||
|
||||
### Customizing Permissions
|
||||
|
||||
The permissions exposed by FAB are very granular and allow for a great level of
|
||||
customization. FAB creates many permissions automatically for each model that is
|
||||
created (can_add, can_delete, can_show, can_edit, …) as well as for each view.
|
||||
On top of that, Superset can expose more granular permissions like **all_datasource_access**.
|
||||
|
||||
**We do not recommend altering the 3 base roles as there are a set of assumptions that
|
||||
Superset is built upon**. It is possible though for you to create your own roles, and union them to existing ones.
|
||||
|
||||
### Permissions
|
||||
|
||||
Roles are composed of a set of permissions, and Superset has many categories of
|
||||
permissions. Here are the different categories of permissions:
|
||||
|
||||
- Model & Action: models are entities like Dashboard, Slice, or User. Each model has
|
||||
a fixed set of permissions, like **can_edit**, **can_show**, **can_delete**, **can_list**, **can_add**,
|
||||
and so on. For example, you can allow a user to delete dashboards by adding **can_delete** on
|
||||
Dashboard entity to a role and granting this user that role.
|
||||
- Views: views are individual web pages, like the Explore view or the SQL Lab view.
|
||||
When granted to a user, they will see that view in its menu items, and be able to load that page.
|
||||
- Data source: For each data source, a permission is created. If the user does not have the
|
||||
`all_datasource_access permission` granted, the user will only be able to see Slices or explore the data sources that are granted to them
|
||||
- Database: Granting access to a database allows for the user to access all
|
||||
data sources within that database, and will enable the user to query that
|
||||
database in SQL Lab, provided that the SQL Lab specific permission have been granted to the user
|
||||
|
||||
### Restricting Access to a Subset of Data Sources
|
||||
|
||||
We recommend giving a user the **Gamma** role plus any other roles that would add
|
||||
access to specific data sources. We recommend that you create individual roles for
|
||||
each access profile. For example, the users on the Finance team might have access to a set of
|
||||
databases and data sources; these permissions can be consolidated in a single role.
|
||||
Users with this profile then need to be assigned the **Gamma** role as a foundation to
|
||||
the models and views they can access, and that Finance role that is a collection of permissions to data objects.
|
||||
|
||||
A user can have multiple roles associated with them. For example, an executive on the Finance
|
||||
team could be granted **Gamma**, **Finance**, and the **Executive** roles. The **Executive**
|
||||
role could provide access to a set of data sources and dashboards made available only to executives.
|
||||
In the **Dashboards** view, a user can only see the ones they have access to
|
||||
based on the roles and permissions that were attributed.
|
||||
|
||||
### Row Level Security
|
||||
|
||||
Using Row Level Security filters (under the **Security** menu) you can create filters
|
||||
that are assigned to a particular table, as well as a set of roles.
|
||||
If you want members of the Finance team to only have access to
|
||||
rows where `department = "finance"`, you could:
|
||||
|
||||
- Create a Row Level Security filter with that clause (`department = "finance"`)
|
||||
- Then assign the clause to the **Finance** role and the table it applies to
|
||||
|
||||
The **clause** field, which can contain arbitrary text, is then added to the generated
|
||||
SQL statement’s WHERE clause. So you could even do something like create a filter
|
||||
for the last 30 days and apply it to a specific role, with a clause
|
||||
like `date_field > DATE_SUB(NOW(), INTERVAL 30 DAY)`. It can also support
|
||||
multiple conditions: `client_id = 6` AND `advertiser="foo"`, etc.
|
||||
|
||||
All relevant Row level security filters will be combined together (under the hood,
|
||||
the different SQL clauses are combined using AND statements). This means it's
|
||||
possible to create a situation where two roles conflict in such a way as to limit a table subset to empty.
|
||||
|
||||
For example, the filters `client_id=4` and `client_id=5`, applied to a role,
|
||||
will result in users of that role having `client_id=4` AND `client_id=5`
|
||||
added to their query, which can never be true.
|
||||
|
||||
### User Sessions
|
||||
|
||||
Superset uses [Flask](https://pypi.org/project/Flask/)
|
||||
and [Flask-Login](https://pypi.org/project/Flask-Login/) for user session management.
|
||||
|
||||
Session cookies are used to maintain session info and user state between requests,
|
||||
although they do not contain personal user information they serve the purpose of identifying
|
||||
a user session on the server side.
|
||||
The session cookie is encrypted with the application `SECRET_KEY` and cannot be read by the client.
|
||||
So it's very important to keep the `SECRET_KEY` secret and set to a secure unique complex random value.
|
||||
|
||||
Flask and Flask-Login offer a number of configuration options to control session behavior.
|
||||
|
||||
- Relevant Flask settings:
|
||||
|
||||
`SESSION_COOKIE_HTTPONLY`: (default: `False`): Controls if cookies should be set with the `HttpOnly` flag.
|
||||
|
||||
`SESSION_COOKIE_SECURE`: (default: `False`) Browsers will only send cookies with requests over
|
||||
HTTPS if the cookie is marked “secure”. The application must be served over HTTPS for this to make sense.
|
||||
|
||||
`SESSION_COOKIE_SAMESITE`: (default: "Lax") Prevents the browser from sending this cookie along with cross-site requests.
|
||||
|
||||
`PERMANENT_SESSION_LIFETIME`: (default: "31 days") The lifetime of a permanent session as a `datetime.timedelta` object.
|
||||
|
||||
#### Switching to server side sessions
|
||||
|
||||
Server side sessions offer benefits over client side sessions on security and performance.
|
||||
By enabling server side sessions, the session data is stored server side and only a session ID
|
||||
is sent to the client. When a user logs in, a session is created server side and the session ID
|
||||
is sent to the client in a cookie. The client will send the session ID with each request and the
|
||||
server will use it to retrieve the session data.
|
||||
On logout, the session is destroyed server side and the session cookie is deleted on the client side.
|
||||
This reduces the risk for replay attacks and session hijacking.
|
||||
|
||||
Superset uses [Flask-Session](https://flask-session.readthedocs.io/en/latest/) to manage server side sessions.
|
||||
To enable this extension you have to set:
|
||||
|
||||
``` python
|
||||
SESSION_SERVER_SIDE = True
|
||||
```
|
||||
|
||||
Flask-Session offers multiple backend session interfaces for Flask, here's an example for Redis:
|
||||
|
||||
``` python
|
||||
from redis import Redis
|
||||
|
||||
SESSION_TYPE = "redis"
|
||||
SESSION_REDIS = Redis(host="redis", port=6379, db=0)
|
||||
# sign the session cookie sid
|
||||
SESSION_USE_SIGNER = True
|
||||
```
|
||||
|
||||
### Content Security Policy (CSP)
|
||||
|
||||
Superset uses the [Talisman](https://pypi.org/project/flask-talisman/) extension to enable implementation of a
|
||||
[Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), an added
|
||||
layer of security that helps to detect and mitigate certain types of attacks, including
|
||||
Cross-Site Scripting (XSS) and data injection attacks.
|
||||
|
||||
A CSP makes it possible for server administrators to reduce or eliminate the vectors by which XSS can
|
||||
occur by specifying the domains that the browser should consider to be valid sources of executable scripts.
|
||||
A CSP-compatible browser will then only execute scripts loaded in source files received from those allowed domains,
|
||||
ignoring all other scripts (including inline scripts and event-handling HTML attributes).
|
||||
|
||||
A policy is described using a series of policy directives, each of which describes the policy for
|
||||
a certain resource type or policy area. You can check possible directives
|
||||
[here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy).
|
||||
|
||||
It's extremely important to correctly configure a Content Security Policy when deploying Superset to
|
||||
prevent many types of attacks. Superset provides two variables in `config.py` for deploying a CSP:
|
||||
|
||||
- `TALISMAN_ENABLED` defaults to `True`; set this to `False` in order to disable CSP
|
||||
- `TALISMAN_CONFIG` holds the actual the policy definition (*see example below*) as well as any
|
||||
other arguments to be passed to Talisman.
|
||||
|
||||
When running in production mode, Superset will check at startup for the presence
|
||||
of a CSP. If one is not found, it will issue a warning with the security risks. For environments
|
||||
where CSP policies are defined outside of Superset using other software, administrators can disable
|
||||
this warning using the `CONTENT_SECURITY_POLICY_WARNING` key in `config.py`.
|
||||
|
||||
#### CSP Requirements
|
||||
|
||||
- Superset needs the `style-src unsafe-inline` CSP directive in order to operate.
|
||||
|
||||
```
|
||||
style-src 'self' 'unsafe-inline'
|
||||
```
|
||||
|
||||
- Only scripts marked with a [nonce](https://content-security-policy.com/nonce/) can be loaded and executed.
|
||||
Nonce is a random string automatically generated by Talisman on each page load.
|
||||
You can get current nonce value by calling jinja macro `csp_nonce()`.
|
||||
|
||||
```html
|
||||
<script nonce="{{ csp_nonce() }}">
|
||||
/* my script */
|
||||
</script>
|
||||
```
|
||||
|
||||
- Some dashboards load images using data URIs and require `data:` in their `img-src`
|
||||
|
||||
```
|
||||
img-src 'self' data:
|
||||
```
|
||||
|
||||
- MapBox charts use workers and need to connect to MapBox servers in addition to the Superset origin
|
||||
|
||||
```
|
||||
worker-src 'self' blob:
|
||||
connect-src 'self' https://api.mapbox.com https://events.mapbox.com
|
||||
```
|
||||
|
||||
- Cartodiagram charts request map data (image and json) from external resources that can be edited by users,
|
||||
and therefore either require a list of allowed domains to request from or a wildcard (`'*'`) for `img-src` and `connect-src`.
|
||||
|
||||
- Other CSP directives default to `'self'` to limit content to the same origin as the Superset server.
|
||||
|
||||
In order to adjust provided CSP configuration to your needs, follow the instructions and examples provided in
|
||||
[Content Security Policy Reference](https://content-security-policy.com/)
|
||||
|
||||
#### Other Talisman security considerations
|
||||
|
||||
Setting `TALISMAN_ENABLED = True` will invoke Talisman's protection with its default arguments,
|
||||
of which `content_security_policy` is only one. Those can be found in the
|
||||
[Talisman documentation](https://pypi.org/project/flask-talisman/) under *Options*.
|
||||
These generally improve security, but administrators should be aware of their existence.
|
||||
|
||||
In particular, the option of `force_https = True` (`False` by default) may break Superset's Alerts & Reports
|
||||
if workers are configured to access charts via a `WEBDRIVER_BASEURL` beginning
|
||||
with `http://`. As long as a Superset deployment enforces https upstream, e.g.,
|
||||
through a load balancer or application gateway, it should be acceptable to keep this
|
||||
option disabled. Otherwise, you may want to enable `force_https` like this:
|
||||
|
||||
```python
|
||||
TALISMAN_CONFIG = {
|
||||
"force_https": True,
|
||||
"content_security_policy": { ...
|
||||
```
|
||||
|
||||
#### Configuring Talisman in Superset
|
||||
|
||||
Talisman settings in Superset can be modified using superset_config.py. If you need to adjust security policies, you can override the default configuration.
|
||||
|
||||
Example: Overriding Talisman Configuration in superset_config.py for loading images form s3 or other external sources.
|
||||
|
||||
```python
|
||||
TALISMAN_CONFIG = {
|
||||
"content_security_policy": {
|
||||
"base-uri": ["'self'"],
|
||||
"default-src": ["'self'"],
|
||||
"img-src": [
|
||||
"'self'",
|
||||
"blob:",
|
||||
"data:",
|
||||
"https://apachesuperset.gateway.scarf.sh",
|
||||
"https://static.scarf.sh/",
|
||||
# "https://cdn.brandfolder.io", # Uncomment when SLACK_ENABLE_AVATARS is True # noqa: E501
|
||||
"ows.terrestris.de",
|
||||
"aws.s3.com", # Add Your Bucket or external data source
|
||||
],
|
||||
"worker-src": ["'self'", "blob:"],
|
||||
"connect-src": [
|
||||
"'self'",
|
||||
"https://api.mapbox.com",
|
||||
"https://events.mapbox.com",
|
||||
],
|
||||
"object-src": "'none'",
|
||||
"style-src": [
|
||||
"'self'",
|
||||
"'unsafe-inline'",
|
||||
],
|
||||
"script-src": ["'self'", "'strict-dynamic'"],
|
||||
},
|
||||
"content_security_policy_nonce_in": ["script-src"],
|
||||
"force_https": False,
|
||||
"session_cookie_secure": False,
|
||||
}
|
||||
```
|
||||
|
||||
For more information on setting up Talisman, please refer to
|
||||
https://superset.apache.org/docs/configuration/networking-settings/#changing-flask-talisman-csp.
|
||||
|
||||
### Reporting Security Vulnerabilities
|
||||
|
||||
Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its
|
||||
software projects. Apache Superset is highly sensitive and forthcoming to issues pertaining to its
|
||||
features and functionality.
|
||||
|
||||
If you have apprehensions regarding Superset security or you discover vulnerability or potential
|
||||
threat, don’t hesitate to get in touch with the Apache Security Team by dropping a mail at
|
||||
security@apache.org. In the mail, specify the project name Superset with the description of the
|
||||
issue or potential threat. You are also urged to recommend the way to reproduce and replicate the
|
||||
issue. The security team and the Superset community will get back to you after assessing and
|
||||
analysing the findings.
|
||||
|
||||
PLEASE PAY ATTENTION to report the security issue on the security email before disclosing it on
|
||||
public domain. The ASF Security Team maintains a page with the description of how vulnerabilities
|
||||
and potential threats are handled, check [their web page](https://apache.org/security/committers.html)
|
||||
for more details.
|
||||
@@ -31,7 +31,7 @@ your existing SQL-speaking database or data store.
|
||||
|
||||
First things first, we need to add the connection credentials to your database to be able
|
||||
to query and visualize data from it. If you're using Superset locally via
|
||||
[Docker compose](/docs/installation/docker-compose), you can
|
||||
[Docker compose](/admin-docs/installation/docker-compose), you can
|
||||
skip this step because a Postgres database, named **examples**, is included and
|
||||
pre-configured in Superset for you.
|
||||
|
||||
@@ -193,7 +193,7 @@ Access to dashboards is managed via owners and permissions. Non-owner access can
|
||||
through dataset permissions or dashboard-level roles (using the `DASHBOARD_RBAC` feature flag).
|
||||
|
||||
For detailed information on configuring dashboard access, see the
|
||||
[Dashboard Access Control](/docs/security/security#dashboard-access-control) section in the
|
||||
[Dashboard Access Control](/admin-docs/security/security#dashboard-access-control) section in the
|
||||
Security documentation.
|
||||
|
||||
<img src={useBaseUrl("/img/tutorial/tutorial_dashboard_access.png" )} />
|
||||
|
||||
250
docs/docs/using-superset/sql-templating.mdx
Normal file
250
docs/docs/using-superset/sql-templating.mdx
Normal file
@@ -0,0 +1,250 @@
|
||||
---
|
||||
title: SQL Templating
|
||||
sidebar_position: 4
|
||||
description: Use Jinja templates in SQL Lab and virtual datasets to create dynamic queries
|
||||
keywords: [sql templating, jinja, sql lab, virtual datasets, dynamic queries]
|
||||
---
|
||||
|
||||
{/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/}
|
||||
|
||||
# SQL Templating
|
||||
|
||||
Superset supports [Jinja templating](https://jinja.palletsprojects.com/) in SQL Lab queries and virtual datasets. This allows you to write dynamic SQL that responds to filters, user context, and URL parameters.
|
||||
|
||||
:::note
|
||||
SQL templating must be enabled by your administrator via the `ENABLE_TEMPLATE_PROCESSING` feature flag.
|
||||
For advanced configuration options, see the [SQL Templating Configuration Guide](/admin-docs/configuration/sql-templating).
|
||||
:::
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Jinja templates use double curly braces `{{ }}` for expressions and `{% %}` for logic blocks.
|
||||
|
||||
### Using Parameters
|
||||
|
||||
You can define parameters in SQL Lab via the **Parameters** menu as JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"my_table": "sales",
|
||||
"start_date": "2024-01-01"
|
||||
}
|
||||
```
|
||||
|
||||
Then reference them in your query:
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM {{ my_table }}
|
||||
WHERE order_date >= '{{ start_date }}'
|
||||
```
|
||||
|
||||
### Conditional Logic
|
||||
|
||||
Use Jinja's logic blocks for conditional SQL:
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM orders
|
||||
WHERE 1 = 1
|
||||
{% if start_date %}
|
||||
AND order_date >= '{{ start_date }}'
|
||||
{% endif %}
|
||||
{% if end_date %}
|
||||
AND order_date < '{{ end_date }}'
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
## Available Macros
|
||||
|
||||
Superset provides built-in macros for common use cases.
|
||||
|
||||
### User Context
|
||||
|
||||
| Macro | Description |
|
||||
|-------|-------------|
|
||||
| `{{ current_username() }}` | Returns the logged-in user's username |
|
||||
| `{{ current_user_id() }}` | Returns the logged-in user's account ID |
|
||||
| `{{ current_user_email() }}` | Returns the logged-in user's email |
|
||||
| `{{ current_user_roles() }}` | Returns an array of the user's roles |
|
||||
|
||||
**Example: Row-level filtering by user**
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM sales_data
|
||||
WHERE sales_rep = '{{ current_username() }}'
|
||||
```
|
||||
|
||||
**Example: Role-based access**
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM users
|
||||
WHERE role IN {{ current_user_roles()|where_in }}
|
||||
```
|
||||
|
||||
### Filter Values
|
||||
|
||||
Access dashboard and chart filter values in your queries:
|
||||
|
||||
| Macro | Description |
|
||||
|-------|-------------|
|
||||
| `{{ filter_values('column') }}` | Returns filter values as a list |
|
||||
| `{{ get_filters('column') }}` | Returns filters with operators |
|
||||
|
||||
**Example: Using filter values**
|
||||
|
||||
```sql
|
||||
SELECT product, SUM(revenue) as total
|
||||
FROM sales
|
||||
WHERE region IN {{ filter_values('region')|where_in }}
|
||||
GROUP BY product
|
||||
```
|
||||
|
||||
The `where_in` filter converts the list to SQL format: `('value1', 'value2', 'value3')`
|
||||
|
||||
### Time Filters
|
||||
|
||||
For charts with time range filters:
|
||||
|
||||
| Macro | Description |
|
||||
|-------|-------------|
|
||||
| `{{ get_time_filter('column') }}` | Returns time filter with `from_expr` and `to_expr` |
|
||||
|
||||
**Example: Time-filtered virtual dataset**
|
||||
|
||||
```sql
|
||||
{% set time_filter = get_time_filter("order_date", default="Last 7 days") %}
|
||||
SELECT *
|
||||
FROM orders
|
||||
WHERE order_date >= {{ time_filter.from_expr }}
|
||||
AND order_date < {{ time_filter.to_expr }}
|
||||
```
|
||||
|
||||
### URL Parameters
|
||||
|
||||
Pass custom values via URL query strings:
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM orders
|
||||
WHERE country = '{{ url_param('country') }}'
|
||||
```
|
||||
|
||||
Access via: `superset.example.com/sqllab?country=US`
|
||||
|
||||
### Reusing Dataset Definitions
|
||||
|
||||
Query existing datasets by ID:
|
||||
|
||||
```sql
|
||||
-- Query a dataset (ID 42) as a table
|
||||
SELECT * FROM {{ dataset(42) }} LIMIT 100
|
||||
|
||||
-- Include computed metrics
|
||||
SELECT * FROM {{ dataset(42, include_metrics=True) }}
|
||||
```
|
||||
|
||||
Reuse metric definitions across queries:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
category,
|
||||
{{ metric('total_revenue') }} as revenue
|
||||
FROM sales
|
||||
GROUP BY category
|
||||
```
|
||||
|
||||
## Testing Templates in SQL Lab
|
||||
|
||||
Some variables like `from_dttm` and `filter_values()` only work when filters are applied from dashboards or charts. To test in SQL Lab:
|
||||
|
||||
**Option 1: Use defaults**
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM orders
|
||||
WHERE date >= '{{ from_dttm | default("2024-01-01", true) }}'
|
||||
```
|
||||
|
||||
**Option 2: Set test parameters**
|
||||
|
||||
Add to the Parameters menu:
|
||||
|
||||
```json
|
||||
{
|
||||
"_filters": [
|
||||
{"col": "region", "op": "IN", "val": ["US", "EU"]}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Option 3: Use `{% set %}`**
|
||||
|
||||
```sql
|
||||
{% set start_date = "2024-01-01" %}
|
||||
SELECT * FROM orders WHERE date >= '{{ start_date }}'
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Dynamic Table Selection
|
||||
|
||||
```sql
|
||||
{% set table_name = url_param('table') or 'default_table' %}
|
||||
SELECT * FROM {{ table_name }}
|
||||
```
|
||||
|
||||
### User-Specific Data Access
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM sensitive_data
|
||||
WHERE department IN (
|
||||
SELECT department
|
||||
FROM user_permissions
|
||||
WHERE username = '{{ current_username() }}'
|
||||
)
|
||||
```
|
||||
|
||||
### Time-Based Partitioning
|
||||
|
||||
```sql
|
||||
{% set time_filter = get_time_filter("event_date", remove_filter=True) %}
|
||||
SELECT *
|
||||
FROM events
|
||||
WHERE event_date >= {{ time_filter.from_expr }}
|
||||
AND event_date < {{ time_filter.to_expr }}
|
||||
```
|
||||
|
||||
Using `remove_filter=True` applies the filter in the inner query for better performance.
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `|where_in` filter to convert lists to SQL `IN` clauses
|
||||
- Use `|tojson` to serialize arrays as JSON strings
|
||||
- Test queries with explicit parameter values before relying on filter context
|
||||
- For complex templating needs, ask your administrator about custom Jinja macros
|
||||
|
||||
:::resources
|
||||
- [Admin Guide: SQL Templating Configuration](/admin-docs/configuration/sql-templating)
|
||||
- [Blog: Intro to Jinja Templating in Apache Superset](https://preset.io/blog/intro-jinja-templating-apache-superset/)
|
||||
:::
|
||||
Reference in New Issue
Block a user