Compare commits
2 Commits
fix/mask-s
...
fix/scarf-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31aa3bd80a | ||
|
|
a48d5fefaf |
14
.github/CODEOWNERS
vendored
@@ -1,5 +1,7 @@
|
||||
# Notify all committers of DB migration changes, per SIP-59
|
||||
|
||||
# https://github.com/apache/superset/issues/13351
|
||||
|
||||
/superset/migrations/ @mistercrunch @michael-s-molina @betodealmeida @eschutho @sadpandajoe
|
||||
|
||||
# Notify some committers of changes in the components
|
||||
@@ -10,30 +12,28 @@
|
||||
|
||||
# Notify Helm Chart maintainers about changes in it
|
||||
|
||||
/helm/superset/ @dpgaspar @villebro @nytai @michael-s-molina @mistercrunch @rusackas @Antonio-RiveroMartnez @hainenber
|
||||
/helm/superset/ @craig-rueda @dpgaspar @villebro @nytai @michael-s-molina @mistercrunch @rusackas @Antonio-RiveroMartnez
|
||||
|
||||
# Notify E2E test maintainers of changes
|
||||
|
||||
/superset-frontend/playwright/ @sadpandajoe @geido @eschutho @rusackas @mistercrunch
|
||||
/superset-frontend/cypress-base/ @sadpandajoe @geido @eschutho @rusackas @mistercrunch
|
||||
/superset-frontend/cypress-base/ @sadpandajoe @geido @eschutho @rusackas @betodealmeida @mistercrunch
|
||||
|
||||
# Notify PMC members of changes to GitHub Actions
|
||||
|
||||
/.github/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @kgabryje @sha174n @dpgaspar @sadpandajoe @hainenber
|
||||
/.github/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar @sadpandajoe @hainenber
|
||||
|
||||
# Notify PMC members of changes to CI-executed scripts (supply-chain risk:
|
||||
# scripts/ files run directly in CI workflows and can execute arbitrary code)
|
||||
|
||||
/scripts/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @kgabryje @dpgaspar @sha174n @sadpandajoe @hainenber
|
||||
/scripts/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar @sadpandajoe @hainenber
|
||||
|
||||
# Notify PMC members of changes to required GitHub Actions
|
||||
|
||||
/.asf.yaml @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @kgabryje @dpgaspar @sha174n @Antonio-RiveroMartnez
|
||||
/.asf.yaml @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar @Antonio-RiveroMartnez
|
||||
|
||||
# Maps are a finicky contribution process we care about
|
||||
|
||||
**/*.geojson @villebro @rusackas
|
||||
**/*.ipynb @villebro @rusackas
|
||||
/superset-frontend/plugins/legacy-plugin-chart-country-map/ @villebro @rusackas
|
||||
|
||||
# Notify translation maintainers of changes to translations
|
||||
|
||||
2
.github/actions/setup-supersetbot/action.yml
vendored
@@ -17,7 +17,6 @@ runs:
|
||||
- name: Install supersetbot from npm
|
||||
if: ${{ inputs.from-npm == 'true' }}
|
||||
shell: bash
|
||||
# zizmor: ignore[adhoc-packages] - supersetbot is a first-party Apache CLI (apache-superset/supersetbot) installed globally as a tool; a global CLI install has no application manifest/lockfile context
|
||||
run: npm install -g supersetbot
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
@@ -32,7 +31,6 @@ runs:
|
||||
if: ${{ inputs.from-npm == 'false' }}
|
||||
shell: bash
|
||||
working-directory: supersetbot
|
||||
# zizmor: ignore[adhoc-packages] - installs the locally packed supersetbot tarball built from the trusted apache-superset/supersetbot checkout; no lockfile applies to a global CLI install
|
||||
run: |
|
||||
# simple trick to install globally with dependencies
|
||||
npm pack
|
||||
|
||||
300
.github/dependabot.yml
vendored
@@ -10,7 +10,11 @@ updates:
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
ignore:
|
||||
- dependency-name: "react-error-boundary"
|
||||
- dependency-name: "@rjsf/*"
|
||||
# remark-gfm v4+ requires react-markdown v9+, which needs React 18
|
||||
- dependency-name: "remark-gfm"
|
||||
- dependency-name: "react-markdown"
|
||||
# TODO: remove below entries until React >= 19.0.0
|
||||
- dependency-name: "react-icons"
|
||||
# JSDOM v30 doesn't play well with Jest v30
|
||||
@@ -46,6 +50,7 @@ updates:
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
open-pull-requests-limit: 10
|
||||
@@ -73,6 +78,8 @@ updates:
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/docs/"
|
||||
ignore:
|
||||
- dependency-name: "react-error-boundary"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 10
|
||||
@@ -102,3 +109,296 @@ updates:
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
# Now for all of our plugins and packages!
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-calendar/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-partition/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-world-map/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-pivot-table/"
|
||||
ignore:
|
||||
# TODO: remove below entries until React >= 19.0.0
|
||||
- dependency-name: "react-icons"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-chord/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-horizon/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-rose/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-preset-chart-deckgl/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-table/"
|
||||
ignore:
|
||||
# TODO: remove below entries until React >= 19.0.0
|
||||
- dependency-name: "react-icons"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-country-map/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-map-box/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-preset-chart-nvd3/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-word-cloud/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-paired-t-test/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-echarts/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-ag-grid-table/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-cartodiagram/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-handlebars/"
|
||||
ignore:
|
||||
# `just-handlerbars-helpers` library in plugin-chart-handlebars requires `currencyformatter`` to be < 2
|
||||
- dependency-name: "currencyformatter.js"
|
||||
update-types: ["version-update:semver-major"]
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/generator-superset/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/superset-ui-chart-controls/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/superset-ui-core/"
|
||||
ignore:
|
||||
# not until React >= 18.0.0
|
||||
- dependency-name: "react-markdown"
|
||||
- dependency-name: "remark-gfm"
|
||||
- dependency-name: "react-error-boundary"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/superset-ui-switchboard/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
2
.github/workflows/bump-python-package.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
uses: ./.github/actions/setup-supersetbot/
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }}
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
|
||||
2
.github/workflows/check-python-deps.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
- name: Login to Docker Hub
|
||||
if: steps.check.outputs.python
|
||||
continue-on-error: true
|
||||
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USER }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
4
.github/workflows/codeql-analysis.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -75,6 +75,6 @@ jobs:
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
||||
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
2
.github/workflows/generate-FOSSA-report.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||
uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "11"
|
||||
|
||||
@@ -37,10 +37,7 @@ jobs:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install Dependencies
|
||||
# Versions are pinned to avoid ad-hoc, unpinned package installs.
|
||||
# Bump deliberately when upgrading.
|
||||
# zizmor: ignore[adhoc-packages] - @action-validator is a global CLI tool installed to validate the repo's workflows; a global CLI install has no application manifest/lockfile context, and the versions are pinned above
|
||||
run: npm install -g @action-validator/core@0.6.0 @action-validator/cli@0.6.0
|
||||
run: npm install -g @action-validator/core @action-validator/cli --save-dev
|
||||
|
||||
- name: Run Script
|
||||
run: bash .github/workflows/github-action-validator.sh
|
||||
|
||||
2
.github/workflows/license-check.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||
uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "11"
|
||||
|
||||
19
.github/workflows/pre-commit.yml
vendored
@@ -32,18 +32,19 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
||||
|
||||
- name: Install helm-docs
|
||||
run: go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.14.2
|
||||
|
||||
- name: Enable brew and helm-docs
|
||||
# Add brew to the path - see https://github.com/actions/runner-images/issues/6283
|
||||
run: |
|
||||
echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
echo "HOMEBREW_PREFIX=$HOMEBREW_PREFIX" >>"${GITHUB_ENV}"
|
||||
echo "HOMEBREW_CELLAR=$HOMEBREW_CELLAR" >>"${GITHUB_ENV}"
|
||||
echo "HOMEBREW_REPOSITORY=$HOMEBREW_REPOSITORY" >>"${GITHUB_ENV}"
|
||||
brew install norwoodj/tap/helm-docs
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
@@ -62,7 +63,7 @@ jobs:
|
||||
yarn install --immutable
|
||||
|
||||
- name: Cache pre-commit environments
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit-v2-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
|
||||
4
.github/workflows/release.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
||||
|
||||
- name: Cache npm
|
||||
if: env.HAS_TAGS
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
|
||||
- name: Cache npm
|
||||
if: env.HAS_TAGS
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
id: npm-cache # use this to check for `cache-hit` (`steps.npm-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.npm-cache-dir-path.outputs.dir }}
|
||||
|
||||
7
.github/workflows/showtime-trigger.yml
vendored
@@ -2,8 +2,7 @@ name: 🎪 Superset Showtime
|
||||
|
||||
# Ultra-simple: just sync on any PR state change
|
||||
on:
|
||||
# zizmor: ignore[dangerous-triggers] - required to react to PR label changes; PR code is
|
||||
# only checked out and built after the maintainer-authorization gate (write/admin actors)
|
||||
# zizmor: ignore[dangerous-triggers] - required to react to PR label changes; this workflow does not check out or execute PR-provided code
|
||||
pull_request_target:
|
||||
types: [labeled, unlabeled, synchronize, closed]
|
||||
|
||||
@@ -157,10 +156,6 @@ jobs:
|
||||
with:
|
||||
ref: ${{ steps.check.outputs.target_sha }}
|
||||
persist-credentials: false
|
||||
# Building fork PR code is Showtime's purpose: deploys are gated on the
|
||||
# maintainer-authorization step above (write/admin actors only), so this
|
||||
# checkout is an explicit, authorized opt-in rather than an automatic one.
|
||||
allow-unsafe-pr-checkout: true
|
||||
|
||||
- name: Setup Docker Environment (only if build needed)
|
||||
if: steps.auth.outputs.authorized == 'true' && steps.check.outputs.build_needed == 'true'
|
||||
|
||||
2
.github/workflows/superset-docs-deploy.yml
vendored
@@ -71,7 +71,7 @@ jobs:
|
||||
node-version-file: "./docs/.nvmrc"
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
- uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||
- uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: "21"
|
||||
|
||||
2
.github/workflows/superset-helm-lint.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
|
||||
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
|
||||
with:
|
||||
version: v3.16.4
|
||||
|
||||
|
||||
2
.github/workflows/superset-helm-release.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
|
||||
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
|
||||
with:
|
||||
version: v3.5.4
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
- name: Login to Docker Hub
|
||||
if: ${{ steps.dependabot-metadata.outputs.package-ecosystem == 'pip' }}
|
||||
continue-on-error: true
|
||||
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USER }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
2
.pre-commit-config.yaml
Executable file → Normal file
@@ -63,7 +63,7 @@ repos:
|
||||
hooks:
|
||||
- id: prettier-frontend
|
||||
name: prettier (frontend)
|
||||
entry: bash -c 'cd superset-frontend && files=(); for f in "$@"; do files+=("${f#superset-frontend/}"); done; npx prettier --write -- "${files[@]}"' --
|
||||
entry: bash -c 'cd superset-frontend && for file in "$@"; do npx prettier --write "${file#superset-frontend/}"; done'
|
||||
language: system
|
||||
pass_filenames: true
|
||||
files: ^superset-frontend/.*\.(js|jsx|ts|tsx|css|scss|sass|json)$
|
||||
|
||||
@@ -120,7 +120,7 @@ RUN useradd --user-group -d ${SUPERSET_HOME} -m --no-log-init --shell /bin/bash
|
||||
# Some bash scripts needed throughout the layers
|
||||
COPY --chmod=755 docker/*.sh /app/docker/
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade uv
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||
|
||||
# Using uv as it's faster/simpler than pip
|
||||
RUN uv venv /app/.venv
|
||||
@@ -141,7 +141,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
|
||||
COPY superset/translations/ /app/translations_mo/
|
||||
RUN if [ "${BUILD_TRANSLATIONS}" = "true" ]; then \
|
||||
pybabel compile --use-fuzzy -d /app/translations_mo || true; \
|
||||
pybabel compile -d /app/translations_mo | true; \
|
||||
fi; \
|
||||
rm -f /app/translations_mo/*/*/*.[po,json]
|
||||
|
||||
|
||||
17
README.md
@@ -247,13 +247,16 @@ Understanding the Superset Points of View
|
||||
|
||||
- [Superset API](https://superset.apache.org/docs/rest-api)
|
||||
|
||||
<!--
|
||||
The OSS Insight "Repo Activity" widget (https://next.ossinsight.io/) was
|
||||
intentionally removed. This README is rendered on the ASF-hosted website
|
||||
(superset.apache.org), so its contents are subject to ASF's third-party
|
||||
content and CSP rules. OSS Insight has no Data Processing Agreement (DPA)
|
||||
with the ASF, so we cannot embed its images/widgets here. Do not re-add it.
|
||||
-->
|
||||
## 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" />
|
||||
|
||||
@@ -619,34 +619,14 @@ categories:
|
||||
- name: Symmetrics
|
||||
url: https://www.symmetrics.fyi
|
||||
|
||||
Government / Public authority:
|
||||
- name: Centre Régional Auvergnat de l'Information Géographique (France)
|
||||
url: https://www.craig.fr/
|
||||
logo: craig.png
|
||||
|
||||
Government:
|
||||
- name: City of Ann Arbor, MI
|
||||
url: https://www.a2gov.org/
|
||||
contributors: ["@sfirke"]
|
||||
|
||||
- name: Métropole Européenne de Lille (France)
|
||||
url: https://data.lillemetropole.fr/accueil/
|
||||
logo: mel.jpg
|
||||
|
||||
- name: NRLM - Sarathi, India
|
||||
url: https://pib.gov.in/PressReleasePage.aspx?PRID=1999586
|
||||
|
||||
- name: Région Bretagne (France)
|
||||
url: https://geobretagne.fr/
|
||||
logo: geobretagne.svg
|
||||
|
||||
- name: Région Hauts-de-France (France)
|
||||
url: https://www.geo2france.fr/
|
||||
logo: geo2france.png
|
||||
|
||||
- name: Rennes Métropole (France)
|
||||
url: https://metropole.rennes.fr/
|
||||
logo: rennes-ville-metropole_noir.svg
|
||||
|
||||
- name: RIS3 Strategy of CZ, MIT CR
|
||||
url: https://www.ris3.cz/
|
||||
contributors: ["@RIS3CZ"]
|
||||
@@ -702,10 +682,6 @@ categories:
|
||||
url: https://automattic.com/
|
||||
contributors: ["@Khrol", "@Usiel"]
|
||||
|
||||
- name: CamptoCamp
|
||||
url: https://camptocamp.com/
|
||||
logo: camptocamp.svg
|
||||
|
||||
- name: Dropbox
|
||||
url: https://www.dropbox.com/
|
||||
contributors: ["@bkyryliuk"]
|
||||
@@ -714,10 +690,6 @@ categories:
|
||||
url: https://flowbird.com
|
||||
contributors: ["@EmmanuelCbd"]
|
||||
|
||||
- name: geOrchestra
|
||||
url: https://www.georchestra.org
|
||||
logo: georchestra.svg
|
||||
|
||||
- name: GEOTAB
|
||||
url: https://www.geotab.com
|
||||
contributors: ["@JZ6"]
|
||||
@@ -734,10 +706,6 @@ categories:
|
||||
url: https://www.increff.com/
|
||||
contributors: ["@ishansinghania"]
|
||||
|
||||
- name: jDev
|
||||
url: https://jdev.fr/
|
||||
logo: jDev.svg
|
||||
|
||||
- name: Let's Roam
|
||||
url: https://www.letsroam.com/
|
||||
|
||||
@@ -748,11 +716,6 @@ categories:
|
||||
url: https://1beat.com/
|
||||
contributors: ["@GuyAttia"]
|
||||
|
||||
- name: pi-Geosolutions
|
||||
url: https://www.pi-geosolutions.fr/
|
||||
logo: pi-Geosolutions.png
|
||||
contributors: ["@jeanpommier"]
|
||||
|
||||
- name: X
|
||||
url: https://x.com/
|
||||
|
||||
|
||||
272
UPDATING.md
@@ -24,135 +24,6 @@ assists people when migrating to a new version.
|
||||
|
||||
## Next
|
||||
|
||||
### Owners, dashboard roles, and RLS roles replaced by Subjects
|
||||
|
||||
Superset now uses subject-based access assignments for dashboards, charts, datasets,
|
||||
alerts/reports, and Row Level Security. A Subject can represent a user, role, or group.
|
||||
|
||||
This is a breaking API and metadata change:
|
||||
|
||||
- `owners` is replaced by `editors` for dashboards, charts, datasets, and alerts/reports.
|
||||
- Dashboard `roles` and the `DASHBOARD_RBAC` feature flag are replaced by dashboard/chart
|
||||
`viewers`, enabled with `ENABLE_VIEWERS`.
|
||||
- RLS `roles` is replaced by `subjects`.
|
||||
- The legacy `dashboard_user`, `slice_user`, `sqlatable_user`, `report_schedule_user`,
|
||||
`dashboard_roles`, and `rls_filter_roles` tables are migrated into subject junction tables
|
||||
and dropped on upgrade.
|
||||
|
||||
For deployments that previously used `DASHBOARD_RBAC` and later disabled it: remove stale rows
|
||||
from the legacy `dashboard_roles` table before upgrading, otherwise those role assignments will
|
||||
become active dashboard Viewers after migration.
|
||||
|
||||
API clients and automation should send and read `editors`, `viewers`, and `subjects` instead
|
||||
of the legacy fields.
|
||||
|
||||
Subject pickers support users, groups, and roles, but only users and groups are selectable by
|
||||
default. Roles remain supported as Subject types for backwards compatibility with RLS role
|
||||
assignments and the previous `DASHBOARD_RBAC` model, but they are not recommended for new
|
||||
resource-specific assignments. Prefer groups for membership-based access and keep roles focused
|
||||
on capability grants. Existing Role subject assignments remain effective after migration even when
|
||||
Roles are hidden from the default dropdown values; configure the relevant `SUBJECTS_RELATED_TYPES_*`
|
||||
setting to make Roles selectable when editing subject lists. See the [Security documentation](docs/admin_docs/security/security.mdx#subjects)
|
||||
for the full Subject model and picker configuration guidance.
|
||||
|
||||
To make roles selectable everywhere:
|
||||
|
||||
```python
|
||||
from superset.subjects.types import SubjectType
|
||||
|
||||
SUBJECTS_RELATED_TYPES = [
|
||||
SubjectType.USER,
|
||||
SubjectType.GROUP,
|
||||
SubjectType.ROLE,
|
||||
]
|
||||
```
|
||||
|
||||
To make roles selectable for RLS while other pickers keep the user and group default, use the
|
||||
RLS-specific override:
|
||||
|
||||
```python
|
||||
from superset.subjects.types import SubjectType
|
||||
|
||||
SUBJECTS_RELATED_TYPES_RLS = [
|
||||
SubjectType.USER,
|
||||
SubjectType.GROUP,
|
||||
SubjectType.ROLE,
|
||||
]
|
||||
```
|
||||
|
||||
Entity-specific `SUBJECTS_RELATED_TYPES_*` settings replace `SUBJECTS_RELATED_TYPES` for that
|
||||
picker.
|
||||
|
||||
Deployments using `EXTRA_OWNERS_RESOLVER` must migrate to `EXTRA_EDITORS_RESOLVER`. The new
|
||||
resolver should return editor Subjects, subject IDs, or dicts with an `id` key instead of FAB
|
||||
User objects. API responses expose these dynamic assignments as `extra_editors` instead of
|
||||
`extra_owners`.
|
||||
|
||||
`DASHBOARD_RBAC` has been removed. To preserve the previous Dashboard RBAC behavior, enable both
|
||||
subject viewers and viewer datasource bypass:
|
||||
|
||||
```python
|
||||
FEATURE_FLAGS = {
|
||||
"ENABLE_VIEWERS": True,
|
||||
}
|
||||
VIEWER_PROMISCUOUS_MODE = True
|
||||
```
|
||||
|
||||
Enabling only `ENABLE_VIEWERS` allows assigning dashboard/chart viewer subjects, but viewers still
|
||||
need normal datasource permissions unless `VIEWER_PROMISCUOUS_MODE` is also enabled.
|
||||
|
||||
For backwards compatibility, enabling `ENABLE_VIEWERS` does not change access for dashboards or
|
||||
charts that have no assigned viewers. Those resources continue to use the implicit dataset-access
|
||||
model: users who can access the underlying dataset can still see published dashboards that use that
|
||||
dataset and charts backed by that dataset.
|
||||
Assigning one or more viewers opts that resource into explicit viewer access for non-editors. To
|
||||
return a resource to the implicit dataset-access model, remove all viewers from it. Explicit Viewers
|
||||
are the intended model going forward; deprecating and removing implicit viewership can be considered
|
||||
in a later major version.
|
||||
|
||||
- [41044](https://github.com/apache/superset/issues/41044): Removes the deprecated `AVOID_COLORS_COLLISION` feature flag (it defaulted to `True`). Color-collision avoidance is now permanently enabled; any config override setting it to `False` is ignored.
|
||||
|
||||
- [39925](https://github.com/apache/superset/pull/39925): URL prefixing for `SUPERSET_APP_ROOT` subdirectory deployments is now handled automatically by helpers in `src/utils/navigationUtils` (`openInNewTab`, `redirect`, `getShareableUrl`, `<AppLink>`). Direct imports of `ensureAppRoot` / `makeUrl` from `src/utils/pathUtils` are forbidden outside `navigationUtils.ts` (enforced by a static-invariant test); contributors writing new code should use the focused helpers instead. No runtime behaviour change for existing callers — all 19 prior call sites have been migrated and four pre-existing double-prefix and missing-prefix bugs are fixed as part of the migration.
|
||||
|
||||
- [39925](https://github.com/apache/superset/pull/39925): `SupersetClient.getUrl()` now strips a single leading application-root segment from the supplied `endpoint` before building the request URL, so a caller that accidentally pre-prefixes its endpoint (for example by wrapping it with `ensureAppRoot` before passing it to the client) no longer produces a doubled `/superset/superset/...` URL under subdirectory deployment. The strip is **single-pass** — a genuine `/superset/superset/<slug>` route is preserved, not collapsed — and **silent** (no console warning); the static-invariant test remains the primary signal for pre-prefixing at the call site, and this runtime strip is a safety net beneath it. Code that intentionally targeted a literal `/<app_root>/<app_root>/...` endpoint through `getUrl` (a configuration that has no legitimate use under the prefixing model) would have its first redundant segment removed.
|
||||
|
||||
- **Breaking — `Superset` view class route prefix removed.** The `Superset` view in `superset/views/core.py` now declares `route_base = ""`, overriding Flask-AppBuilder's auto-derived `/superset` prefix. Routes that previously lived at `/superset/welcome/`, `/superset/dashboard/<id>/`, `/superset/dashboard/p/<key>/`, `/superset/explore/`, etc. now respond at `/welcome/`, `/dashboard/<id>/`, `/dashboard/p/<key>/`, `/explore/`, etc. Under subdirectory deployment (`SUPERSET_APP_ROOT=/superset`) the URLs are unchanged from end-user perspective — `AppRootMiddleware` re-applies the prefix via `SCRIPT_NAME`. Under root deployments, any external integration or bookmark that hard-codes `/superset/<endpoint>/` paths must be updated to drop the prefix. This fixes the doubled `/superset/superset/...` URLs that `url_for` emitted for these endpoints under subdirectory deployment and the related 404s on the routes themselves.
|
||||
|
||||
- **Breaking — Three sibling view classes route prefix removed.** Following the same rationale as the `Superset` class above, `ExplorePermalinkView` (`superset/views/explore.py`), `TagModelView`, and `TaggedObjectsModelView` (`superset/views/tags.py`, `superset/views/all_entities.py`) now mount at the application root rather than a hard-coded `/superset/...`. The user-visible URLs `/superset/explore/p/<key>/`, `/superset/tags/`, and `/superset/all_entities/` are unchanged under subdirectory deployment; under root deployments these views now serve `/explore/p/<key>/`, `/tags/`, and `/all_entities/`, so any external integration or bookmark must drop the `/superset/` prefix. `Dashboard.url` and `Dashboard.get_url` likewise return `/dashboard/<id>/` instead of the prior `/superset/dashboard/<id>/` literal so downstream consumers (DashboardList row hrefs, MCP service `dashboard_url`) emit a single, deployment-correct prefix.
|
||||
|
||||
- **Legacy `/superset/*` path support.** A new outermost WSGI middleware `LegacyPrefixRedirectMiddleware` (`superset/middleware/legacy_prefix_redirect.py`) 308-redirects every enumerated legacy `/superset/<canonical>` path to its post-`route_base=""` canonical location (e.g. `/superset/welcome/` → `/welcome/` under root; → `/superset/welcome/` under `SUPERSET_APP_ROOT=/superset`, because the canonical resolves through `AppRootMiddleware`). Bookmarks, email links, and external integrations survive the route-base collapse for one release cycle. POST against a GET-only canonical returns 410 Gone instead of 308 (308 would 405 on retry). The shim is removed at EOL `5.0.0`, matching the `@deprecated(eol_version="5.0.0")` gate on `Superset.explore` and `Superset.explore_json`.
|
||||
|
||||
- **PWA web app manifest served dynamically.** The PWA manifest is now served at `/pwa-manifest.json` (under `APPLICATION_ROOT`) by a new `PwaManifestView` (`superset/views/pwa_manifest.py`) instead of the static file at `/static/assets/pwa-manifest.json`. The legacy static source at `superset-frontend/src/pwa-manifest.json` has been removed (along with its `webpack.config.js` `CopyPlugin` rule). The new endpoint resolves `APPLICATION_ROOT` and `STATIC_ASSETS_PREFIX` at request time so PWA install works under subdirectory deployments and split static-prefix / app-root deployments (where `STATIC_ASSETS_PREFIX` points to a CDN host while the Superset backend stays under `APPLICATION_ROOT`). The `<link rel="manifest">` href in `superset/templates/superset/spa.html` was updated correspondingly (using a new `application_root_rstrip` template global). Operators with a forked `spa.html` should switch any manifest `<link>` to `{{ application_root_rstrip }}/pwa-manifest.json`.
|
||||
|
||||
- **Hard re-bookmark break — `/superset/sql/<database_id>/`.** SQL Lab moved to its own blueprint at `/sqllab/`. The legacy `/superset/sql/<id>/` shape changed to a query-string form (`/sqllab/?dbid=<id>`); no 1:1 path mapping exists, so `LegacyPrefixRedirectMiddleware` does **not** redirect this route — it passes through and surfaces a 404. Users with bookmarks to `/superset/sql/<id>/` must update them to `/sqllab/?dbid=<id>`.
|
||||
|
||||
- **`SqlaTable.sql_url` query-string format.** `SqlaTable.sql_url` now URL-encodes `table_name` and joins it as a query parameter rather than concatenating a second `?`. Previously, with `Database.sql_url` returning `/sqllab/?dbid=<id>`, the concatenation produced `/sqllab/?dbid=<id>?table_name=<raw>` — a malformed second `?` that broke the query parser. External code that parsed the legacy `<base>?table_name=<raw>` shape now sees properly percent-encoded values (e.g. `/` → `%2F`, ` ` → `+` or `%20`); decode with `urllib.parse.parse_qsl`.
|
||||
|
||||
- **New config flag `EMBEDDED_DISABLE_PERMALINK_ORIGIN_REWRITE` (default `False`).** Share/permalink URLs now substitute `window.location.origin` for the backend-supplied origin so a proxied or subdirectory-deployed Superset never hands the user an unreachable internal hostname. Operators whose reverse proxy correctly forwards `X-Forwarded-Host` *and* who want permalinks to carry the backend's literal origin can opt out by setting `EMBEDDED_DISABLE_PERMALINK_ORIGIN_REWRITE = True` in `superset_config.py`. Default `False` (rewrite is on); flipping the default would regress the dominant proxied/subdir deployment to an unreachable host.
|
||||
|
||||
- [41651](https://github.com/apache/superset/pull/41651): **New do-not-translate standard for translation catalogs.** Strings that must stay identical to the source — icon names (e.g. `bolt`), enum/option values (`step-after`), SQL keywords, API field names (`error_message`), code constants, and example placeholders — are now marked with a `#. do-not-translate` extracted comment. The list lives in the `superset/translations/do-not-translate.txt` registry; `scripts/translations/apply_do_not_translate.py` stamps the marker onto `messages.pot` during `babel_update.sh`, and `pybabel update` propagates it to every `.po`, so the status is consistent across all languages. The AI backfill (`backfill_po.py`) and translators leave these entries untranslated (source fallback). The legacy per-catalog convention (a `# Не переводить` translator comment in the `ru` catalog) is still honored for back-compat but is superseded by this standard; contributors adding new machine-read strings should add the msgid to the registry rather than annotating individual catalogs.
|
||||
|
||||
### SQL Lab denies large-object and information_schema access by default
|
||||
|
||||
`DISALLOWED_SQL_FUNCTIONS` and `DISALLOWED_SQL_TABLES` now ship with additional default entries, so SQL Lab and chart-data queries that reference them are rejected where they were previously allowed:
|
||||
|
||||
- PostgreSQL large-object routines (`lo_from_bytea`, `lo_export`, `lo_import`, `lo_put`, `lo_create`, `lo_creat`, `lowrite`, `lo_get`, `loread`, `lo_unlink`), which read and write bytes on the database server's filesystem.
|
||||
- The SQL-standard `information_schema` views (`tables`, `columns`, `routines`, `views`, the privilege/grant views, etc.), which expose table, column, privilege, and view-definition metadata across the whole database.
|
||||
|
||||
Deployments that legitimately query these (for example tooling that introspects `information_schema`) can restore the previous behavior by overriding `DISALLOWED_SQL_FUNCTIONS` / `DISALLOWED_SQL_TABLES` in `superset_config.py` to drop the entries they need.
|
||||
|
||||
Because the denylist now resolves the effective schema through the query-aware path, PostgreSQL queries that change the `search_path` (e.g. `SET search_path = ...`) are rejected on the SQL Lab execution and cost-estimate paths whenever any `DISALLOWED_SQL_TABLES` entry is configured (the default for PostgreSQL), matching the behavior previously applied only when `RLS_IN_SQLLAB` was enabled.
|
||||
|
||||
### SQL parser input length cap (SQL_MAX_PARSE_LENGTH)
|
||||
|
||||
The SQL parser now rejects scripts whose UTF-8 byte length exceeds the new
|
||||
`SQL_MAX_PARSE_LENGTH` config option (default `1_000_000` bytes) before they are
|
||||
handed to sqlglot, which bounds parser memory and CPU usage. A single query
|
||||
larger than the cap (for example a very large `IN (...)` list or a big
|
||||
virtual-dataset SQL) raises a parse error in SQL Lab and dashboard-generated
|
||||
queries. Deployments that legitimately run queries above this size should raise
|
||||
the value, and `SQL_MAX_PARSE_LENGTH = None` disables the check entirely.
|
||||
|
||||
### Guest-token RLS rules reject unknown fields
|
||||
|
||||
The `rls` rules passed to `POST /api/v1/security/guest_token/` are now validated strictly: a rule may only contain `dataset` and `clause`. Previously unknown fields were silently dropped, so a mistyped or legacy scope key (most commonly `datasource` instead of `dataset`) produced a rule with no `dataset`, which is treated as a *global* rule applied to every dataset the embedded resource can reach. Such a request now returns HTTP 400 identifying the offending field instead of issuing a token with an unintended global rule. Integrators that were sending extra fields in RLS rules must remove them; valid dataset-scoped (`{"dataset": 41, "clause": "..."}`) and global (`{"clause": "..."}`) rules are unaffected.
|
||||
@@ -169,27 +40,10 @@ When the MCP service has JWT auth enabled (`MCP_AUTH_ENABLED = True`), an audien
|
||||
|
||||
The git SHA and build number surfaced in the "About" section, the bootstrap payload, and the public `/version` endpoint are now only included for admin users by default; the release version string is still shown to everyone. To expose the build details to all users (the previous behavior), set the `SUPERSET_EXPOSE_BUILD_DETAILS` environment variable (or `EXPOSE_BUILD_DETAILS_TO_USERS = True` in `superset_config.py`).
|
||||
|
||||
### Helm chart adopts Kubernetes recommended labels (breaking upgrade)
|
||||
|
||||
The Helm chart now labels and selects workloads using the [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/) (`app.kubernetes.io/*`) instead of the legacy `app`/`release` labels. Because a Deployment's `spec.selector.matchLabels` is immutable, `helm upgrade` against an existing release will fail with a `field is immutable` error.
|
||||
|
||||
To upgrade, delete the affected workloads (which selector labels changed) before upgrading, then run the upgrade so they are recreated with the new labels:
|
||||
|
||||
```bash
|
||||
kubectl delete deployment,statefulset -l release=<release-name> -n <namespace>
|
||||
helm upgrade <release-name> superset/superset
|
||||
```
|
||||
|
||||
Alternatively, perform a fresh install. This is a one-time migration; subsequent upgrades are unaffected.
|
||||
|
||||
### Pivot table First/Last aggregations follow data order
|
||||
|
||||
The pivot table chart's `First` and `Last` aggregations now return the first and last value in data (query result) order, instead of effectively returning the minimum and maximum. Existing pivot tables that use these aggregations for totals/subtotals may show different values after upgrading. For deterministic results, ensure the underlying query has a stable sort order.
|
||||
|
||||
### `FetchRetryOptions` callback parameters widened to allow `null`
|
||||
|
||||
The `error` and `response` parameters of the `retryDelay` and `retryOn` callbacks in `FetchRetryOptions` (exported from `@superset-ui/core`) are now typed `Error | null` and `Response | null` to match the actual call-site signature provided by `fetch-retry`. Because these parameter types are contravariant, consumers who typed their callbacks with the non-nullable `(attempt: number, error: Error, response: Response) => number` will get a TypeScript compile error. Widen your callback signatures to accept `Error | null` / `Response | null`.
|
||||
|
||||
### `thumbnail_url` removed from dashboard list API response
|
||||
|
||||
The `thumbnail_url` field has been removed from `GET /api/v1/dashboard/` list responses. External consumers relying on this field must now construct the thumbnail URL client-side using `id` and `changed_on_utc`:
|
||||
@@ -213,17 +67,6 @@ ALTER TABLE tagged_object DROP CONSTRAINT <constraint_name>;
|
||||
-- MySQL: find names via `SHOW CREATE TABLE tagged_object;`
|
||||
ALTER TABLE tagged_object DROP FOREIGN KEY <constraint_name>;
|
||||
```
|
||||
### Entity version-history infrastructure (gated off by default)
|
||||
|
||||
Introduces the schema and SQLAlchemy-Continuum wiring that captures version history for charts, dashboards, and datasets, plus read-only `GET /api/v1/{chart,dashboard,dataset}/<uuid>/versions/` endpoints. This ships **inert**: a new config flag `ENABLE_VERSIONING_CAPTURE` defaults to `False`, so no save writes any version rows and the endpoints return empty. It is an operational kill-switch (a release toggle that becomes a permanent ops switch), not a feature flag — set it to `True` to enable capture once validated. The migration is additive; existing entity `PUT` responses gain `old_version_uuid` / `new_version_uuid` body fields and an `ETag` header (both null/absent when capture is off).
|
||||
|
||||
A few save- and import-path internals change **unconditionally** (independent of the flag), because the versioned mappers must behave correctly whether or not capture is enabled:
|
||||
|
||||
- `DatasetDAO` column/metric updates move from bulk operations to per-row ORM operations, and a metadata refresh now preserves column primary keys via a natural-key (`column_name`) upsert instead of delete-and-reinsert — so charts that reference dataset columns by id keep working across a refresh (previously such references could be invalidated).
|
||||
- `ImportExportMixin.reset_ownership` stamps the current user onto `created_by`/`changed_by` when a request context is present (previously left null for the column default to fill).
|
||||
- `UpdateDashboardCommand` runs its body under `no_autoflush`.
|
||||
|
||||
These are behavior changes that take effect on upgrade regardless of `ENABLE_VERSIONING_CAPTURE`; no operator action is required.
|
||||
|
||||
### Webhook alerts/reports block private/internal hosts by default
|
||||
|
||||
@@ -234,7 +77,6 @@ Deployments that intentionally point webhooks at internal targets (chatops bridg
|
||||
### Impala cancel_query blocks private/internal hosts by default
|
||||
|
||||
The Impala engine spec's `cancel_query` issues an HTTP request from the Superset backend to the host configured on the Impala database connection. That host is now validated before the request: if it resolves to a private/internal IP range, the cancel call is refused and a warning is logged. Operators whose Impala cluster runs on an internal network can opt out by setting `IMPALA_CANCEL_QUERY_ALLOW_INTERNAL_HOSTS = True` in `superset_config.py`. This mirrors the dataset-import and webhook opt-out flags.
|
||||
|
||||
### Map chart renderer and OpenStreetMap migration behavior
|
||||
|
||||
The MapLibre migration for deck.gl charts preserves saved non-Mapbox styles on
|
||||
@@ -272,11 +114,6 @@ Operators can tune or disable the policy via config:
|
||||
### Data uploads bounded by UPLOAD_MAX_FILE_SIZE_BYTES
|
||||
|
||||
Single data-file uploads (CSV, Excel, columnar) are now bounded by the `UPLOAD_MAX_FILE_SIZE_BYTES` config option, which defaults to `100 * 1024 * 1024` (100 MB). Files larger than this are rejected with a `413` before their contents are buffered into memory. Set `UPLOAD_MAX_FILE_SIZE_BYTES = None` to disable the check and restore unbounded uploads.
|
||||
### Currency symbol position follows the locale when unset
|
||||
|
||||
When a chart's currency control leaves the **Prefix or suffix** field empty, the currency symbol position is now derived from the deployment locale's own convention via `Intl.NumberFormat` instead of always defaulting to a suffix. For example, under the default `en-US` locale `USD`, `GBP`, and `EUR` render as a prefix (`$ 1,000`), while eurozone locales such as `fr-FR` render `EUR` as a suffix (`1 000 €`). An explicit Prefix/Suffix selection is always honored and is unaffected.
|
||||
|
||||
Charts that relied on the previous always-suffix default for an unset position will render the symbol on the locale-appropriate side instead; set the position explicitly on the metric's currency control to pin it.
|
||||
|
||||
### Duration formatter precision
|
||||
|
||||
@@ -342,18 +179,6 @@ Runbook to adopt:
|
||||
2. Set that value on the tunnel's `server_host_key` (via the database/SSH tunnel API or UI payload).
|
||||
3. Optionally set `SSH_TUNNEL_STRICT_HOST_KEY_CHECKING = True` in `superset_config.py` to require host-key verification on all tunnels.
|
||||
|
||||
### SMTP server certificate validation enabled by default
|
||||
|
||||
`SMTP_SSL_SERVER_AUTH` now defaults to `True` (previously `False`). With this default, STARTTLS/SSL connections to the configured SMTP server validate the server's TLS certificate against the system trusted CA store. This makes outbound email (alerts and reports) verify the mail server's identity out of the box.
|
||||
|
||||
If your SMTP server presents a self-signed certificate, or a certificate that is not trusted by the system CA store, email delivery may now fail with a certificate verification error. To restore the previous behavior of skipping certificate validation, set the following in `superset_config.py`:
|
||||
|
||||
```python
|
||||
SMTP_SSL_SERVER_AUTH = False
|
||||
```
|
||||
|
||||
The recommended fix is to add the SMTP server's certificate (or its issuing CA) to the system trust store rather than disabling validation.
|
||||
|
||||
### Dataset import validates catalog against the target connection
|
||||
|
||||
Importing a dataset now validates the `catalog` field against the target database connection. When the connection has multi-catalog disabled (`allow_multi_catalog` off) and the dataset's catalog is not the connection's default catalog, the import fails instead of silently persisting the non-default catalog. This matches the validation already enforced on the dataset update path and prevents imported datasets from querying an unintended database.
|
||||
@@ -403,80 +228,6 @@ Schedule the cutover in a quiet window. Runtime reads use only the single config
|
||||
|
||||
The migration is transactional (all-or-nothing) and idempotent — it can be safely re-run or resumed. Note that AES-GCM, unlike AES-CBC, does not support querying directly over encrypted columns; audit any code that filters on an encrypted column before switching. See the SIP at `docs/sip/authenticated-encryption-at-rest.md` for details.
|
||||
|
||||
### Soft delete and restore for datasets
|
||||
|
||||
**The soft-delete behavior in this section applies only when the `SOFT_DELETE` feature flag is enabled. The flag defaults to `False`** (`@lifecycle: development`), so on a default deployment `DELETE /api/v1/dataset/<id>` continues to **hard-delete permanently** — nothing is recoverable. Enable `SOFT_DELETE` to get the behavior described below.
|
||||
|
||||
**Flag-toggle caveat:** the soft-delete visibility filter is evaluated per query while the flag is on. If datasets are soft-deleted during a flag-on window and the flag is later turned **off**, those rows reappear as live datasets in all lists, lookups, and relationship loads (including charts that reference them). The `POST /<uuid>/restore` endpoint and the `dataset_deleted_state` list filter remain functional regardless of the flag, deliberately, so rows soft-deleted during a flag-on window stay discoverable and restorable after a rollback of the flag.
|
||||
|
||||
**Flag-independent parts of this work** (active even with `SOFT_DELETE` off): the restore endpoint and deleted-state filter (above); the database-deletion guard counting soft-deleted datasets; the `get_or_create_dataset` soft-deleted-twin pre-check; the combined datasource listing (`GET /api/v1/datasource/...`) always excluding soft-deleted datasets; and the two uniqueness-validation changes documented at the end of this section. Everything else — the soft DELETE itself and the visibility filtering — is flag-gated.
|
||||
|
||||
With the flag enabled: `DELETE /api/v1/dataset/<id>` no longer hard-deletes the dataset (the bulk-delete endpoint behaves the same way). The row is marked with a `deleted_at` timestamp and hidden from all list, detail, and lookup endpoints. Datasets in this state are excluded from default queries and from relationship loads (e.g. `database.tables`).
|
||||
|
||||
**No cascade in v1.** Soft-delete does not propagate to dependent charts or dashboards: they remain visible. Loading a chart whose dataset is soft-deleted surfaces a "datasource not found" error at chart-load time. Restore the dataset to recover.
|
||||
|
||||
**Database deletion is blocked by soft-deleted datasets.** Superset already refuses to delete a database that still has datasets (`DatabaseDeleteDatasetsExistFailedError`); that check now explicitly counts soft-deleted datasets too (it bypasses the visibility filter), since the soft-deleted `tables` rows still reference the database via `database_id` and must not be orphaned. Consequence: because dataset `DELETE` is soft and v1 ships no hard-delete/purge, **a database that has ever had datasets cannot be deleted through the API once those datasets are soft-deleted** — the rows remain and keep blocking the delete. Until a purge capability lands, operators who must remove such a database have to hard-delete the underlying `tables` rows out-of-band first. This is a deliberate trade-off (no orphaned rows / restorable datasets) and is expected to be resolved by the planned purge work.
|
||||
|
||||
**Side-effect change for operators.** Because the row is no longer physically deleted, FAB `ab_view_menu` / permission-view rows tied to the dataset are also preserved. Downstream automation that relied on `DELETE /api/v1/dataset/<id>` cleaning up those rows must now react to the new `POST /api/v1/dataset/<uuid>/restore` lifecycle, or call the eventual hard-delete endpoint.
|
||||
|
||||
**New endpoint** — `POST /api/v1/dataset/<uuid>/restore` clears `deleted_at` and returns the dataset to active state. Requires `can_write on Dataset` and editorship of the row (or admin). Soft-deleted datasets can also be surfaced in the list endpoint via the new `dataset_deleted_state` rison filter: `include` returns both live and soft-deleted rows, `only` returns just the soft-deleted ones. Any other value is ignored. For non-admin users, soft-deleted rows are limited to datasets they can edit — the same audience that can restore them.
|
||||
|
||||
**Permissions migration:** existing role grants of `can_write on Dataset` cover the new restore endpoint automatically; no role migration is required.
|
||||
|
||||
**Schema migration:** the migration adds a nullable `deleted_at` column and an index on it (`ix_tables_deleted_at`) to the `tables` table. The column add is instant; the index build runs inline (no `CONCURRENTLY`) and may briefly block writes on the `tables` table (INSERT/UPDATE/DELETE are queued while the index builds; reads are unaffected) on large Postgres deployments. MySQL InnoDB builds the index online (no blocking). Production deployments with many thousands of datasets should run this migration during a maintenance window.
|
||||
|
||||
**Rollback note:** if the application code is rolled back after datasets have been soft-deleted, the older code path's visibility filter no longer applies and previously hidden rows become visible to the older code. Pair the rollback with a data decision (restore the rows, hard-delete them, or also downgrade the migration) rather than assuming the old hard-delete semantics still hold. **Downgrading the migration destroys the deletion markers**: `downgrade()` drops the `deleted_at` column, so any not-yet-restored soft-deleted datasets silently become live, active datasets with no record they were ever deleted. Reconcile the trash (restore or hard-delete each row) *before* downgrading, and disable the `SOFT_DELETE` flag first so no new soft deletes land mid-rollback.
|
||||
|
||||
**SQL Lab / dataset-creation flows:** creating a dataset over a table whose dataset sits in the trash is refused. The SQL Lab "save as dataset" flow (`get_or_create_dataset`) and file uploads return a **422 naming the hidden twin and the restore endpoint**; the plain create, update, and duplicate paths currently fail with the generic "already exists" 422. In all cases the remediation is the same: restore the hidden dataset (or use a different table name). Perm-string maintenance also covers hidden rows: renaming a database rewrites `perm`/`schema_perm`/`catalog_perm` on soft-deleted datasets and their charts, so a later restore does not resurrect stale permission strings.
|
||||
|
||||
**Importer behavior:** importing a dataset YAML whose UUID matches an existing **soft-deleted** dataset is treated as an implicit restore-with-update — **and this happens even when `overwrite` is not set**. This is a deliberate asymmetry with active rows: an active dataset imported without `overwrite=true` is returned unchanged, but a soft-deleted UUID match is restored *and* has the upload's contents applied regardless of the `overwrite` argument, on the reasoning that re-importing a deleted dataset's exact UUID is an explicit request to bring it back. The restore preserves the original PK, the chart back-reference, `table_columns`, and `sql_metrics`. Non-editors get `ImportFailedError`. Callers without `can_write` get `ImportFailedError` instead of silently receiving the soft-deleted row.
|
||||
|
||||
**Uniqueness-validation changes that apply regardless of the feature flag:** two dataset uniqueness checks were tightened alongside this work and are active even with `SOFT_DELETE` off. (1) Create/update uniqueness treats a dataset whose `catalog` is `NULL` as belonging to the database's default catalog, so a legacy twin pair (`catalog=NULL` vs. `catalog=<default>`, same database/schema/name) that older versions allowed now fails validation with "already exists" when either row is edited — resolve by renaming or removing one of the twins. (2) Duplicating a dataset now checks name collisions scoped to the target (database, catalog, schema) instead of globally by name alone: duplicates into other databases that were previously blocked are now allowed.
|
||||
|
||||
### Soft delete and restore for charts
|
||||
|
||||
**Everything in this section applies only when the `SOFT_DELETE` feature flag is enabled. The flag defaults to `False`** (`@lifecycle: development`), so on a default deployment `DELETE /api/v1/chart/<id>` continues to **hard-delete permanently** — nothing is recoverable. Enable `SOFT_DELETE` to get the behavior described below.
|
||||
|
||||
**Flag-toggle caveat:** the soft-delete visibility filter is evaluated per query while the flag is on. If charts are soft-deleted during a flag-on window and the flag is later turned **off**, those rows reappear as live charts in all lists, lookups, and relationship loads (including dashboards that contained them). The `POST /<uuid>/restore` endpoint and the `chart_deleted_state` list filter remain functional regardless of the flag, deliberately, so rows soft-deleted during a flag-on window stay discoverable and restorable after a rollback of the flag.
|
||||
|
||||
With the flag enabled: `DELETE /api/v1/chart/<id>` no longer hard-deletes the chart (the bulk-delete endpoint behaves the same way). The row is marked with a `deleted_at` timestamp and hidden from all list, detail, and lookup endpoints. Charts in this state are excluded from default queries and from relationship loads (e.g. `dashboard.slices`).
|
||||
|
||||
**Operational notes:** a report schedule whose target chart is soft-deleted now fails its runs with an explicit error ("The chart this report targets was deleted...") until the chart is restored or the report re-pointed — chart deletion is blocked while a report references the chart, but a validate/commit race or a flag toggle can still produce this state. Dashboards **preserve** their membership rows for soft-deleted charts: saving a dashboard does not sever a trashed member, and restoring the chart re-attaches it to its dashboards.
|
||||
|
||||
**New endpoint** — `POST /api/v1/chart/<uuid>/restore` clears `deleted_at` and returns the chart to active state. Requires `can_write on Chart` and editorship of the row (or admin). Soft-deleted charts can also be surfaced in the list endpoint via the new `chart_deleted_state` rison filter: `include` returns both live and soft-deleted rows, `only` returns just the soft-deleted ones. Any other value is ignored. For non-admin users, soft-deleted rows are limited to charts they can edit — the same audience that can restore them.
|
||||
|
||||
**Permissions migration:** existing role grants of `can_write on Chart` cover the new restore endpoint automatically; no role migration is required.
|
||||
|
||||
**Schema migration:** the migration adds a nullable `deleted_at` column and an index on it (`ix_slices_deleted_at`) to the `slices` table. The column add is instant; the index build runs inline (no `CONCURRENTLY`) and may briefly block writes on the `slices` table (INSERT/UPDATE/DELETE are queued while the index builds; reads are unaffected) on large Postgres deployments. MySQL InnoDB builds the index online (no blocking).
|
||||
|
||||
**Rollback note:** if the application code is rolled back after charts have been soft-deleted, the older code path's visibility filter no longer applies and previously hidden rows become visible to the older code. Pair the rollback with a data decision (restore the rows, hard-delete them, or also downgrade the migration) rather than assuming the old hard-delete semantics still hold. **Downgrading the migration destroys the deletion markers**: `downgrade()` drops the `deleted_at` column, so any not-yet-restored soft-deleted charts silently become live, active charts with no record they were ever deleted. Reconcile the trash (restore or hard-delete each row) *before* downgrading, and disable the `SOFT_DELETE` flag first so no new soft deletes land mid-rollback.
|
||||
|
||||
**Importer behavior:** importing a chart YAML whose UUID matches an existing **soft-deleted** chart is treated as an implicit restore-with-update — **and this happens even when `overwrite` is not set**. This is a deliberate asymmetry with active rows: an active chart imported without `overwrite=true` is returned unchanged, but a soft-deleted UUID match is restored *and* has the upload's contents applied regardless of the `overwrite` argument, on the reasoning that re-importing a deleted chart's exact UUID is an explicit request to bring it back. The restore preserves the original PK and all out-of-archive references (`dashboard_slices` junctions, `report.chart_id`, tag rows). The operation is permission-gated: non-editors get `ImportFailedError`, and callers without `can_write` get `ImportFailedError` instead of silently receiving the soft-deleted row.
|
||||
|
||||
- [39914](https://github.com/apache/superset/pull/39914) `ALERT_REPORT_SLACK_V2` now defaults to `True` and the legacy Slack v1 integration (`Slack` recipient type, `files.upload` API) is deprecated for removal in the next major. Slack blocked new apps from `files.upload` in May 2024 and fully retired the method for all apps on November 12, 2025; because the v1 path sends files through `files.upload`, v1 file-bearing sends now fail at the API level — only text-only `chat_postMessage` still works via the legacy path. Grant your Slack bot the `channels:read` and `groups:read` scopes so existing `Slack` recipients can be auto-upgraded to `SlackV2` on next send. Operators who explicitly override the flag to `False`, or whose Slack bot is missing those scopes, will see deprecation warnings while text-only sends continue through the legacy path.
|
||||
|
||||
### Soft delete and restore for dashboards
|
||||
|
||||
**Everything in this section applies only when the `SOFT_DELETE` feature flag is enabled. The flag defaults to `False`** (`@lifecycle: development`), so on a default deployment `DELETE /api/v1/dashboard/<id>` continues to **hard-delete permanently** — nothing is recoverable. Enable `SOFT_DELETE` to get the behavior described below.
|
||||
|
||||
**Flag-toggle caveat:** the soft-delete visibility filter is evaluated per query while the flag is on. If dashboards are soft-deleted during a flag-on window and the flag is later turned **off**, those rows reappear as live dashboards in all lists and lookups (including slug lookups — if a soft-deleted dashboard's slug was reused while the flag was on, both rows become visible with the same slug). The `POST /<uuid>/restore` endpoint and the `dashboard_deleted_state` list filter remain functional regardless of the flag, deliberately, so rows soft-deleted during a flag-on window stay discoverable and restorable after a rollback of the flag.
|
||||
|
||||
With the flag enabled: `DELETE /api/v1/dashboard/<id>` no longer hard-deletes the dashboard (the bulk-delete endpoint behaves the same way). The row is marked with a `deleted_at` timestamp and hidden from the dashboard API's list, detail, and lookup endpoints, which return 404 for soft-deleted dashboards. The embedded-dashboard iframe URL (`/embedded/<uuid>`) keeps rendering because it reads only `embedded.allowed_domains` and `embedded.dashboard_id` (the FK column) without dereferencing the parent dashboard; the frontend's subsequent dashboard-API fetch is what sees the 404 and surfaces "dashboard not found" to the user.
|
||||
|
||||
**New endpoint** — `POST /api/v1/dashboard/<uuid>/restore` clears `deleted_at` and returns the dashboard to active state. Requires `can_write on Dashboard` and editorship of the row (or admin). Soft-deleted dashboards can also be surfaced in the list endpoint via the new `dashboard_deleted_state` rison filter: `include` returns both live and soft-deleted rows, `only` returns just the soft-deleted ones. Any other value is ignored. For non-admin users, soft-deleted rows are limited to dashboards they can edit — the same audience that can restore them.
|
||||
|
||||
**Permissions migration:** existing role grants of `can_write on Dashboard` cover the new restore endpoint automatically; no role migration is required.
|
||||
|
||||
**Schema migration:** the migration adds a nullable `deleted_at` column and an index on it (`ix_dashboards_deleted_at`) to the `dashboards` table, and **replaces the full unique constraint on `slug`** with a partial unique index (`ix_dashboards_active_slug`) enforcing slug uniqueness only among active (non-soft-deleted) rows. The column add is instant. On Postgres the constraint swap briefly blocks reads and writes during `ALTER TABLE ... DROP CONSTRAINT` (acquires `ACCESS EXCLUSIVE`), then blocks writes only during `CREATE UNIQUE INDEX` (acquires `ShareLock`); reads pass through during the index build. Both windows are sub-second on a typical `dashboards` table. MySQL InnoDB builds the functional index online (no blocking).
|
||||
|
||||
**Rollback note:** the downgrade restores the original full unique constraint on `slug`. If the partial-index window allowed slug reuse (a soft-deleted row and an active row holding the same slug), `ALTER TABLE ... ADD CONSTRAINT idx_unique_slug UNIQUE (slug)` will abort with a unique-constraint violation. Before downgrading, hard-delete the soft-deleted duplicates (or rename one side) so each slug appears at most once across all rows. Rolling back the application code while leaving the new migration in place is also possible but exposes soft-deleted rows to the older code path; pair the rollback with a data decision (restore, hard-delete, or migrate-down).
|
||||
|
||||
The partial-index replacement is dialect-dependent: PostgreSQL uses a native `WHERE deleted_at IS NULL` partial index; MySQL 8.0.13+ uses a functional index over `(CASE WHEN deleted_at IS NULL THEN slug END)` (8.0.13 is the first release with functional key parts). **MySQL <8.0.13, MariaDB, and SQLite keep the original full unique constraint** (functional indexes / column-level UNIQUE recreation aren't supported cleanly — MariaDB is excluded even at 10.x because its `CASE`-expression index semantics differ), so on those backends a soft-deleted dashboard continues to reserve its slug for the lifetime of the row.
|
||||
|
||||
**Slug semantics:** on PostgreSQL and MySQL 8.0.13+, the slug of a soft-deleted dashboard is **free for reuse**. A new active dashboard can claim it immediately. Restoring a soft-deleted dashboard whose slug has since been claimed returns **422 with a clean error** (`DashboardSlugConflictError`) — rename one of the dashboards and retry; the restore is not silently rejected by a database-level constraint violation.
|
||||
|
||||
**Importer behavior:** importing a dashboard YAML whose UUID matches an existing **soft-deleted** dashboard is treated as an implicit restore-with-update — **and this happens even when `overwrite` is not set**. This is a deliberate asymmetry with active rows: an active dashboard imported without `overwrite=true` is returned unchanged (the import never mutates it), but a soft-deleted UUID match is restored *and* has the upload's contents applied regardless of the `overwrite` argument, on the reasoning that re-importing a deleted dashboard's exact UUID is an explicit request to bring it back. The restore preserves the original PK and all pre-deletion relationship rows (`dashboard_slices` junctions, editor/viewer subjects, tags). Callers whose imports must never mutate existing state should treat bundles that may contain previously deleted UUIDs accordingly. The operation is permission-gated: it requires `can_write` and editorship of the deleted row (or admin) — non-editors get `ImportFailedError`, and callers without `can_write` get `ImportFailedError` instead of silently receiving the soft-deleted row.
|
||||
|
||||
### Granular Export Controls
|
||||
|
||||
A new feature flag `GRANULAR_EXPORT_CONTROLS` introduces three fine-grained permissions that replace the legacy `can_csv` permission:
|
||||
@@ -766,29 +517,6 @@ See `superset/mcp_service/PRODUCTION.md` for deployment guides.
|
||||
}
|
||||
```
|
||||
|
||||
### Composite primary keys on many-to-many association tables
|
||||
|
||||
Eight M:N association tables move from a synthetic `id INTEGER PRIMARY KEY` to a composite `PRIMARY KEY (fk1, fk2)` on their two foreign-key columns. The surrogate `id` is dropped, and the redundant `UNIQUE (fk1, fk2)` on the two tables that carried one is removed (now subsumed by the PK).
|
||||
|
||||
| Table | Composite PK |
|
||||
|---|---|
|
||||
| `dashboard_roles` | `(dashboard_id, role_id)` |
|
||||
| `dashboard_slices` | `(dashboard_id, slice_id)` |
|
||||
| `dashboard_user` | `(user_id, dashboard_id)` |
|
||||
| `report_schedule_user` | `(user_id, report_schedule_id)` |
|
||||
| `rls_filter_roles` | `(role_id, rls_filter_id)` |
|
||||
| `rls_filter_tables` | `(table_id, rls_filter_id)` |
|
||||
| `slice_user` | `(user_id, slice_id)` |
|
||||
| `sqlatable_user` | `(user_id, table_id)` |
|
||||
|
||||
**Before upgrading:**
|
||||
|
||||
- The migration **deletes** two classes of pre-existing rows the composite PK cannot accommodate: duplicate `(fk1, fk2)` pairs (it keeps the lowest `id` and removes the rest) and rows with `NULL` in either FK column. Both are meaningless for `secondary=` association tables, but export the affected rows first if you need an audit record.
|
||||
- External tooling (BI tools, backup scripts) that references the surrogate `id` on these tables will break; no application code references it.
|
||||
- Downgrade restores the `id` column (and the original `UNIQUE` on the two tables that had it) but leaves the FK columns `NOT NULL` (intentional — a `NULL` FK in a junction row is meaningless).
|
||||
|
||||
For large `dashboard_slices` / `report_schedule_user` tables, see the operator runbook in [#39859](https://github.com/apache/superset/pull/39859) — pre-flight inventory queries, per-dialect lock-window sizing, and the duplicate / NULL-FK roll-up — to plan the maintenance window.
|
||||
|
||||
## 6.0.0
|
||||
- [33055](https://github.com/apache/superset/pull/33055): Upgrades Flask-AppBuilder to 5.0.0. The AUTH_OID authentication type has been deprecated and is no longer available as an option in Flask-AppBuilder. OpenID (OID) is considered a deprecated authentication protocol - if you are using AUTH_OID, you will need to migrate to an alternative authentication method such as OAuth, LDAP, or database authentication before upgrading.
|
||||
- [34871](https://github.com/apache/superset/pull/34871): Fixed Jest test hanging issue from Ant Design v5 upgrade. MessageChannel is now mocked in test environment to prevent rc-overflow from causing Jest to hang. Test environment only - no production impact.
|
||||
|
||||
@@ -287,10 +287,8 @@ to specify on behalf of which username to render the dashboards. In general, das
|
||||
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 a physical user represented by the alert/report editors
|
||||
(giving priority to the last modifier, then the creator, then the first direct user editor, then a
|
||||
deterministic user from editor roles or groups). To use a fixed user account, just change the config
|
||||
as follows (`admin` in this example):
|
||||
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
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
{/*
|
||||
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.
|
||||
*/}
|
||||
|
||||
---
|
||||
title: AWS IAM Authentication
|
||||
sidebar_label: AWS IAM Authentication
|
||||
version: 1
|
||||
sidebar_position: 15
|
||||
---
|
||||
|
||||
|
||||
@@ -139,10 +139,6 @@ from superset.tasks.types import FixedExecutor
|
||||
THUMBNAIL_EXECUTORS = [FixedExecutor("admin")]
|
||||
```
|
||||
|
||||
When using `ExecutorType.EDITOR`, thumbnails are rendered as a physical user represented by
|
||||
the dashboard or chart editors. Superset prioritizes the last modifier, then the creator,
|
||||
then the first direct user editor, then a deterministic user from editor roles or groups.
|
||||
|
||||
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.
|
||||
|
||||
@@ -183,10 +179,10 @@ WEBDRIVER_BASEURL = "https://superset.company.com"
|
||||
|
||||
To control which user account is used for rendering thumbnails and warming up caches, configure
|
||||
`THUMBNAIL_EXECUTORS` and `CACHE_WARMUP_EXECUTORS`. Each accepts a list of executor types (which
|
||||
resolve to an editor, creator, modifier, or the currently-logged-in user) and/or a
|
||||
`FixedExecutor` pinned to a specific username. By default, thumbnails render as the current user
|
||||
(`ExecutorType.CURRENT_USER`) and cache warmup uses editor-based execution
|
||||
(`ExecutorType.EDITOR`) where executor-based cache warmup is used.
|
||||
resolve to an owner, creator, modifier, or the currently-logged-in user) and/or a `FixedExecutor`
|
||||
pinned to a specific username. By default, thumbnails render as the current user
|
||||
(`ExecutorType.CURRENT_USER`) and cache warmup runs as the chart/dashboard owner
|
||||
(`ExecutorType.OWNER`).
|
||||
|
||||
To force both to run as a dedicated service account (`admin` in this example):
|
||||
|
||||
|
||||
@@ -549,24 +549,6 @@ CELERY_BEAT_SCHEDULE = {
|
||||
|
||||
Adjust `retention_period_days` to control how long query rows are kept. Companion opt-in tasks (`prune_logs`, `prune_tasks`) exist for pruning the logs and tasks tables; see the commented-out examples in `superset/config.py`. Without enabling these tasks, the metadata database will grow unbounded over time.
|
||||
|
||||
## Dashboard Layout Size Limit
|
||||
|
||||
Each dashboard stores its layout (the position, size, and nesting of every chart, row, and tab) as a JSON blob in the metadata database. Superset caps the length of this serialized blob with `SUPERSET_DASHBOARD_POSITION_DATA_LIMIT`, which defaults to `65535`:
|
||||
|
||||
```python
|
||||
SUPERSET_DASHBOARD_POSITION_DATA_LIMIT = 65535
|
||||
```
|
||||
|
||||
This is a Python-level cap (65535 is 2¹⁶ − 1), independent of the database column capacity — the `position_json` column is a `MEDIUMTEXT`, which holds far more. When the serialized layout reaches this limit, the editor blocks the save and reports the current length, the limit, and this setting's name. A warning is shown once the layout passes 90% of the limit.
|
||||
|
||||
Large dashboards — for example, many charts spread across nested tabs — can exceed the default. Because the underlying column comfortably stores larger values, you can safely raise the limit:
|
||||
|
||||
```python
|
||||
SUPERSET_DASHBOARD_POSITION_DATA_LIMIT = 131072 # double the default
|
||||
```
|
||||
|
||||
Alternatively, split a very large dashboard into several smaller ones. Note that this check is enforced when saving layout edits in the UI; a dashboard imported from a ZIP with an oversized layout will load and render, but cannot be edited and re-saved until the limit is raised.
|
||||
|
||||
:::resources
|
||||
- [Blog: Feature Flags in Apache Superset](https://preset.io/blog/feature-flags-in-apache-superset-and-preset/)
|
||||
:::
|
||||
|
||||
@@ -60,9 +60,9 @@ There are two approaches to making dashboards publicly accessible:
|
||||
|
||||
**Option 2: Dashboard-level access (selective control)**
|
||||
1. Set `PUBLIC_ROLE_LIKE = "Public"` in `superset_config.py`
|
||||
2. Add the `'ENABLE_VIEWERS': True` [Feature Flag](/admin-docs/configuration/feature-flags)
|
||||
3. Edit each dashboard's properties and add the "Public" role subject as a viewer
|
||||
4. Only published dashboards with the Public role subject explicitly assigned are visible to anonymous users
|
||||
2. Add the `'DASHBOARD_RBAC': True` [Feature Flag](/admin-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](/admin-docs/security/#public) for more details.
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ https://superset.apache.org/admin-docs/configuration/configuring-superset/#rotat
|
||||
|
||||
### **Appendix C: Secrets Register and Rotation Schedule**
|
||||
|
||||
`SUPERSET_SECRET_KEY` is not the only security-critical secret in a Superset deployment. Maintain an inventory of all such secrets, store each in a secrets manager (not in `superset_config.py` or version control), assign a responsible maintainer, and rotate them on a defined cadence as well as after any suspected compromise.
|
||||
`SUPERSET_SECRET_KEY` is not the only security-critical secret in a Superset deployment. Maintain an inventory of all such secrets, store each in a secrets manager (not in `superset_config.py` or version control), assign an owner, and rotate them on a defined cadence as well as after any suspected compromise.
|
||||
|
||||
| Secret | Purpose | Risk if leaked | Suggested rotation |
|
||||
|---|---|---|---|
|
||||
|
||||
@@ -91,24 +91,24 @@ PUBLIC_ROLE_LIKE = "Public"
|
||||
# PUBLIC_ROLE_LIKE = "Gamma"
|
||||
```
|
||||
|
||||
If you prefer to manually configure the Public role's permissions, or use subject-based
|
||||
dashboard viewer assignments, you do not need to set `PUBLIC_ROLE_LIKE`.
|
||||
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 by default:** 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:
|
||||
- **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:
|
||||
|
||||
- **Dataset-based access:** 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.
|
||||
- **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.
|
||||
|
||||
- **Subject-based dashboard access:** When `ENABLE_VIEWERS` is enabled, anonymous users can
|
||||
see published dashboards where the "Public" role subject has been explicitly added as a
|
||||
viewer. If `VIEWER_PROMISCUOUS_MODE` is enabled, viewer access can bypass dataset
|
||||
permission checks for dashboard rendering.
|
||||
- **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
|
||||
@@ -131,76 +131,10 @@ tables in the **Permissions** dropdown. To select the data sources you want to a
|
||||
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.
|
||||
|
||||
### Subjects
|
||||
|
||||
A **subject** is a unified identity that can be granted access to Superset resources such as
|
||||
dashboards, charts, and datasets. Subjects come in three types:
|
||||
|
||||
- **User** — an individual Superset user
|
||||
- **Group** — a FAB group
|
||||
- **Role** — a FAB role (e.g. Alpha, Gamma, or any custom role)
|
||||
|
||||
Subjects are used throughout Superset to assign **editors** (who can modify a resource) and
|
||||
**viewers** (who can view it). For new resource-specific assignments, Superset defaults to
|
||||
**Users** and **Groups** in subject pickers. Groups are the recommended way to grant access to a
|
||||
set of people because they represent organizational membership, while roles remain focused on
|
||||
capability grants such as "can read dashboards" or "can write charts".
|
||||
|
||||
Role subjects are still supported for backwards compatibility with features that previously used
|
||||
roles directly, including Row Level Security role assignments and `DASHBOARD_RBAC`. Existing role
|
||||
subject assignments continue to be enforced even when roles are not exposed in the default picker
|
||||
configuration. However, when an administrator edits a subject list, roles are not available as new
|
||||
dropdown values unless that picker has been configured to expose role subjects. Roles are not
|
||||
recommended for new subject assignments, because using roles for both permissions and resource
|
||||
membership couples two separate concerns.
|
||||
|
||||
Administrators can control which subject types are available in pickers with
|
||||
`SUBJECTS_RELATED_TYPES`. By default, this setting exposes only users and groups:
|
||||
|
||||
```python
|
||||
from superset.subjects.types import SubjectType
|
||||
|
||||
SUBJECTS_RELATED_TYPES = [
|
||||
SubjectType.USER,
|
||||
SubjectType.GROUP,
|
||||
]
|
||||
```
|
||||
|
||||
Set `SUBJECTS_RELATED_TYPES = None` to expose all subject types, including roles. To expose roles
|
||||
only for a specific entity, set that entity's override:
|
||||
|
||||
```python
|
||||
from superset.subjects.types import SubjectType
|
||||
|
||||
SUBJECTS_RELATED_TYPES = [
|
||||
SubjectType.USER,
|
||||
SubjectType.GROUP,
|
||||
]
|
||||
|
||||
# Leave dashboard, chart, and alert/report overrides unset so they inherit
|
||||
# the users + groups default. Expose roles only in the RLS subject picker for
|
||||
# compatibility with existing role-based RLS workflows.
|
||||
SUBJECTS_RELATED_TYPES_RLS = [
|
||||
SubjectType.USER,
|
||||
SubjectType.GROUP,
|
||||
SubjectType.ROLE,
|
||||
]
|
||||
```
|
||||
|
||||
Available per-entity overrides are:
|
||||
|
||||
- `SUBJECTS_RELATED_TYPES_DASHBOARDS` for dashboard editor/viewer pickers
|
||||
- `SUBJECTS_RELATED_TYPES_CHARTS` for chart editor/viewer pickers
|
||||
- `SUBJECTS_RELATED_TYPES_RLS` for Row Level Security subject pickers
|
||||
- `SUBJECTS_RELATED_TYPES_ALERT_REPORTS` for alert/report editor pickers
|
||||
|
||||
When an override is set, it replaces `SUBJECTS_RELATED_TYPES` for that picker. When it is `None`,
|
||||
the picker inherits the global default.
|
||||
|
||||
### Dashboard Access Control
|
||||
|
||||
Access to dashboards is managed via editors (subjects that have edit permissions to the dashboard).
|
||||
Non-editor user access can be managed in two ways. Note that dashboards must be published to be
|
||||
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)
|
||||
@@ -212,40 +146,30 @@ 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 and Chart-Level Access
|
||||
#### Dashboard-Level Access (DASHBOARD_RBAC)
|
||||
|
||||
For fine-grained control over which dashboards and charts specific users or groups can access,
|
||||
enable subject-based viewers:
|
||||
For fine-grained control over which dashboards specific roles can access, enable the
|
||||
`DASHBOARD_RBAC` feature flag:
|
||||
|
||||
```python
|
||||
FEATURE_FLAGS = {
|
||||
"ENABLE_VIEWERS": True,
|
||||
"DASHBOARD_RBAC": True,
|
||||
}
|
||||
```
|
||||
|
||||
With this enabled, you can assign viewer subjects to each dashboard or chart in its properties.
|
||||
Users will see resources where they are assigned directly, or indirectly through a group subject.
|
||||
Role subjects can also be enabled for compatibility, but groups are recommended for new viewer
|
||||
assignments.
|
||||
|
||||
`ENABLE_VIEWERS` can be adopted incrementally. Dashboards and charts with no assigned viewers keep
|
||||
the existing implicit dataset-access behavior: users who can access the underlying dataset can still
|
||||
see published dashboards that use that dataset and charts backed by that dataset. Assigning one or
|
||||
more viewers changes that specific resource to explicit viewer access for non-editors. Removing all
|
||||
viewers returns the resource to the dataset-based fallback. Explicit Viewers are the preferred model
|
||||
going forward; the implicit fallback may be deprecated and removed in a later major version.
|
||||
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:**
|
||||
- Viewer access uses normal dataset checks unless `VIEWER_PROMISCUOUS_MODE` is enabled
|
||||
- With `VIEWER_PROMISCUOUS_MODE`, dashboard viewer access can bypass dataset-level checks for
|
||||
charts and datasets in that dashboard
|
||||
- Dashboards and charts without assigned viewers fall back to dataset-based access
|
||||
- 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 permissions
|
||||
- Creating dashboard-specific access patterns that don't align with dataset ownership
|
||||
|
||||
### SQL Execution Security Considerations
|
||||
|
||||
@@ -377,16 +301,16 @@ 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 dataset, as well as a set of subjects.
|
||||
that are assigned to a particular dataset, 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 subject and the dataset it applies to
|
||||
- Then assign the clause to the **Finance** role and the dataset 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 subject, with a clause
|
||||
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.
|
||||
|
||||
@@ -397,14 +321,12 @@ RLS clauses also support **Jinja templating** when `ENABLE_TEMPLATE_PROCESSING`
|
||||
|
||||
There are two types of RLS filters:
|
||||
|
||||
- **Regular** — The filter clause is applied when the querying user matches one of the
|
||||
subjects assigned to the filter. Use this to restrict what specific users, roles, or groups
|
||||
can see.
|
||||
- **Base** — The filter clause is applied to **all** users _except_ those matching the assigned
|
||||
subjects. Use this to define a default restriction that privileged subjects (e.g. the Admin
|
||||
role subject) are exempt from. For example, a Base filter with clause `1 = 0` and the Admin
|
||||
role subject would hide all rows from everyone except Admin - useful as a deny-by-default
|
||||
baseline.
|
||||
- **Regular** — The filter clause is applied when the querying user belongs to one of the
|
||||
roles assigned to the filter. Use this to restrict what specific roles can see.
|
||||
- **Base** — The filter clause is applied to **all** users _except_ those in the assigned
|
||||
roles. Use this to define a default restriction that privileged roles (e.g. Admin) are
|
||||
exempt from. For example, a Base filter with clause `1 = 0` and the Admin role would
|
||||
hide all rows from everyone except Admin — useful as a deny-by-default baseline.
|
||||
|
||||
#### Group Keys and Filter Combination
|
||||
|
||||
@@ -494,20 +416,21 @@ GET /api/v1/rowlevelsecurity/
|
||||
GET /api/v1/rowlevelsecurity/?q=(filters:!((col:tables,opr:rel_m_m,value:<dataset_id>)))
|
||||
```
|
||||
|
||||
**Filter RLS rules by subject:**
|
||||
**Filter RLS rules by role:**
|
||||
|
||||
```
|
||||
GET /api/v1/rowlevelsecurity/?q=(filters:!((col:subjects,opr:rel_m_m,value:<subject_id>)))
|
||||
GET /api/v1/rowlevelsecurity/?q=(filters:!((col:roles,opr:rel_m_m,value:<role_id>)))
|
||||
```
|
||||
|
||||
**View details of a specific rule** (including clause, assigned datasets, and subjects):
|
||||
**View details of a specific rule** (including clause, assigned datasets, and roles):
|
||||
|
||||
```
|
||||
GET /api/v1/rowlevelsecurity/<id>
|
||||
```
|
||||
|
||||
The response includes the filter's `name`, `filter_type` (Regular or Base), `clause`,
|
||||
`group_key`, assigned `tables` (with id, schema, and table\_name), and assigned `subjects`.
|
||||
`group_key`, assigned `tables` (with id, schema, and table\_name), and assigned `roles`
|
||||
(with id and name).
|
||||
|
||||
:::tip Auditing RLS for virtual datasets
|
||||
To find all RLS rules that could affect a particular virtual dataset, query the list
|
||||
|
||||
@@ -26,7 +26,7 @@ import { StoryWithControls } from '../../../src/components/StorybookWrapper';
|
||||
|
||||
# MetadataBar
|
||||
|
||||
MetadataBar displays a row of metadata items (SQL info, editors, last modified, tags, dashboards, etc.) that collapse responsively based on available width.
|
||||
MetadataBar displays a row of metadata items (SQL info, owners, last modified, tags, dashboards, etc.) that collapse responsively based on available width.
|
||||
|
||||
## Live Example
|
||||
|
||||
@@ -43,9 +43,9 @@ MetadataBar displays a row of metadata items (SQL info, editors, last modified,
|
||||
title: "Click to view query"
|
||||
},
|
||||
{
|
||||
type: "editor",
|
||||
type: "owner",
|
||||
createdBy: "Jane Smith",
|
||||
editors: [
|
||||
owners: [
|
||||
"John Doe",
|
||||
"Mary Wilson"
|
||||
],
|
||||
@@ -104,9 +104,9 @@ function Demo() {
|
||||
const items = [
|
||||
{ type: 'sql', title: 'Click to view query' },
|
||||
{
|
||||
type: 'editor',
|
||||
type: 'owner',
|
||||
createdBy: 'Jane Smith',
|
||||
editors: ['John Doe', 'Mary Wilson'],
|
||||
owners: ['John Doe', 'Mary Wilson'],
|
||||
createdOn: 'a week ago',
|
||||
},
|
||||
{
|
||||
@@ -125,7 +125,7 @@ function Demo() {
|
||||
```tsx live
|
||||
function MinimalMetadata() {
|
||||
const items = [
|
||||
{ type: 'editor', createdBy: 'Admin', editors: ['Admin'], createdOn: 'yesterday' },
|
||||
{ type: 'owner', createdBy: 'Admin', owners: ['Admin'], createdOn: 'yesterday' },
|
||||
{ type: 'lastModified', value: '2 hours ago', modifiedBy: 'Admin' },
|
||||
];
|
||||
return <MetadataBar items={items} />;
|
||||
@@ -138,7 +138,7 @@ function MinimalMetadata() {
|
||||
function FullMetadata() {
|
||||
const items = [
|
||||
{ type: 'sql', title: 'SELECT * FROM ...' },
|
||||
{ type: 'editor', createdBy: 'Jane Smith', editors: ['Jane Smith', 'John Doe', 'Bob Wilson'], createdOn: '2 weeks ago' },
|
||||
{ type: 'owner', createdBy: 'Jane Smith', owners: ['Jane Smith', 'John Doe', 'Bob Wilson'], createdOn: '2 weeks ago' },
|
||||
{ type: 'lastModified', value: '3 days ago', modifiedBy: 'John Doe' },
|
||||
{ type: 'tags', values: ['production', 'finance', 'quarterly'] },
|
||||
{ type: 'dashboards', title: 'Used in 12 dashboards' },
|
||||
@@ -158,7 +158,7 @@ function FullMetadata() {
|
||||
| `createdBy` | `string` | `"Jane Smith"` | - |
|
||||
| `modifiedBy` | `string` | `"Jane Smith"` | - |
|
||||
| `description` | `string` | `"To preview the list of dashboards go to More settings."` | - |
|
||||
| `items` | `any` | `[{"type":"sql","title":"Click to view query"},{"type":"editor","createdBy":"Jane Smith","editors":["John Doe","Mary Wilson"],"createdOn":"a week ago"},{"type":"lastModified","value":"a week ago","modifiedBy":"Jane Smith"},{"type":"tags","values":["management","research","poc"]},{"type":"dashboards","title":"Added to 3 dashboards","description":"To preview the list of dashboards go to More settings."}]` | Items displayed in the metadata bar. The `editor` type shows editors/creators. |
|
||||
| `items` | `any` | `[{"type":"sql","title":"Click to view query"},{"type":"owner","createdBy":"Jane Smith","owners":["John Doe","Mary Wilson"],"createdOn":"a week ago"},{"type":"lastModified","value":"a week ago","modifiedBy":"Jane Smith"},{"type":"tags","values":["management","research","poc"]},{"type":"dashboards","title":"Added to 3 dashboards","description":"To preview the list of dashboards go to More settings."}]` | - |
|
||||
|
||||
## Import
|
||||
|
||||
|
||||
@@ -332,39 +332,15 @@ cd superset-frontend
|
||||
npm run build-translation
|
||||
|
||||
# Backend
|
||||
pybabel compile --use-fuzzy -d superset/translations
|
||||
pybabel compile -d superset/translations
|
||||
```
|
||||
|
||||
`--use-fuzzy` includes `#, fuzzy` entries in the compiled `.mo` files. Superset
|
||||
serves fuzzy translations on purpose: the frontend build (`po2json --fuzzy`)
|
||||
already includes them, `flask fab babel-compile` (used by the release images)
|
||||
compiles with `-f`, and the production `Dockerfile` compiles with `--use-fuzzy`
|
||||
as well. This keeps machine-generated (and other draft) translations visible in
|
||||
the UI rather than falling back to English while they await review.
|
||||
|
||||
### Backfilling missing translations with AI
|
||||
|
||||
For languages with many untranslated strings, the repo includes a script that
|
||||
uses Claude AI to generate draft translations for any missing entries. All
|
||||
AI-generated strings are marked `#, fuzzy` and tagged with an attribution
|
||||
comment so that human reviewers know they need to be checked.
|
||||
|
||||
Note that `#, fuzzy` marks a translation as *needing review*, not as *withheld*:
|
||||
both the frontend and backend builds serve fuzzy entries (see [Applying
|
||||
translations](#applying-translations) above), so an AI-generated string is shown
|
||||
in the UI as soon as it is built and deployed. Reviewers should verify each
|
||||
entry and remove the `#, fuzzy` flag to promote it to a confirmed translation.
|
||||
|
||||
The script never touches entries that must stay literal — icon names, enum
|
||||
values, SQL keywords, API field names, and example placeholders. These are
|
||||
registered in `superset/translations/do-not-translate.txt`;
|
||||
`scripts/translations/apply_do_not_translate.py` stamps them in `messages.pot`
|
||||
with a `#. do-not-translate` extracted comment (run automatically
|
||||
from `babel_update.sh`), which `pybabel update` then propagates to every
|
||||
catalog. To mark a new string do-not-translate, add its msgid to the registry.
|
||||
The backfill also honors that marker and any legacy do-not-translate translator
|
||||
comment (e.g. the `ru` catalog's `# Не переводить`), leaving such entries
|
||||
untranslated so they fall back to the source token.
|
||||
comment so that human reviewers know they need to be checked before merging.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ from superset.dashboards.commands.create import CreateDashboardCommand
|
||||
def test_create_dashboard_success():
|
||||
properties = {
|
||||
"dashboard_title": "Test Dashboard",
|
||||
"editors": [1]
|
||||
"owners": [1]
|
||||
}
|
||||
|
||||
command = CreateDashboardCommand(properties)
|
||||
@@ -275,11 +275,9 @@ def handle_validation_error(error):
|
||||
from typing import List, Optional, Dict, Any
|
||||
from superset.models.dashboard import Dashboard
|
||||
|
||||
def get_dashboards_by_editor(editor_id: int) -> List[Dashboard]:
|
||||
"""Get all dashboards editable by a specific subject"""
|
||||
return db.session.query(Dashboard).filter(
|
||||
Dashboard.editors.any(id=editor_id)
|
||||
).all()
|
||||
def get_dashboards_by_owner(owner_id: int) -> List[Dashboard]:
|
||||
"""Get all dashboards owned by a specific user"""
|
||||
return db.session.query(Dashboard).filter_by(owner_id=owner_id).all()
|
||||
|
||||
def create_dashboard(properties: Dict[str, Any]) -> Optional[Dashboard]:
|
||||
"""Create a new dashboard with the given properties"""
|
||||
|
||||
@@ -153,10 +153,10 @@ class DashboardDAO:
|
||||
return db.session.query(Dashboard).filter_by(slug=slug).first()
|
||||
|
||||
@classmethod
|
||||
def find_by_editor(cls, editor_id: int) -> List[Dashboard]:
|
||||
"""Find all dashboards editable by a subject"""
|
||||
return db.session.query(Dashboard).filter(
|
||||
Dashboard.editors.any(id=editor_id)
|
||||
def find_by_owner(cls, owner_id: int) -> List[Dashboard]:
|
||||
"""Find all dashboards owned by a user"""
|
||||
return db.session.query(Dashboard).filter_by(
|
||||
created_by_fk=owner_id
|
||||
).all()
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -120,7 +120,7 @@ SMTP_MAIL_FROM = "superset@localhost"
|
||||
# Must match where your frontend is running
|
||||
WEBDRIVER_BASEURL = "http://localhost:9000/"
|
||||
|
||||
ALERT_REPORTS_EXECUTORS = [ExecutorType.EDITOR]
|
||||
ALERT_REPORTS_EXECUTE_AS = [ExecutorType.OWNER]
|
||||
|
||||
FEATURE_FLAGS = {
|
||||
"ALERT_REPORTS": True,
|
||||
|
||||
@@ -181,23 +181,6 @@ value in milliseconds in the JSON Metadata field:
|
||||
Here, the entire dashboard will refresh at once if periodic refresh is on. The stagger time of 2.5
|
||||
seconds is ignored.
|
||||
|
||||
The manual **Refresh dashboard** button can also stagger its chart requests, controlled by the
|
||||
`SUPERSET_DASHBOARD_MANUAL_REFRESH_STAGGER_MS` server config in `superset_config.py`. This defaults
|
||||
to `0`, which preserves the original behavior where every chart request fires at the same time when
|
||||
the button is clicked. To opt in to staggering, set a positive number of milliseconds; the window
|
||||
then becomes the larger of this value and the per-dashboard `stagger_time` metadata, which itself
|
||||
defaults to `5000` milliseconds when it is not set explicitly. Setting `stagger_refresh` to `false`
|
||||
in a dashboard's JSON Metadata also disables staggering on the manual-refresh path, so its charts
|
||||
fire all at once even when the server config is positive. If the backend does not provide a value at
|
||||
all, for example an older backend that predates this config or a value explicitly set to `None`, the
|
||||
frontend falls back to a built-in default of `5000` milliseconds.
|
||||
|
||||
```python
|
||||
# superset_config.py
|
||||
# 0 (the default) fires every chart at once; set a positive value to stagger.
|
||||
SUPERSET_DASHBOARD_MANUAL_REFRESH_STAGGER_MS = 0
|
||||
```
|
||||
|
||||
**Why does ‘flask fab’ or superset freeze/hang/not responding when started (my home directory is
|
||||
NFS mounted)?**
|
||||
|
||||
|
||||
@@ -254,13 +254,16 @@ Understanding the Superset Points of View
|
||||
|
||||
- [Superset API](/developer-docs/api)
|
||||
|
||||
<!--
|
||||
The OSS Insight "Repo Activity" widget (https://next.ossinsight.io/) was
|
||||
intentionally removed. This page is rendered on the ASF-hosted website
|
||||
(superset.apache.org), so its contents are subject to ASF's third-party
|
||||
content and CSP rules. OSS Insight has no Data Processing Agreement (DPA)
|
||||
with the ASF, so we cannot embed its images/widgets here. Do not re-add it.
|
||||
-->
|
||||
## 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" />
|
||||
|
||||
@@ -211,8 +211,8 @@ slices and dashboards of your own.
|
||||
|
||||
### Manage access to Dashboards
|
||||
|
||||
Access to dashboards is managed via editors and permissions. Non-editor access can be controlled
|
||||
through dataset permissions, or through dashboard viewers when `ENABLE_VIEWERS` is enabled.
|
||||
Access to dashboards is managed via owners and permissions. Non-owner access can be controlled
|
||||
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](/admin-docs/security/#dashboard-access-control) section in the
|
||||
@@ -228,9 +228,7 @@ title of your dashboard.
|
||||
<img src={useBaseUrl("/img/tutorial/publish_button_dashboard.png" )} />
|
||||
|
||||
:::warning
|
||||
Draft dashboards are only visible to dashboard editors and admins. Published dashboards are visible
|
||||
to users with access to the underlying datasets, or, when `ENABLE_VIEWERS` is enabled, to users
|
||||
who have viewer access directly or through an assigned role or group subject.
|
||||
Draft dashboards are only visible to the dashboard owners and admins. Published dashboards are visible to all users with access to the underlying datasets or if RBAC is enabled, to the roles that have been granted access to the dashboard.
|
||||
:::
|
||||
|
||||
### Mark a Dashboard as Favorite
|
||||
|
||||
@@ -749,7 +749,7 @@ const config: Config = {
|
||||
showReadingTime: true,
|
||||
// Please change this to your repo.
|
||||
editUrl:
|
||||
'https://github.com/apache/superset/tree/master/docs',
|
||||
'https://github.com/facebook/docusaurus/edit/main/website/blog/',
|
||||
},
|
||||
theme: {
|
||||
customCss: require.resolve('./src/styles/custom.css'),
|
||||
|
||||
@@ -58,15 +58,26 @@
|
||||
"@fontsource/inter": "^5.2.8",
|
||||
"@mdx-js/react": "^3.1.1",
|
||||
"@saucelabs/theme-github-codeblock": "^0.3.0",
|
||||
"@storybook/addon-docs": "^10.4.5",
|
||||
"@storybook/addon-docs": "^8.6.18",
|
||||
"@storybook/blocks": "^8.6.15",
|
||||
"@storybook/channels": "^8.6.18",
|
||||
"@storybook/client-logger": "^8.6.18",
|
||||
"@storybook/components": "^8.6.18",
|
||||
"@storybook/core": "^8.6.18",
|
||||
"@storybook/core-events": "^8.6.18",
|
||||
"@storybook/csf": "^0.1.13",
|
||||
"@storybook/docs-tools": "^8.6.18",
|
||||
"@storybook/preview-api": "^8.6.18",
|
||||
"@storybook/theming": "^8.6.15",
|
||||
"@superset-ui/core": "^0.20.4",
|
||||
"@swc/core": "^1.15.43",
|
||||
"antd": "^6.5.0",
|
||||
"baseline-browser-mapping": "^2.10.40",
|
||||
"@swc/core": "^1.15.41",
|
||||
"antd": "^6.4.5",
|
||||
"baseline-browser-mapping": "^2.10.38",
|
||||
"caniuse-lite": "^1.0.30001799",
|
||||
"docusaurus-plugin-openapi-docs": "^5.1.0",
|
||||
"docusaurus-theme-openapi-docs": "^5.1.0",
|
||||
"js-yaml": "^5.2.0",
|
||||
"docusaurus-plugin-openapi-docs": "^5.0.2",
|
||||
"docusaurus-theme-openapi-docs": "^5.0.2",
|
||||
"js-yaml": "^4.2.0",
|
||||
"js-yaml-loader": "^1.2.2",
|
||||
"json-bigint": "^1.0.0",
|
||||
"prism-react-renderer": "^2.4.1",
|
||||
"react": "^18.3.1",
|
||||
@@ -77,8 +88,8 @@
|
||||
"react-table": "^7.8.0",
|
||||
"remark-import-partial": "^0.0.2",
|
||||
"reselect": "^5.2.0",
|
||||
"storybook": "^10.4.5",
|
||||
"swagger-ui-react": "^5.32.8",
|
||||
"storybook": "^8.6.18",
|
||||
"swagger-ui-react": "^5.32.6",
|
||||
"swc-loader": "^0.2.7",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"unist-util-visit": "^5.1.0"
|
||||
@@ -95,11 +106,11 @@
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"globals": "^17.7.0",
|
||||
"prettier": "^3.9.1",
|
||||
"globals": "^17.6.0",
|
||||
"prettier": "^3.8.4",
|
||||
"typescript": "~6.0.3",
|
||||
"typescript-eslint": "^8.62.0",
|
||||
"webpack": "^5.108.2"
|
||||
"typescript-eslint": "^8.61.1",
|
||||
"webpack": "^5.107.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@@ -117,16 +128,14 @@
|
||||
"react-redux": "^9.2.0",
|
||||
"@reduxjs/toolkit": "^2.5.0",
|
||||
"baseline-browser-mapping": "^2.9.19",
|
||||
"swagger-client": "3.37.3",
|
||||
"lodash": "4.18.1",
|
||||
"lodash-es": "4.18.1",
|
||||
"yaml": "1.10.3",
|
||||
"uuid": "11.1.1",
|
||||
"serialize-javascript": "7.0.5",
|
||||
"d3-color": "3.1.0",
|
||||
"ws": "^8.21.0",
|
||||
"@docusaurus/core/@docusaurus/utils/gray-matter/js-yaml": "^3.15.0",
|
||||
"@docusaurus/core/**/js-yaml": "^4.3.0",
|
||||
"docusaurus-plugin-openapi-docs/**/js-yaml": "^4.3.0"
|
||||
"ws": "^8.21.0"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ export interface DatabaseInfo {
|
||||
expressions_in_orderby?: boolean;
|
||||
|
||||
// Platform features
|
||||
limit_method?: number;
|
||||
limit_method?: string;
|
||||
limit_clause?: boolean;
|
||||
max_column_name?: number;
|
||||
supports_file_upload?: boolean;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
import Layout from '@theme/Layout';
|
||||
import { Avatar, Card, Col, Collapse, Row, Typography } from 'antd';
|
||||
import { load } from 'js-yaml';
|
||||
import BlurredSection from '../components/BlurredSection';
|
||||
import SectionHeader from '../components/SectionHeader';
|
||||
import DataSet from '../../../RESOURCES/INTHEWILD.yaml';
|
||||
@@ -37,7 +36,7 @@ interface DataSetType {
|
||||
categories: Record<string, Organization[]>;
|
||||
}
|
||||
|
||||
const typedDataSet = load(DataSet) as DataSetType;
|
||||
const typedDataSet = DataSet as DataSetType;
|
||||
|
||||
const ContributorAvatars = ({ contributors }: { contributors?: string[] }) => {
|
||||
if (!contributors?.length) return null;
|
||||
|
||||
@@ -22,7 +22,6 @@ import Link from '@docusaurus/Link';
|
||||
import { Card, Carousel, Flex } from 'antd';
|
||||
import styled from '@emotion/styled';
|
||||
import GitHubButton from 'react-github-btn';
|
||||
import { load } from 'js-yaml';
|
||||
import { mq } from '../utils';
|
||||
import SectionHeader from '../components/SectionHeader';
|
||||
import databaseData from '../data/databases.json';
|
||||
@@ -61,7 +60,7 @@ interface DataSetType {
|
||||
categories: Record<string, Organization[]>;
|
||||
}
|
||||
|
||||
const typedDataSet = load(DataSet) as DataSetType;
|
||||
const typedDataSet = DataSet as DataSetType;
|
||||
|
||||
// Extract all organizations with logos for the carousel
|
||||
const companiesWithLogos = Object.values(typedDataSet.categories)
|
||||
|
||||
4
docs/src/types/yaml.d.ts
vendored
@@ -18,11 +18,11 @@
|
||||
*/
|
||||
|
||||
declare module '*.yaml' {
|
||||
const content: string;
|
||||
const content: unknown;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.yml' {
|
||||
const content: string;
|
||||
const content: unknown;
|
||||
export default content;
|
||||
}
|
||||
|
||||
@@ -61,10 +61,10 @@ export default function webpackExtendPlugin(): Plugin<void> {
|
||||
);
|
||||
});
|
||||
|
||||
// Load YAML file as raw text string
|
||||
// Add YAML loader rule directly to existing rules
|
||||
config.module?.rules?.push({
|
||||
test: /\.ya?ml$/,
|
||||
type: 'asset/source',
|
||||
use: 'js-yaml-loader',
|
||||
});
|
||||
|
||||
// Add swc-loader rule for superset-frontend files
|
||||
@@ -168,6 +168,60 @@ export default function webpackExtendPlugin(): Plugin<void> {
|
||||
__dirname,
|
||||
'../../superset-frontend/packages/superset-core/src',
|
||||
),
|
||||
// Add proper Storybook aliases
|
||||
'@storybook/blocks': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/blocks',
|
||||
),
|
||||
'@storybook/components': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/components',
|
||||
),
|
||||
'@storybook/theming': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/theming',
|
||||
),
|
||||
'@storybook/client-logger': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/client-logger',
|
||||
),
|
||||
'@storybook/core-events': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/core-events',
|
||||
),
|
||||
// Add internal Storybook aliases
|
||||
'storybook/internal/components': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/components',
|
||||
),
|
||||
'storybook/internal/theming': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/theming',
|
||||
),
|
||||
'storybook/internal/client-logger': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/client-logger',
|
||||
),
|
||||
'storybook/internal/csf': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/csf',
|
||||
),
|
||||
'storybook/internal/preview-api': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/preview-api',
|
||||
),
|
||||
'storybook/internal/docs-tools': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/docs-tools',
|
||||
),
|
||||
'storybook/internal/core-events': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/core-events',
|
||||
),
|
||||
'storybook/internal/channels': path.resolve(
|
||||
__dirname,
|
||||
'../node_modules/@storybook/channels',
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
9
docs/static/.htaccess
vendored
@@ -22,14 +22,7 @@ RewriteRule ^(.*)$ https://superset.apache.org/$1 [R,L]
|
||||
RewriteCond %{HTTP_HOST} ^superset.incubator.apache.org$ [NC]
|
||||
RewriteRule ^(.*)$ https://superset.apache.org/$1 [R=301,L]
|
||||
|
||||
# CSP permissions for superset.apache.org
|
||||
# Additional domains required for docs site functionality:
|
||||
# - widget.kapa.ai: AI chatbot widget (uses Google reCAPTCHA). Approval here: https://privacy.apache.org/faq/committers.html
|
||||
# - *.googleapis.com, *.google.com, *.gstatic.com: Google Calendar embed, kapa.ai reCAPTCHA - all of these loaded with user consent, following policy laid out in https://privacy.apache.org/faq/committers.html
|
||||
# - github.com, *.github.com, *.githubusercontent.com: GitHub user-attachment images in docs (apex github.com serves user-attachments/* assets). Discussed/resolved in this thread: https://issues.apache.org/jira/browse/INFRA-25701?filter=-2 (DPA in place with GitHub)
|
||||
# - *.algolia.net, *.algolianet.com: Algolia DocSearch. Approved here: https://privacy.apache.org/faq/committers.html
|
||||
# See: https://infra.apache.org/tools/csp.html
|
||||
SetEnv CSP_PROJECT_DOMAINS "widget.kapa.ai https://*.googleapis.com/ https://*.google.com/ https://*.gstatic.com/ https://github.com/ https://*.github.com/ https://*.githubusercontent.com/ https://*.algolia.net/ https://*.algolianet.com/"
|
||||
Header set Content-Security-Policy "default-src data: blob: 'self' *.apache.org widget.kapa.ai *.githubusercontent.com *.scarf.sh *.googleapis.com *.google.com *.run.app *.gstatic.com *.github.com *.algolia.net *.algolianet.com 'unsafe-inline' 'unsafe-eval'; frame-src *; frame-ancestors 'self' *.google.com https://sidebar.bugherd.com; form-action 'self'; worker-src blob:; img-src 'self' blob: data: https:; font-src 'self'; object-src 'none'"
|
||||
|
||||
# REDIRECTS
|
||||
|
||||
|
||||
31
docs/static/feature-flags.json
vendored
@@ -87,12 +87,6 @@
|
||||
"lifecycle": "development",
|
||||
"description": "Enable semantic layers and show semantic views alongside datasets"
|
||||
},
|
||||
{
|
||||
"name": "SOFT_DELETE",
|
||||
"default": false,
|
||||
"lifecycle": "development",
|
||||
"description": "Temporary rollout / kill-switch gate for soft delete (default off = legacy hard delete). An emergency stop, not a clean rollback: flipping ON->OFF resurrects already-soft-deleted rows. Removed (along with its two gate points \u2014 BaseDAO.delete routing and the do_orm_execute visibility listener) once soft delete is stable."
|
||||
},
|
||||
{
|
||||
"name": "TABLE_V2_TIME_COMPARISON_ENABLED",
|
||||
"default": false,
|
||||
@@ -122,9 +116,9 @@
|
||||
},
|
||||
{
|
||||
"name": "ALERT_REPORT_SLACK_V2",
|
||||
"default": true,
|
||||
"default": false,
|
||||
"lifecycle": "testing",
|
||||
"description": "Enables Slack V2 integration for Alerts and Reports. Defaults to True; the legacy Slack v1 path is deprecated and will be removed in the next major release. Operators must grant the Slack bot both the `channels:read` and `groups:read` scopes so existing v1 recipients can be auto-upgraded on their next send. Without those scopes, file uploads fail (Slack retired the `files.upload` endpoint in 2025) and only text-only `chat_postMessage` sends will continue to work via the legacy path."
|
||||
"description": "Enables Slack V2 integration for Alerts and Reports"
|
||||
},
|
||||
{
|
||||
"name": "ALERT_REPORT_WEBHOOK",
|
||||
@@ -182,13 +176,6 @@
|
||||
"description": "Allows users to add a superset:// DB that can query across databases. Experimental with potential security/performance risks. See SUPERSET_META_DB_LIMIT.",
|
||||
"docs": "https://superset.apache.org/user-docs/databases/supported/superset-meta-database"
|
||||
},
|
||||
{
|
||||
"name": "ENABLE_VIEWERS",
|
||||
"default": false,
|
||||
"lifecycle": "testing",
|
||||
"description": "Subject-based viewer access control for dashboards and charts. When enabled, resources can have explicit viewer Subject assignments.",
|
||||
"category": "security"
|
||||
},
|
||||
{
|
||||
"name": "ESTIMATE_QUERY_COST",
|
||||
"default": false,
|
||||
@@ -263,6 +250,14 @@
|
||||
"description": "Enables CSS Templates in Settings menu and dashboard forms",
|
||||
"category": "runtime_config"
|
||||
},
|
||||
{
|
||||
"name": "DASHBOARD_RBAC",
|
||||
"default": false,
|
||||
"lifecycle": "stable",
|
||||
"description": "Role-based access control for dashboards",
|
||||
"docs": "https://superset.apache.org/docs/using-superset/creating-your-first-dashboard",
|
||||
"category": "runtime_config"
|
||||
},
|
||||
{
|
||||
"name": "DASHBOARD_VIRTUALIZATION",
|
||||
"default": true,
|
||||
@@ -400,6 +395,12 @@
|
||||
}
|
||||
],
|
||||
"deprecated": [
|
||||
{
|
||||
"name": "AVOID_COLORS_COLLISION",
|
||||
"default": true,
|
||||
"lifecycle": "deprecated",
|
||||
"description": "Avoid color collisions in charts by using distinct colors"
|
||||
},
|
||||
{
|
||||
"name": "DRILL_TO_DETAIL",
|
||||
"default": true,
|
||||
|
||||
4
docs/static/img/logos/camptocamp.svg
vendored
|
Before Width: | Height: | Size: 14 KiB |
BIN
docs/static/img/logos/craig.png
vendored
|
Before Width: | Height: | Size: 40 KiB |
BIN
docs/static/img/logos/geo2france.png
vendored
|
Before Width: | Height: | Size: 4.6 KiB |
2
docs/static/img/logos/geobretagne.svg
vendored
|
Before Width: | Height: | Size: 7.0 KiB |
108
docs/static/img/logos/georchestra.svg
vendored
@@ -1,108 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="76.919907mm"
|
||||
height="26.149284mm"
|
||||
viewBox="0 0 76.919907 26.149284"
|
||||
version="1.1"
|
||||
id="svg855"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
sodipodi:docname="georchestra-logo.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview857"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
fit-margin-top="2"
|
||||
fit-margin-right="2"
|
||||
fit-margin-bottom="2"
|
||||
fit-margin-left="2"
|
||||
inkscape:zoom="4.0920134"
|
||||
inkscape:cx="120.47859"
|
||||
inkscape:cy="47.775992"
|
||||
inkscape:window-width="2400"
|
||||
inkscape:window-height="1271"
|
||||
inkscape:window-x="2391"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs852" />
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-73.097929,-135.79112)">
|
||||
<g
|
||||
id="g53648"
|
||||
transform="matrix(1.1048988,0,0,1.1048988,-54.141498,96.632368)">
|
||||
<path
|
||||
id="path164290-3-6-4"
|
||||
style="fill:#85127e;fill-opacity:0.4;stroke-width:0.606168;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
d="m 126.99257,37.251152 a 10.023325,10.023325 0 0 0 -10.0231,10.023355 10.023325,10.023325 0 0 0 10.0231,10.023083 10.023325,10.023325 0 0 0 9.62187,-7.232846 3.0318022,3.5371027 0 0 1 -2.01469,-3.330589 3.0318022,3.5371027 0 0 1 1.70117,-3.175791 10.023325,10.023325 0 0 0 -9.30835,-6.307212 z"
|
||||
inkscape:export-filename="C:\Users\Agathe\Desktop\georchestra_univers.png"
|
||||
inkscape:export-xdpi="200"
|
||||
inkscape:export-ydpi="200" />
|
||||
<path
|
||||
id="path20251-5-9-8-2"
|
||||
style="fill:#85127e;fill-opacity:1;stroke-width:0.337452;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
d="m 138.54037,41.724815 a 4.988567,4.988567 0 0 0 -4.9887,4.988712 4.988567,4.988567 0 0 0 4.9887,4.98844 4.988567,4.988567 0 0 0 4.98844,-4.98844 4.988567,4.988567 0 0 0 -4.98844,-4.988712 z m 0,2.683748 a 2.3048444,2.3048444 0 0 1 2.30472,2.304964 2.3048444,2.3048444 0 0 1 -2.30472,2.304704 2.3048444,2.3048444 0 0 1 -2.30496,-2.304704 2.3048444,2.3048444 0 0 1 2.30496,-2.304964 z"
|
||||
inkscape:export-filename="C:\Users\Agathe\Desktop\georchestra_univers.png"
|
||||
inkscape:export-xdpi="200"
|
||||
inkscape:export-ydpi="200" />
|
||||
<g
|
||||
aria-label="ge rchestra"
|
||||
id="text10089-26-6-9"
|
||||
style="font-size:9.62958px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto, Normal';letter-spacing:0px;fill:#85127e;stroke-width:0.601849">
|
||||
<path
|
||||
d="m 123.84851,51.576041 q -0.66682,0 -1.14556,-0.177819 -0.47875,-0.177819 -0.76941,-0.475324 -0.29067,-0.297505 -0.40351,-0.653142 l 1.11478,-0.270148 q 0.0752,0.140203 0.21886,0.287245 0.14362,0.150463 0.38641,0.249631 0.24621,0.102588 0.61895,0.102588 0.52662,0 0.872,-0.25305 0.34537,-0.25305 0.34537,-0.817283 v -0.995103 h -0.0615 q -0.0957,0.191498 -0.28041,0.393254 -0.18123,0.201756 -0.48216,0.33854 -0.2975,0.136784 -0.74889,0.136784 -0.60527,0 -1.09769,-0.283827 -0.489,-0.287246 -0.77967,-0.854899 -0.28724,-0.571072 -0.28724,-1.42939 0,-0.865158 0.28724,-1.460167 0.29067,-0.59843 0.78309,-0.906193 0.49242,-0.311183 1.09769,-0.311183 0.46165,0 0.75915,0.157301 0.30092,0.153882 0.47874,0.372736 0.17782,0.215434 0.27015,0.406932 h 0.0684 v -0.868577 h 1.2208 v 5.337987 q 0,0.659982 -0.32144,1.09769 -0.32144,0.441128 -0.87884,0.656563 -0.55739,0.218854 -1.26525,0.218854 z m 0.0103,-3.104992 q 0.39325,0 0.67024,-0.191498 0.27699,-0.191497 0.42061,-0.550555 0.14362,-0.359057 0.14362,-0.861738 0,-0.495841 -0.14362,-0.868577 -0.1402,-0.372736 -0.41719,-0.577911 -0.27357,-0.208596 -0.67366,-0.208596 -0.41377,0 -0.69076,0.215435 -0.27699,0.215434 -0.41719,0.59159 -0.1402,0.372736 -0.1402,0.848059 0,0.482163 0.1402,0.84464 0.14362,0.359058 0.42061,0.560814 0.28041,0.198337 0.68734,0.198337 z"
|
||||
id="path1811" />
|
||||
<path
|
||||
d="m 129.91145,49.620032 q -0.78993,0 -1.36442,-0.328281 -0.57107,-0.3317 -0.87883,-0.936969 -0.30777,-0.608688 -0.30777,-1.43281 0,-0.810444 0.30777,-1.422552 0.31118,-0.615527 0.86857,-0.957486 0.5574,-0.345379 1.30971,-0.345379 0.48558,0 0.91645,0.157301 0.43429,0.153882 0.76599,0.478743 0.33512,0.324862 0.52662,0.827542 0.19149,0.499261 0.19149,1.19002 v 0.379575 h -4.30527 v -0.834382 h 3.11867 q -0.003,-0.355638 -0.15388,-0.632625 -0.15046,-0.280406 -0.42061,-0.441127 -0.26673,-0.160721 -0.62236,-0.160721 -0.37958,0 -0.66683,0.184658 -0.28724,0.181238 -0.44796,0.478743 -0.1573,0.294085 -0.16072,0.646303 v 0.728374 q 0,0.458226 0.16756,0.786507 0.16756,0.324862 0.46848,0.499261 0.30093,0.17098 0.70444,0.17098 0.27015,0 0.489,-0.07523 0.21885,-0.07865 0.37957,-0.229113 0.16073,-0.150462 0.2428,-0.372736 l 1.15582,0.129944 q -0.10943,0.458226 -0.41719,0.800186 -0.30435,0.33854 -0.77967,0.526617 -0.47532,0.184658 -1.08743,0.184658 z"
|
||||
id="path1813" />
|
||||
<path
|
||||
d="m 145.2449,49.517445 v -5.252498 h 1.20027 v 0.875416 h 0.0547 q 0.14362,-0.454806 0.49242,-0.701017 0.35222,-0.24963 0.8036,-0.24963 0.10259,0 0.22912,0.01026 0.12994,0.0068 0.21543,0.02394 v 1.138725 q -0.0787,-0.02736 -0.24963,-0.04787 -0.16756,-0.02394 -0.32486,-0.02394 -0.33854,0 -0.60869,0.147043 -0.26673,0.143623 -0.42061,0.400092 -0.15388,0.25647 -0.15388,0.59159 v 3.087895 z"
|
||||
style="font-weight:600;font-family:inter;-inkscape-font-specification:'inter Semi-Bold'"
|
||||
id="path1815" />
|
||||
<path
|
||||
d="m 151.13685,49.620032 q -0.7865,0 -1.35074,-0.345379 -0.56081,-0.345379 -0.86516,-0.954067 -0.30092,-0.612107 -0.30092,-1.408873 0,-0.800185 0.30776,-1.412293 0.30777,-0.615527 0.86858,-0.957486 0.56423,-0.345379 1.33364,-0.345379 0.63947,0 1.13189,0.235952 0.49584,0.232532 0.78993,0.659982 0.29408,0.424029 0.33512,0.991682 h -1.18318 q -0.0718,-0.379575 -0.34196,-0.632625 -0.26673,-0.256469 -0.7147,-0.256469 -0.37957,0 -0.66682,0.205175 -0.28725,0.201756 -0.44797,0.581331 -0.1573,0.379575 -0.1573,0.909613 0,0.536876 0.1573,0.92329 0.1573,0.382995 0.44113,0.59159 0.28725,0.205176 0.67366,0.205176 0.27357,0 0.489,-0.102588 0.21886,-0.106007 0.3659,-0.304344 0.14704,-0.198336 0.20176,-0.482163 h 1.18318 q -0.0445,0.557394 -0.32829,0.988263 -0.28382,0.42745 -0.77282,0.670241 -0.48901,0.239371 -1.14899,0.239371 z"
|
||||
style="font-weight:600;font-family:inter;-inkscape-font-specification:'inter Semi-Bold'"
|
||||
id="path1817" />
|
||||
<path
|
||||
d="m 155.64387,46.439809 v 3.077636 h -1.2379 v -7.003331 h 1.21054 v 2.643347 h 0.0615 q 0.18466,-0.444547 0.57107,-0.701017 0.38984,-0.259889 0.99169,-0.259889 0.54713,0 0.95406,0.229113 0.40694,0.229113 0.62921,0.67024 0.22569,0.441128 0.22569,1.077173 v 3.344364 h -1.23789 v -3.152867 q 0,-0.530037 -0.27357,-0.824122 -0.27015,-0.297505 -0.75915,-0.297505 -0.32828,0 -0.58817,0.143623 -0.25647,0.140203 -0.40351,0.406932 -0.14362,0.266728 -0.14362,0.646303 z"
|
||||
style="font-weight:600;font-family:inter;-inkscape-font-specification:'inter Semi-Bold'"
|
||||
id="path1819" />
|
||||
<path
|
||||
d="m 162.6335,49.620032 q -0.78992,0 -1.36441,-0.328281 -0.57108,-0.3317 -0.87884,-0.936969 -0.30776,-0.608688 -0.30776,-1.43281 0,-0.810444 0.30776,-1.422552 0.31118,-0.615527 0.86858,-0.957486 0.55739,-0.345379 1.3097,-0.345379 0.48558,0 0.91645,0.157301 0.43429,0.153882 0.76599,0.478743 0.33512,0.324862 0.52662,0.827542 0.1915,0.499261 0.1915,1.19002 v 0.379575 h -4.30527 v -0.834382 h 3.11867 q -0.003,-0.355638 -0.15388,-0.632625 -0.15047,-0.280406 -0.42061,-0.441127 -0.26673,-0.160721 -0.62237,-0.160721 -0.37958,0 -0.66682,0.184658 -0.28725,0.181238 -0.44797,0.478743 -0.1573,0.294085 -0.16072,0.646303 v 0.728374 q 0,0.458226 0.16756,0.786507 0.16756,0.324862 0.46849,0.499261 0.30092,0.17098 0.70443,0.17098 0.27015,0 0.489,-0.07523 0.21886,-0.07865 0.37958,-0.229113 0.16072,-0.150462 0.24279,-0.372736 l 1.15582,0.129944 q -0.10942,0.458226 -0.41719,0.800186 -0.30434,0.33854 -0.77967,0.526617 -0.47532,0.184658 -1.08743,0.184658 z"
|
||||
style="font-weight:600;font-family:inter;-inkscape-font-specification:'inter Semi-Bold'"
|
||||
id="path1821" />
|
||||
<path
|
||||
d="m 170.16686,45.653302 -1.12846,0.123106 q -0.0479,-0.17098 -0.16756,-0.321442 -0.11627,-0.150462 -0.31461,-0.242792 -0.19833,-0.09233 -0.48558,-0.09233 -0.38641,0 -0.64972,0.167561 -0.25989,0.16756 -0.25647,0.434288 -0.003,0.229113 0.16756,0.372736 0.1744,0.143623 0.57449,0.235952 l 0.89593,0.191497 q 0.74548,0.160721 1.10795,0.50952 0.3659,0.348799 0.36932,0.913032 -0.003,0.495841 -0.29067,0.875416 -0.28382,0.376156 -0.78992,0.588171 -0.5061,0.212014 -1.16267,0.212014 -0.96432,0 -1.55249,-0.403512 -0.58817,-0.406932 -0.70102,-1.131886 l 1.20712,-0.116266 q 0.0821,0.355638 0.3488,0.536876 0.26673,0.181239 0.69417,0.181239 0.44113,0 0.70786,-0.181239 0.27015,-0.181238 0.27015,-0.447966 0,-0.225694 -0.1744,-0.372736 -0.17098,-0.147043 -0.53346,-0.225694 l -0.89593,-0.188077 q -0.75573,-0.157302 -1.11821,-0.530038 -0.36248,-0.376155 -0.35906,-0.950647 -0.003,-0.485582 0.26331,-0.84122 0.27015,-0.359058 0.74889,-0.553975 0.48217,-0.198336 1.11137,-0.198336 0.92329,0 1.45333,0.393253 0.53346,0.393254 0.65998,1.063495 z"
|
||||
style="font-weight:600;font-family:inter;-inkscape-font-specification:'inter Semi-Bold'"
|
||||
id="path1823" />
|
||||
<path
|
||||
d="m 173.925,44.264947 v 0.957486 h -3.01951 v -0.957486 z m -2.27403,-1.258411 h 1.23789 v 4.931056 q 0,0.24963 0.0752,0.382994 0.0787,0.129945 0.20518,0.177819 0.12652,0.04788 0.2804,0.04788 0.11627,0 0.21202,-0.0171 0.0992,-0.0171 0.15046,-0.03078 l 0.2086,0.967746 q -0.0992,0.0342 -0.28383,0.07523 -0.18124,0.04104 -0.44455,0.04787 -0.46506,0.01368 -0.8378,-0.140203 -0.37274,-0.157302 -0.59159,-0.485583 -0.21543,-0.328281 -0.21201,-0.820703 z"
|
||||
style="font-weight:600;font-family:inter;-inkscape-font-specification:'inter Semi-Bold'"
|
||||
id="path1825" />
|
||||
<path
|
||||
d="m 174.96112,49.517445 v -5.252498 h 1.20028 v 0.875416 h 0.0547 q 0.14363,-0.454806 0.49242,-0.701017 0.35222,-0.24963 0.80361,-0.24963 0.10259,0 0.22911,0.01026 0.12995,0.0068 0.21544,0.02394 v 1.138725 q -0.0787,-0.02736 -0.24963,-0.04787 -0.16756,-0.02394 -0.32487,-0.02394 -0.33853,0 -0.60868,0.147043 -0.26673,0.143623 -0.42061,0.400092 -0.15388,0.25647 -0.15388,0.59159 v 3.087895 z"
|
||||
style="font-weight:600;font-family:inter;-inkscape-font-specification:'inter Semi-Bold'"
|
||||
id="path1827" />
|
||||
<path
|
||||
d="m 180.19309,49.623452 q -0.49926,0 -0.89936,-0.177819 -0.39667,-0.181238 -0.6292,-0.533457 -0.22911,-0.352218 -0.22911,-0.868577 0,-0.444547 0.16414,-0.735213 0.16414,-0.290665 0.44796,-0.465065 0.28383,-0.174399 0.63947,-0.263309 0.35905,-0.09233 0.74205,-0.133364 0.46164,-0.04787 0.74889,-0.08549 0.28725,-0.04104 0.41719,-0.123105 0.13337,-0.08549 0.13337,-0.263309 v -0.02052 q 0,-0.386415 -0.22912,-0.59843 -0.22911,-0.212014 -0.65998,-0.212014 -0.45481,0 -0.72153,0.198336 -0.26331,0.198337 -0.35564,0.468485 L 178.6064,45.64646 q 0.13678,-0.478743 0.45138,-0.800185 0.3146,-0.324862 0.76941,-0.485583 0.45481,-0.16414 1.00536,-0.16414 0.37958,0 0.75573,0.08891 0.37616,0.08891 0.68734,0.294085 0.31118,0.201757 0.49926,0.550555 0.1915,0.348799 0.1915,0.871997 v 3.515344 h -1.19002 V 48.79591 h -0.041 q -0.11284,0.218854 -0.31802,0.410351 -0.20175,0.188078 -0.50952,0.304344 -0.30434,0.112847 -0.71469,0.112847 z m 0.32144,-0.909612 q 0.37274,0 0.6463,-0.147043 0.27357,-0.150462 0.42061,-0.396673 0.15047,-0.246211 0.15047,-0.536876 v -0.618947 q -0.0581,0.04787 -0.19834,0.08891 -0.13679,0.04104 -0.30776,0.07181 -0.17098,0.03078 -0.33854,0.05471 -0.16756,0.02394 -0.29067,0.04104 -0.27699,0.03761 -0.49584,0.123105 -0.21886,0.08549 -0.34538,0.239372 -0.12653,0.150462 -0.12653,0.389834 0,0.341959 0.24963,0.516358 0.24964,0.1744 0.63605,0.1744 z"
|
||||
style="font-weight:600;font-family:inter;-inkscape-font-specification:'inter Semi-Bold'"
|
||||
id="path1829" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 12 KiB |
1
docs/static/img/logos/jDev.svg
vendored
|
Before Width: | Height: | Size: 26 KiB |
BIN
docs/static/img/logos/mel.jpg
vendored
|
Before Width: | Height: | Size: 27 KiB |
BIN
docs/static/img/logos/pi-Geosolutions.png
vendored
|
Before Width: | Height: | Size: 22 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="178" height="34" version="1.0" viewBox="27 27 367 70"><switch><foreignObject width="1" height="1" x="0" y="0" requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/"/><g><path d="M221.8 47.9c1.3 4.4 5 7.1 10.9 7.1 6 0 10.1-2.8 10.1-7.9 0-4.2-2.6-6.8-9.9-7.8-4.1-.6-5.5-1.6-5.5-3.6 0-2.2 1.8-3.2 4.5-3.2 3.3 0 5.1 1.5 5.8 4.4l4.2-1.2c-1.1-4.6-4.5-7.2-10.1-7.2-5.5 0-9.1 2.6-9.1 7.5 0 3.5 1.8 6.4 9 7.4 4.7.6 6.2 1.7 6.2 3.9 0 2.4-1.9 3.6-5.1 3.6-3.8 0-6-1.7-7.1-4.7zm-21.1-8.3c.5-4 2.9-6.8 7.1-6.8 3.9 0 6.5 2.4 6.5 6.8zm18.3 1.1c0-7.9-4.4-12.1-11.1-12.1-7.6 0-11.9 5.3-11.9 13.2 0 8 4.3 13.2 12.1 13.2 5.6 0 9.2-2.7 10.5-7l-4.3-1.4c-.9 3.2-3.5 4.1-6.2 4.1-4.9 0-7.1-3.1-7.4-7.2H219zm-44.7 13.8V35.9c2.5 2.4 9.6 12.8 12.4 18.6h4.6V29h-4.5v17.1c-3.3-5.9-7.9-12-12.8-17.1h-4.3v25.5zm-27.5 0V35.9c2.5 2.4 9.6 12.8 12.4 18.6h4.6V29h-4.5v17.1c-3.3-5.9-7.9-12-12.7-17.1h-4.3v25.5zm-27.4-14.9c.5-4 2.9-6.8 7.1-6.8 3.9 0 6.5 2.4 6.5 6.8zm18.2 1.1c0-7.9-4.4-12.1-11.1-12.1-7.6 0-11.9 5.3-11.9 13.2 0 8 4.3 13.2 12.1 13.2 5.6 0 9.2-2.7 10.5-7l-4.3-1.4c-.9 3.2-3.5 4.1-6.2 4.1-4.9 0-7.1-3.1-7.4-7.2h18.3zM101 33.2c3.6 0 5.5 1.7 5.5 4.6 0 2.6-1.6 4.4-5 4.4h-6.1v-9zm4.4 12.3c4.5-1.5 5.9-4.9 5.9-8.2 0-5.2-3.6-8.3-9.8-8.3H90.9v25.5h4.5v-8.3h5.2l1.7 2.8c3 4.9 4.2 5.7 9 5.7v-4.3c-2.5 0-3.4-.8-5.3-3.9zM383.9 71.9c2.8 0 4.8 1.8 4.8 5.1h-9.9c.3-3 2-5.1 5.1-5.1m8.8 6c0-6.1-3.4-9.5-8.8-9.5-6 0-9.4 4.1-9.4 10.3 0 6.1 3.4 10.3 9.7 10.3 4.5 0 7.2-2.1 8.2-5.6l-3.5-1.2c-.6 2-2.3 3-4.7 3-3.5 0-5.1-2.2-5.4-5.2h14v-2.1zm-21.5-15.5H367v26.2h4.2zm-17.4 22.7c-3.3 0-5.3-2.4-5.3-6.4s2.1-6.4 5.3-6.4 5.3 2.4 5.3 6.4c0 3.9-2.1 6.4-5.3 6.4m0 3.8c5.8 0 9.7-3.9 9.7-10.2s-3.9-10.2-9.7-10.2c-5.9 0-9.8 3.9-9.8 10.2.1 6.3 3.9 10.2 9.8 10.2m-22-3.7c-3.3 0-5.4-2.5-5.4-6.5s2.1-6.5 5.4-6.5 5.4 2.5 5.4 6.5c.1 4-2.1 6.5-5.4 6.5M326.4 96V85.5h.2c1.2 2.4 3.7 3.5 6.2 3.5 5 0 8.9-3.9 8.9-10.3s-3.9-10.3-8.9-10.3c-2.5 0-5.1 1.1-6.2 3.5h-.2v-3.1h-4.2V96zm-17.3-10.9c-3.3 0-5.3-2.4-5.3-6.4s2.1-6.4 5.3-6.4 5.3 2.4 5.3 6.4c.1 3.9-2 6.4-5.3 6.4m0 3.8c5.8 0 9.7-3.9 9.7-10.2s-3.9-10.2-9.7-10.2c-5.9 0-9.8 3.9-9.8 10.2.1 6.3 4 10.2 9.8 10.2m-10.8-20.3c-.5-.1-1-.1-1.5-.1-2.5 0-4.4.8-5.4 3.5h-.2v-3.2H287v19.7h4.2v-9.7c0-5.6 2.4-6.1 4.7-6.1.8 0 1.5.1 2.3.2v-4.3zm-17.6 16.2c-3 0-3.4-.9-3.4-6.3v-5.9h5.7v-3.7h-5.7v-4.8H273v4.8h-3.7v3.7h3.7v7c0 7 1.8 9.1 7 9.1 1 0 2.3 0 3.5-.1v-3.8zM259 71.9c2.8 0 4.8 1.8 4.8 5.1h-9.9c.4-3 2.1-5.1 5.1-5.1m8.9 6c0-6.1-3.4-9.5-8.8-9.5-6 0-9.4 4.1-9.4 10.3 0 6.1 3.4 10.3 9.7 10.3 4.5 0 7.2-2.1 8.2-5.6l-3.5-1.2c-.6 2-2.3 3-4.7 3-3.5 0-5.1-2.2-5.4-5.2h14v-2.1zm-3.9-17-9.1 3.2 1.1 3.1 9.1-3.1zm-20 2.2h-4.4c-2.9 5.9-5.5 11.8-7.6 18.6h-.3c-2.1-6.8-4.8-12.7-7.6-18.6h-4.4l-3.1 25.5h4.5l2-17.6c2.4 5.4 4.5 10.9 6.3 16.8h5q2.7-8.7 6.3-16.8l2 17.6h4.5zm-41.2 21.7c-3 0-3.4-.9-3.4-6.3v-5.9h5.7v-3.7h-5.7v-4.8h-4.2v4.8h-3.7v3.7h3.7v7c0 7 1.8 9.1 7 9.1 1 0 2.3 0 3.5-.1v-3.8zm-21.7-12.9c2.8 0 4.8 1.8 4.8 5.1H176c.4-3 2.1-5.1 5.1-5.1m8.9 6c0-6.1-3.4-9.5-8.8-9.5-6 0-9.4 4.1-9.4 10.3 0 6.1 3.4 10.3 9.7 10.3 4.5 0 7.2-2.1 8.2-5.6l-3.5-1.2c-.6 2-2.3 3-4.7 3-3.5 0-5.1-2.2-5.4-5.2h14v-2.1zm-37.3-6c2.8 0 4.8 1.8 4.8 5.1h-9.9c.3-3 2-5.1 5.1-5.1m8.8 6c0-6.1-3.4-9.5-8.8-9.5-6 0-9.3 4.1-9.3 10.3 0 6.1 3.4 10.3 9.7 10.3 4.5 0 7.2-2.1 8.2-5.6l-3.5-1.2c-.6 2-2.3 3-4.7 3-3.5 0-5.1-2.2-5.4-5.2h14v-2.1zm-21.9-15.5h-4.2v26.2h4.2zm-9.1 0h-4.2v26.2h4.2zm-9.4 6.4h-4.2v19.7h4.2zm-2-2.2c1.4 0 2.6-1.2 2.6-2.7 0-1.4-1.2-2.6-2.6-2.6-1.5 0-2.7 1.2-2.7 2.6s1.2 2.7 2.7 2.7m-14.3 22 9-25.5H109l-7.2 21h-.3l-7.2-21h-4.8l9 25.5zM57.4 74.6c-3.7-5.3-6.2-6.9-11.4-7.7v4.9c3.6.5 5.3 2.4 7.6 5.7 6.2 8.9 9.7 12.5 22.3 11.9v-4.7c-9.7.7-13-2.3-18.5-10.1m3.1-2.4c5.3 7.3 8.1 9.8 15.4 9.2v-4.7c-5.4.6-8-2.1-11.7-7.4-4.5-6.4-9.6-9.9-18.2-10.3v4.8c6.1.2 10.1 2.3 14.5 8.4M28.3 88.8h4.9V47.9c-1.5.5-3.4 1.1-4.9 1.8zm13.6-43.2c-1.5.2-3.4.5-4.9.9v42.2h4.9zm26 4.7c0-8.1-6.4-13.5-19-13.5-6.6 0-14.5 1.5-20.6 4v5c5.6-2.5 13.7-4.3 20.6-4.3 9.1 0 14.1 3.1 14.1 8.9 0 3.4-1.7 6.4-4.8 8.3 1.3.7 2.7 1.8 3.8 2.8 3.8-2.4 5.9-6.5 5.9-11.2m-18.4-22c-7 0-14.2 1.5-21.1 3.8v5C36 34.3 43.2 33 49.5 33c14.3 0 22.7 6.5 22.7 16.8 0 6-2.6 11.1-7.5 14.5 1 1.1 2.1 2.4 3 3.5 6.1-4.2 9.4-10.9 9.4-18-.1-13-10.6-21.5-27.6-21.5"/></g></switch></svg>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
@@ -30,6 +30,7 @@
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"../superset-frontend/**/*",
|
||||
"src/webpack.extend.ts",
|
||||
"src/shims/**"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -519,80 +519,6 @@ For a connection to a SQL endpoint you need to use the HTTP path from the endpoi
|
||||
{"connect_args": {"http_path": "/sql/1.0/endpoints/****", "driver_path": "/path/to/odbc/driver"}}
|
||||
```
|
||||
|
||||
##### OAuth2 Authentication
|
||||
|
||||
Superset supports OAuth2 authentication for Databricks, allowing users to authenticate with their personal Databricks accounts instead of using shared access tokens. This provides better security and audit capabilities.
|
||||
|
||||
###### Prerequisites
|
||||
|
||||
1. Create an OAuth2 application in your Databricks account:
|
||||
- Go to your Databricks account console
|
||||
- Navigate to **Settings** → **Developer** → **OAuth apps**
|
||||
- Create a new OAuth app with the redirect URI: `http://your-superset-host:port/api/v1/database/oauth2/`
|
||||
|
||||
2. Configure OAuth2 in your `superset_config.py`:
|
||||
|
||||
```python
|
||||
from datetime import timedelta
|
||||
|
||||
# OAuth2 configuration for Databricks
|
||||
# The authorization endpoint is derived from your Databricks workspace host; the
|
||||
# token endpoint must be set explicitly (see notes below).
|
||||
DATABASE_OAUTH2_CLIENTS = {
|
||||
"Databricks (legacy)": {
|
||||
"id": "your-databricks-client-id",
|
||||
"secret": "your-databricks-client-secret",
|
||||
"scope": "sql",
|
||||
"token_request_uri": "https://your-workspace-host/oidc/v1/token",
|
||||
},
|
||||
"Databricks": {
|
||||
"id": "your-databricks-client-id",
|
||||
"secret": "your-databricks-client-secret",
|
||||
"scope": "sql",
|
||||
"token_request_uri": "https://your-workspace-host/oidc/v1/token",
|
||||
},
|
||||
}
|
||||
|
||||
# OAuth2 redirect URI (adjust hostname/port for your setup)
|
||||
DATABASE_OAUTH2_REDIRECT_URI = "http://your-superset-host:port/api/v1/database/oauth2/"
|
||||
|
||||
# Optional: OAuth2 timeout
|
||||
DATABASE_OAUTH2_TIMEOUT = timedelta(seconds=30)
|
||||
```
|
||||
|
||||
Replace the following placeholders:
|
||||
- `your-databricks-client-id`: Your Databricks OAuth2 application client ID
|
||||
- `your-databricks-client-secret`: Your Databricks OAuth2 application client secret
|
||||
- `your-superset-host:port`: Your Superset instance hostname and port
|
||||
|
||||
**Multi-Cloud Provider Support**
|
||||
|
||||
Databricks fronts the user-to-machine (U2M) OAuth2 flow on every workspace at
|
||||
`https://<workspace-host>/oidc/v1/authorize` and
|
||||
`https://<workspace-host>/oidc/v1/token`, regardless of whether the workspace
|
||||
runs on AWS, Azure, or GCP. Superset derives the **authorization** endpoint
|
||||
directly from your connection's host, so no cloud provider or account/tenant
|
||||
identifier needs to be configured.
|
||||
|
||||
The **token** endpoint cannot be auto-derived (token exchange has no database
|
||||
context to read the host), so you must supply `token_request_uri` in
|
||||
`DATABASE_OAUTH2_CLIENTS`, set to `https://<workspace-host>/oidc/v1/token` for
|
||||
your workspace.
|
||||
|
||||
If you supply a fully-resolved `authorization_request_uri` (and/or
|
||||
`token_request_uri`), those values take precedence over the host-derived
|
||||
defaults.
|
||||
|
||||
###### Usage
|
||||
|
||||
Once configured, users can:
|
||||
|
||||
1. Connect to Databricks databases normally using access tokens
|
||||
2. When querying data, Superset will automatically redirect users to authenticate with Databricks if needed
|
||||
3. User-specific OAuth2 tokens will be used for database connections, providing better security and audit trails
|
||||
|
||||
This feature works with both "Databricks (legacy)" and "Databricks" engine types and automatically supports all major cloud providers (AWS, Azure, GCP).
|
||||
|
||||
#### Denodo
|
||||
|
||||
The recommended connector library for Denodo is
|
||||
|
||||
@@ -212,13 +212,16 @@ Understanding the Superset Points of View
|
||||
|
||||
- [Superset API](https://superset.apache.org/docs/rest-api)
|
||||
|
||||
<!--
|
||||
The OSS Insight "Repo Activity" widget (https://next.ossinsight.io/) was
|
||||
intentionally removed. This page is rendered on the ASF-hosted website
|
||||
(superset.apache.org), so its contents are subject to ASF's third-party
|
||||
content and CSP rules. OSS Insight has no Data Processing Agreement (DPA)
|
||||
with the ASF, so we cannot embed its images/widgets here. Do not re-add it.
|
||||
-->
|
||||
## 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" />
|
||||
|
||||
@@ -254,13 +254,16 @@ Understanding the Superset Points of View
|
||||
|
||||
- [Superset API](/developer-docs/api)
|
||||
|
||||
<!--
|
||||
The OSS Insight "Repo Activity" widget (https://next.ossinsight.io/) was
|
||||
intentionally removed. This page is rendered on the ASF-hosted website
|
||||
(superset.apache.org), so its contents are subject to ASF's third-party
|
||||
content and CSP rules. OSS Insight has no Data Processing Agreement (DPA)
|
||||
with the ASF, so we cannot embed its images/widgets here. Do not re-add it.
|
||||
-->
|
||||
## 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" />
|
||||
|
||||
@@ -246,13 +246,16 @@ Understanding the Superset Points of View
|
||||
|
||||
- [Superset API](https://superset.apache.org/docs/rest-api)
|
||||
|
||||
<!--
|
||||
The OSS Insight "Repo Activity" widget (https://next.ossinsight.io/) was
|
||||
intentionally removed. This page is rendered on the ASF-hosted website
|
||||
(superset.apache.org), so its contents are subject to ASF's third-party
|
||||
content and CSP rules. OSS Insight has no Data Processing Agreement (DPA)
|
||||
with the ASF, so we cannot embed its images/widgets here. Do not re-add it.
|
||||
-->
|
||||
## 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" />
|
||||
|
||||
9066
docs/yarn.lock
@@ -29,7 +29,7 @@ maintainers:
|
||||
- name: craig-rueda
|
||||
email: craig@craigrueda.com
|
||||
url: https://github.com/craig-rueda
|
||||
version: 0.20.0 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
|
||||
version: 0.18.0 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
version: 16.7.27
|
||||
|
||||
@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
|
||||
|
||||
# superset
|
||||
|
||||

|
||||

|
||||
|
||||
Apache Superset is a modern, enterprise-ready business intelligence web application
|
||||
|
||||
@@ -46,21 +46,6 @@ It should be a long random bytes or str.
|
||||
|
||||
On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverrides.secrets`
|
||||
|
||||
## Upgrade Notes
|
||||
|
||||
### Kubernetes recommended labels (breaking)
|
||||
|
||||
This chart labels and selects workloads using the [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/) (`app.kubernetes.io/*`) instead of the legacy `app`/`release` labels. A Deployment's `spec.selector.matchLabels` is immutable, so `helm upgrade` against a release created before this change fails with a `field is immutable` error.
|
||||
|
||||
To upgrade an existing release, delete the affected workloads first (their selector labels changed), then upgrade so they are recreated:
|
||||
|
||||
```console
|
||||
kubectl delete deployment,statefulset -l release=<release-name> -n <namespace>
|
||||
helm upgrade <release-name> superset/superset
|
||||
```
|
||||
|
||||
Alternatively, perform a fresh install. This is a one-time migration; subsequent upgrades are unaffected.
|
||||
|
||||
## Requirements
|
||||
|
||||
| Repository | Name | Version |
|
||||
@@ -74,42 +59,10 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
|-----|------|---------|-------------|
|
||||
| affinity | object | `{}` | |
|
||||
| bootstrapScript | string | see `values.yaml` | Install additional packages and do any other bootstrap configuration in this script For production clusters it's recommended to build own image with this step done in CI |
|
||||
| cache | object | `{"asyncQueries":{"keyPrefix":"qc-","timeout":86400},"cacheDb":null,"cacheUrl":null,"celeryDb":null,"celeryUrl":null,"defaultTimeout":86400,"driver":"","enabled":true,"host":null,"keyPrefix":"superset_","password":null,"port":null,"resultsBackendKeyPrefix":"superset_results","sentinel":null,"ssl":{"ca_certs":null,"certfile":null,"enabled":false,"keyfile":null,"ssl_cert_reqs":"required"},"user":""}` | Redis cache configuration for Superset Redis is optional but recommended for caching and Celery. If redis.enabled (chart dependency) is true, defaults point to the chart's Redis instance. |
|
||||
| cache.asyncQueries | object | `{"keyPrefix":"qc-","timeout":86400}` | Async queries configuration |
|
||||
| cache.cacheDb | string | `nil` | Redis database number for cache (default: 1 when unset; legacy redis_cache_db is honored) |
|
||||
| cache.cacheUrl | string | `nil` | Full Redis cache URL (overrides host/port/user/pass if set) |
|
||||
| cache.celeryDb | string | `nil` | Redis database number for Celery (default: 0 when unset; legacy redis_celery_db is honored) |
|
||||
| cache.celeryUrl | string | `nil` | Full Redis Celery URL (overrides host/port/user/pass if set) |
|
||||
| cache.defaultTimeout | int | `86400` | Default cache timeout in seconds |
|
||||
| cache.driver | string | `""` | Custom Redis driver (e.g. TLS/managed variants); overrides the redis proto in URLs when set. Ports the legacy supersetNode.connections.redis_driver escape hatch. |
|
||||
| cache.enabled | bool | `true` | Enable Redis-based features (cache, Celery). Set to false to disable Redis usage entirely. |
|
||||
| cache.host | string | `nil` | Redis host (default: {{ .Release.Name }}-redis-headless) |
|
||||
| cache.keyPrefix | string | `"superset_"` | Cache key prefix |
|
||||
| cache.password | string | `nil` | Redis password |
|
||||
| cache.port | string | `nil` | Redis port (default: 6379 when unset; legacy supersetNode.connections.redis_port is honored) |
|
||||
| cache.resultsBackendKeyPrefix | string | `"superset_results"` | Results backend key prefix |
|
||||
| cache.sentinel | string | `nil` | Redis Sentinel configuration (optional) |
|
||||
| cache.ssl | object | `{"ca_certs":null,"certfile":null,"enabled":false,"keyfile":null,"ssl_cert_reqs":"required"}` | Redis SSL configuration |
|
||||
| cache.user | string | `""` | Redis user (optional, for Redis ACL) |
|
||||
| cluster | object | `{"databaseServiceName":null,"domain":".svc.cluster.local","redisServiceName":null,"websocketServiceName":null}` | Kubernetes cluster configuration Used for constructing service URLs between chart components |
|
||||
| cluster.databaseServiceName | string | `nil` | Database service name (default: {{ .Release.Name }}-postgresql) Override if using a different service name for the database |
|
||||
| cluster.domain | string | `".svc.cluster.local"` | Kubernetes cluster domain (default: .svc.cluster.local) Override if using a custom cluster domain |
|
||||
| cluster.redisServiceName | string | `nil` | Redis service name (default: {{ .Release.Name }}-redis-headless) Override if using a different service name for Redis |
|
||||
| cluster.websocketServiceName | string | `nil` | WebSocket service name (default: {{ .Release.Name }}-ws) Override if using a different service name for the WebSocket service |
|
||||
| config | object | `{}` | Superset configuration properties Set any configuration property from superset/config.py here See https://github.com/apache/superset/blob/master/superset/config.py for all available options |
|
||||
| configFromSecret | string | `"{{ template \"superset.fullname\" . }}-config"` | The name of the secret which we will use to generate a superset_config.py file Note: this secret must have the key superset_config.py in it and can include other files as well |
|
||||
| configMountPath | string | `"/app/pythonpath"` | |
|
||||
| configOverrides | object | `{}` | A dictionary of overrides to append at the end of superset_config.py - the name does not matter WARNING: the order is not guaranteed Files can be passed as helm --set-file configOverrides.my-override=my-file.py |
|
||||
| configOverridesFiles | object | `{}` | Same as above but the values are files |
|
||||
| database | object | `{"driver":null,"host":null,"name":null,"password":null,"port":null,"ssl":{"enabled":false,"mode":"require"},"uri":null,"user":null}` | Database connection configuration for the Superset metadata database |
|
||||
| database.driver | string | `nil` | Database driver used when uri is not set (default: postgresql+psycopg2 when unset; legacy supersetNode.connections.db_type is honored when this is unset) |
|
||||
| database.host | string | `nil` | Database host (default: {{ .Release.Name }}-postgresql) |
|
||||
| database.name | string | `nil` | Database name (default: superset, resolved via superset.db.name) |
|
||||
| database.password | string | `nil` | Database password (default: superset, resolved via superset.db.password) ⚠️ CHANGE THIS for production |
|
||||
| database.port | string | `nil` | Database port (default: 5432 when unset; legacy supersetNode.connections.db_port is honored) |
|
||||
| database.ssl | object | `{"enabled":false,"mode":"require"}` | Database SSL configuration |
|
||||
| database.uri | string | `nil` | Full database URI (overrides host/port/user/pass/name if set) Example: "postgresql+psycopg2://user:pass@host:5432/dbname" |
|
||||
| database.user | string | `nil` | Database user (default: superset, resolved via superset.db.user) |
|
||||
| envFromSecret | string | `"{{ template \"superset.fullname\" . }}-env"` | The name of the secret which we will use to populate env vars in deployed pods This can be useful for secret keys, etc. |
|
||||
| envFromSecrets | list | `[]` | This can be a list of templated strings |
|
||||
| extraConfigMountPath | string | `"/app/configs"` | |
|
||||
@@ -121,9 +74,7 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| extraSecrets | object | `{}` | Extra files to be mounted as Secrets on the path specified in `configMountPath` |
|
||||
| extraVolumeMounts | list | `[]` | |
|
||||
| extraVolumes | list | `[]` | |
|
||||
| featureFlags | object | `{}` | Feature flags configuration See https://github.com/apache/superset/blob/master/RESOURCES/FEATURE_FLAGS.md |
|
||||
| fullnameOverride | string | `nil` | Provide a name to override the full names of resources |
|
||||
| globalPodAnnotations | object | `{}` | Global pod annotations to be added to all pods Use this to set annotations that apply to all Superset components Component-specific podAnnotations will be merged with these global annotations |
|
||||
| hostAliases | list | `[]` | Custom hostAliases for all superset pods # https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/ |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | |
|
||||
| image.repository | string | `"apachesuperset.docker.scarf.sh/apache/superset"` | |
|
||||
@@ -150,7 +101,7 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| init.enabled | bool | `true` | |
|
||||
| init.extraContainers | list | `[]` | Launch additional containers into init job pod |
|
||||
| init.initContainers | list | a container waiting for postgres | List of initContainers |
|
||||
| init.initscript | string | unused; kept for backwards-compatibility only | DEPRECATED: this field is no longer used by the chart. The init script is rendered entirely from the internal `superset.initScript` template (which runs `superset db upgrade`, `superset init`, admin creation, and examples). Any customization placed here is silently ignored. See UPGRADING.md. |
|
||||
| init.initscript | string | a script to create admin user and initialize roles | A Superset init script |
|
||||
| init.jobAnnotations."helm.sh/hook" | string | `"post-install,post-upgrade"` | |
|
||||
| init.jobAnnotations."helm.sh/hook-delete-policy" | string | `"before-hook-creation"` | |
|
||||
| init.loadExamples | bool | `false` | |
|
||||
@@ -177,7 +128,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| service.type | string | `"ClusterIP"` | |
|
||||
| serviceAccount.annotations | object | `{}` | |
|
||||
| serviceAccount.create | bool | `false` | Create custom service account for Superset. If create: true and serviceAccountName is not provided, `superset.fullname` will be used. |
|
||||
| serviceAccount.name | string | `""` | Service account name to use (if not specified, defaults to release name + chart name) |
|
||||
| serviceAccountName | string | `nil` | Specify service account name to be used |
|
||||
| supersetCeleryBeat.affinity | object | `{}` | Affinity to be added to supersetCeleryBeat deployment |
|
||||
| supersetCeleryBeat.command | list | a `celery beat` command | Command |
|
||||
@@ -249,7 +199,20 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| supersetNode.autoscaling.minReplicas | int | `1` | |
|
||||
| supersetNode.autoscaling.targetCPUUtilizationPercentage | int | `80` | |
|
||||
| supersetNode.command | list | See `values.yaml` | Startup command |
|
||||
| supersetNode.connections | object | `{}` | |
|
||||
| supersetNode.connections.db_host | string | `"{{ .Release.Name }}-postgresql"` | |
|
||||
| supersetNode.connections.db_name | string | `"superset"` | |
|
||||
| supersetNode.connections.db_pass | string | `"superset"` | |
|
||||
| supersetNode.connections.db_port | string | `"5432"` | |
|
||||
| supersetNode.connections.db_type | string | `"postgresql"` | Database type for Superset metadata (Supported types: "postgresql", "mysql") |
|
||||
| supersetNode.connections.db_user | string | `"superset"` | |
|
||||
| supersetNode.connections.redis_cache_db | string | `"1"` | |
|
||||
| supersetNode.connections.redis_celery_db | string | `"0"` | |
|
||||
| supersetNode.connections.redis_driver | string | `""` | |
|
||||
| supersetNode.connections.redis_host | string | `"{{ .Release.Name }}-redis-headless"` | Change in case of bringing your own redis and then also set redis.enabled:false |
|
||||
| supersetNode.connections.redis_port | string | `"6379"` | |
|
||||
| supersetNode.connections.redis_ssl.enabled | bool | `false` | |
|
||||
| supersetNode.connections.redis_ssl.ssl_cert_reqs | string | `"CERT_NONE"` | |
|
||||
| supersetNode.connections.redis_user | string | `""` | |
|
||||
| supersetNode.containerSecurityContext | object | `{}` | |
|
||||
| supersetNode.deploymentAdditionalPodSpec | object | `{}` | Custom pod spec to be added to supersetNode deployment |
|
||||
| supersetNode.deploymentAnnotations | object | `{}` | Annotations to be added to supersetNode deployment |
|
||||
@@ -356,11 +319,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| supersetWorker.deploymentLabels | object | `{}` | Labels to be added to supersetWorker deployment |
|
||||
| supersetWorker.extraContainers | list | `[]` | Launch additional containers into supersetWorker pod |
|
||||
| supersetWorker.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
|
||||
| supersetWorker.healthCheck | object | `{"enabled":false,"livenessFile":"/tmp/celery_worker_alive","livenessHeartbeatInterval":10,"readinessFile":"/tmp/celery_worker_ready"}` | Celery worker file-based health check (worker writes readiness/liveness files via signals; point supersetWorker.readinessProbe/livenessProbe at these files to use them) |
|
||||
| supersetWorker.healthCheck.enabled | bool | `false` | Enable the file-based Celery worker health check |
|
||||
| supersetWorker.healthCheck.livenessFile | string | `"/tmp/celery_worker_alive"` | Liveness file (touched periodically by a heartbeat thread) |
|
||||
| supersetWorker.healthCheck.livenessHeartbeatInterval | int | `10` | Seconds between liveness heartbeats |
|
||||
| supersetWorker.healthCheck.readinessFile | string | `"/tmp/celery_worker_ready"` | Readiness file (created when the worker is ready, removed on shutdown) |
|
||||
| supersetWorker.initContainers | list | a container waiting for postgres and redis | Init container |
|
||||
| supersetWorker.lifecycle | object | `{}` | Container lifecycle hooks for the worker pod |
|
||||
| supersetWorker.livenessProbe.exec.command | list | a `celery inspect ping` command | Liveness probe command |
|
||||
|
||||
@@ -45,21 +45,6 @@ It should be a long random bytes or str.
|
||||
|
||||
On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverrides.secrets`
|
||||
|
||||
## Upgrade Notes
|
||||
|
||||
### Kubernetes recommended labels (breaking)
|
||||
|
||||
This chart labels and selects workloads using the [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/) (`app.kubernetes.io/*`) instead of the legacy `app`/`release` labels. A Deployment's `spec.selector.matchLabels` is immutable, so `helm upgrade` against a release created before this change fails with a `field is immutable` error.
|
||||
|
||||
To upgrade an existing release, delete the affected workloads first (their selector labels changed), then upgrade so they are recreated:
|
||||
|
||||
```console
|
||||
kubectl delete deployment,statefulset -l release=<release-name> -n <namespace>
|
||||
helm upgrade <release-name> superset/superset
|
||||
```
|
||||
|
||||
Alternatively, perform a fresh install. This is a one-time migration; subsequent upgrades are unaffected.
|
||||
|
||||
{{ template "chart.requirementsSection" . }}
|
||||
|
||||
{{ template "chart.valuesSection" . }}
|
||||
|
||||
@@ -1,161 +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.
|
||||
-->
|
||||
|
||||
# Upgrading the Superset Helm Chart
|
||||
|
||||
## Upgrading to chart 0.20.0
|
||||
|
||||
Chart 0.20.0 introduces a structured connection schema. The old keys listed below are **DEPRECATED** — they still work (auto-mapped to the new keys at render time) and a deprecation warning is printed in `helm install`/`helm upgrade` NOTES, but they will be removed in a future release. Migrate as soon as possible.
|
||||
|
||||
### 1. Connection schema: `supersetNode.connections.*` → `database.*` / `cache.*`
|
||||
|
||||
**Before (deprecated — still honored):**
|
||||
|
||||
```yaml
|
||||
supersetNode:
|
||||
connections:
|
||||
db_host: "pg-host"
|
||||
db_port: "5432"
|
||||
db_user: "superset"
|
||||
db_pass: "superset"
|
||||
db_name: "superset"
|
||||
redis_host: "redis-host"
|
||||
redis_port: "6379"
|
||||
redis_cache_db: "1"
|
||||
redis_celery_db: "0"
|
||||
redis_driver: "rediss"
|
||||
```
|
||||
|
||||
**After (new structured keys — recommended):**
|
||||
|
||||
```yaml
|
||||
database:
|
||||
host: "pg-host"
|
||||
port: 5432
|
||||
user: "superset"
|
||||
password: "superset"
|
||||
name: "superset"
|
||||
|
||||
cache:
|
||||
host: "redis-host"
|
||||
port: 6379
|
||||
cacheDb: 1
|
||||
celeryDb: 0
|
||||
driver: "rediss" # optional: custom Redis driver / TLS variant
|
||||
```
|
||||
|
||||
Key-by-key mapping summary:
|
||||
|
||||
| Old key | New key |
|
||||
|---|---|
|
||||
| `supersetNode.connections.db_host` | `database.host` |
|
||||
| `supersetNode.connections.db_port` | `database.port` |
|
||||
| `supersetNode.connections.db_user` | `database.user` |
|
||||
| `supersetNode.connections.db_pass` | `database.password` |
|
||||
| `supersetNode.connections.db_name` | `database.name` |
|
||||
| `supersetNode.connections.redis_host` | `cache.host` |
|
||||
| `supersetNode.connections.redis_port` | `cache.port` |
|
||||
| `supersetNode.connections.redis_cache_db` | `cache.cacheDb` |
|
||||
| `supersetNode.connections.redis_celery_db` | `cache.celeryDb` |
|
||||
| `supersetNode.connections.redis_driver` | `cache.driver` |
|
||||
|
||||
### 2. Service account: root `serviceAccountName` → `serviceAccount.name`
|
||||
|
||||
**Before (deprecated — still honored):**
|
||||
|
||||
```yaml
|
||||
serviceAccountName: my-sa
|
||||
```
|
||||
|
||||
**After (new key — recommended):**
|
||||
|
||||
```yaml
|
||||
serviceAccount:
|
||||
name: my-sa
|
||||
```
|
||||
|
||||
### 3. Init script: `init.initscript` is deprecated and replaced by the built-in template
|
||||
|
||||
> **This is a behavior change.** The chart no longer uses `init.initscript`. The init script is rendered
|
||||
> entirely from an internal chart template (`superset.initScript`), which runs the full initialization
|
||||
> sequence:
|
||||
>
|
||||
> 1. `superset db upgrade` — applies all pending database schema migrations
|
||||
> 2. `superset init` — initializes roles and permissions
|
||||
> 3. Admin user creation (when `init.createAdmin: true`)
|
||||
> 4. Example data loading (when `init.loadExamples: true`)
|
||||
> 5. Datasource import (when `import_datasources.yaml` is present)
|
||||
>
|
||||
> A future PR will optionally split the database migration step into a dedicated upgrade Job for
|
||||
> zero-downtime deployments. Until that PR lands, migrations run as part of the init Job above.
|
||||
|
||||
If you customized `init.initscript` in your `values.yaml`, that customization is silently ignored.
|
||||
Move any customizations to `config` or `configOverrides`:
|
||||
|
||||
```yaml
|
||||
# Move custom Python config here:
|
||||
config:
|
||||
MY_SETTING: "value"
|
||||
|
||||
configOverrides:
|
||||
my_custom_override: |
|
||||
# Python snippet appended to superset_config.py
|
||||
MY_SETTING = "value"
|
||||
```
|
||||
|
||||
If your use case cannot be covered by `config` or `configOverrides`, please open an issue so the maintainers
|
||||
can evaluate extending the template.
|
||||
|
||||
### 4. New top-level sections: `config.*` and `featureFlags.*`
|
||||
|
||||
Two new sections provide direct Superset configuration passthrough without needing raw `configOverrides`.
|
||||
|
||||
**`config.*` — direct Superset config properties:**
|
||||
|
||||
```yaml
|
||||
config:
|
||||
SECRET_KEY: "$(SUPERSET_SECRET_KEY)"
|
||||
ROW_LIMIT: 50000
|
||||
WTF_CSRF_ENABLED: true
|
||||
SQLALCHEMY_POOL_SIZE: 10
|
||||
```
|
||||
|
||||
Each key is injected verbatim into `superset_config.py`. String values are quoted; non-string values
|
||||
(integers, booleans) are rendered as-is.
|
||||
|
||||
**`featureFlags.*` — feature flag overrides:**
|
||||
|
||||
```yaml
|
||||
featureFlags:
|
||||
ALERT_REPORTS: true
|
||||
DASHBOARD_RBAC: true
|
||||
ENABLE_TEMPLATE_PROCESSING: false
|
||||
```
|
||||
|
||||
This is equivalent to setting `FEATURE_FLAGS = {...}` in `superset_config.py`, but is more readable and
|
||||
schema-validated.
|
||||
|
||||
### 5. `values.schema.json` — early validation
|
||||
|
||||
The chart now ships a `values.schema.json` that validates the values you provide. Wrong types (e.g., a string
|
||||
where an integer is expected) or unknown keys in structured sections will cause `helm install`/`helm upgrade`
|
||||
to fail immediately with a descriptive error instead of producing a broken deployment.
|
||||
|
||||
If you get a validation error after upgrading, check that your overridden values match the types documented in
|
||||
`values.yaml` and the schema.
|
||||
@@ -35,9 +35,3 @@
|
||||
echo "Visit http://127.0.0.1:8088 to use your application"
|
||||
kubectl port-forward service/superset 8088:8088 --namespace {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
{{- $warnings := include "superset.deprecationWarnings" . }}
|
||||
{{- if trim $warnings }}
|
||||
|
||||
⚠️ DEPRECATION WARNINGS
|
||||
{{ $warnings }}
|
||||
{{- end }}
|
||||
|
||||
@@ -47,12 +47,11 @@ If release name contains chart name it will be used as a full name.
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "superset.serviceAccountName" -}}
|
||||
{{- $name := coalesce .Values.serviceAccount.name .Values.serviceAccountName -}}
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
{{- default (include "superset.fullname" .) $name -}}
|
||||
{{- else -}}
|
||||
{{- default "default" $name -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
{{- default (include "superset.fullname" .) .Values.serviceAccountName -}}
|
||||
{{- else -}}
|
||||
{{- default "default" .Values.serviceAccountName -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
@@ -62,616 +61,81 @@ Create chart name and version as used by the chart label.
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Common labels for all resources - follows Kubernetes recommended labels
|
||||
https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
|
||||
*/}}
|
||||
{{- define "superset.labels" -}}
|
||||
helm.sh/chart: {{ include "superset.chart" . }}
|
||||
{{ include "superset.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/part-of: superset
|
||||
{{- if .Values.extraLabels }}
|
||||
{{ toYaml .Values.extraLabels }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Selector labels - used by selectors and matchLabels
|
||||
*/}}
|
||||
{{- define "superset.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Component labels - extends superset.labels with component-specific labels
|
||||
Usage: {{ include "superset.componentLabels" (dict "component" "web" "root" .) }}
|
||||
*/}}
|
||||
{{- define "superset.componentLabels" -}}
|
||||
{{ include "superset.labels" .root }}
|
||||
app.kubernetes.io/component: {{ .component }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Component selector labels - for matchLabels with component
|
||||
Usage: {{ include "superset.componentSelectorLabels" (dict "component" "web" "root" .) }}
|
||||
*/}}
|
||||
{{- define "superset.componentSelectorLabels" -}}
|
||||
{{ include "superset.selectorLabels" .root }}
|
||||
app.kubernetes.io/component: {{ .component }}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{/*
|
||||
Coalescing resolvers for DB and Redis connection parameters.
|
||||
Each resolver checks (in order):
|
||||
1. New top-level database.* / cache.* values
|
||||
2. Legacy supersetNode.connections.* keys (deprecation path, using safe index to avoid errors on absent maps)
|
||||
3. cluster.* service name overrides
|
||||
4. Hard-coded defaults derived from the release name
|
||||
Call with root context: {{ include "superset.db.host" . }}
|
||||
*/}}
|
||||
|
||||
{{/*
|
||||
Helper to safely read .Values.supersetNode.connections.<key> without erroring when maps are absent.
|
||||
*/}}
|
||||
{{- define "_superset.legacyConn" -}}
|
||||
{{- $sn := index .Values "supersetNode" | default dict -}}
|
||||
{{- $conn := index $sn "connections" | default dict -}}
|
||||
{{- $conn | toJson -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.db.host" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- tpl (coalesce .Values.database.host (index $conn "db_host") .Values.cluster.databaseServiceName (printf "%s-postgresql" .Release.Name)) $ -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.db.port" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- if .Values.database.port -}}
|
||||
{{- .Values.database.port | toString -}}
|
||||
{{- else -}}
|
||||
{{- coalesce (index $conn "db_port") "5432" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.db.user" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- coalesce .Values.database.user (index $conn "db_user") "superset" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.db.password" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- coalesce .Values.database.password (index $conn "db_pass") "superset" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.db.name" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- coalesce .Values.database.name (index $conn "db_name") "superset" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.db.driver" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- coalesce .Values.database.driver (index $conn "db_type") "postgresql+psycopg2" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.redis.host" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- tpl (coalesce .Values.cache.host (index $conn "redis_host") .Values.cluster.redisServiceName (printf "%s-redis-headless" .Release.Name)) $ -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.redis.port" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- if .Values.cache.port -}}
|
||||
{{- .Values.cache.port | toString -}}
|
||||
{{- else -}}
|
||||
{{- coalesce (index $conn "redis_port") "6379" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.redis.user" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- coalesce .Values.cache.user (index $conn "redis_user") "" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.redis.password" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- coalesce .Values.cache.password (index $conn "redis_password") "" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.redis.cacheDb" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- if not (kindIs "invalid" .Values.cache.cacheDb) -}}
|
||||
{{- .Values.cache.cacheDb | toString -}}
|
||||
{{- else -}}
|
||||
{{- coalesce (index $conn "redis_cache_db") "1" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.redis.celeryDb" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- if not (kindIs "invalid" .Values.cache.celeryDb) -}}
|
||||
{{- .Values.cache.celeryDb | toString -}}
|
||||
{{- else -}}
|
||||
{{- coalesce (index $conn "redis_celery_db") "0" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.redis.proto" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- if .Values.cache.driver }}{{ .Values.cache.driver }}{{- else if index $conn "redis_driver" }}{{ index $conn "redis_driver" }}{{- else if .Values.cache.ssl.enabled }}rediss{{- else }}redis{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.config" }}
|
||||
{{- /* SECURITY: Validate admin password is set if admin creation is enabled */}}
|
||||
{{- if and .Values.init.createAdmin (or (not .Values.init.adminUser.password) (eq .Values.init.adminUser.password "")) }}
|
||||
{{- fail "SECURITY ERROR: init.createAdmin is true but init.adminUser.password is empty. You must set a secure password using --set init.adminUser.password='your-password' or via external secret." }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "superset-config" }}
|
||||
import os
|
||||
import json
|
||||
from urllib.parse import quote
|
||||
{{- if or .Values.config.cacheConfig .Values.config.dataCacheConfig .Values.config.resultsBackend .Values.config.celeryConfig .Values.cache.enabled }}
|
||||
from flask_caching.backends.rediscache import RedisCache
|
||||
{{- end }}
|
||||
|
||||
def env(key, default=None):
|
||||
return os.getenv(key, default)
|
||||
|
||||
{{- /* Database Configuration - Superset always requires a database */}}
|
||||
{{- if .Values.database.uri }}
|
||||
SQLALCHEMY_DATABASE_URI = {{ .Values.database.uri | quote }}
|
||||
# Redis Base URL
|
||||
{{- if .Values.supersetNode.connections.redis_password }}
|
||||
REDIS_BASE_URL=f"{env('REDIS_DRIVER') or env('REDIS_PROTO')}://{env('REDIS_USER', '')}:{env('REDIS_PASSWORD')}@{env('REDIS_HOST')}:{env('REDIS_PORT')}"
|
||||
{{- else }}
|
||||
{{- $driver := include "superset.db.driver" . }}
|
||||
{{- $sslParams := "" }}
|
||||
{{- if and (hasKey .Values.database "ssl") .Values.database.ssl.enabled }}
|
||||
{{- $sslMode := .Values.database.ssl.mode | default "require" }}
|
||||
{{- $sslParams = printf "?sslmode=%s" $sslMode }}
|
||||
{{- end }}
|
||||
SQLALCHEMY_DATABASE_URI = f"{{ $driver }}://{quote(env('DB_USER', ''), safe='')}:{quote(env('DB_PASS', ''), safe='')}@{env('DB_HOST')}:{env('DB_PORT')}/{env('DB_NAME')}{{ $sslParams }}"
|
||||
{{- end }}
|
||||
{{- if hasKey .Values.config "SQLALCHEMY_TRACK_MODIFICATIONS" }}
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = {{ .Values.config.SQLALCHEMY_TRACK_MODIFICATIONS | toString | title }}
|
||||
{{- else }}
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
REDIS_BASE_URL=f"{env('REDIS_DRIVER') or env('REDIS_PROTO')}://{env('REDIS_HOST')}:{env('REDIS_PORT')}"
|
||||
{{- end }}
|
||||
|
||||
{{- /* Redis Configuration - only if Redis cache is configured */}}
|
||||
{{- if .Values.cache.enabled }}
|
||||
{{- if .Values.cache.cacheUrl }}
|
||||
CACHE_REDIS_URL = {{ .Values.cache.cacheUrl | quote }}
|
||||
{{- else }}
|
||||
{{- $useSSL := and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
|
||||
_redis_user = quote(env('REDIS_USER', ''), safe='')
|
||||
_redis_password = quote(env('REDIS_PASSWORD', ''), safe='')
|
||||
_redis_auth = f"{_redis_user}:{_redis_password}@" if (_redis_user or _redis_password) else ""
|
||||
REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{_redis_auth}{env('REDIS_HOST')}:{env('REDIS_PORT')}"
|
||||
{{- if $useSSL }}
|
||||
{{- $sslCertReqs := .Values.cache.ssl.ssl_cert_reqs | default "required" }}
|
||||
REDIS_URL_PARAMS = f"?ssl_cert_reqs={{ $sslCertReqs }}"
|
||||
# Redis URL Params
|
||||
{{- if .Values.supersetNode.connections.redis_ssl.enabled }}
|
||||
REDIS_URL_PARAMS = f"?ssl_cert_reqs={env('REDIS_SSL_CERT_REQS')}"
|
||||
{{- else }}
|
||||
REDIS_URL_PARAMS = ""
|
||||
{{- end }}
|
||||
{{- $cacheDb := include "superset.redis.cacheDb" . }}
|
||||
CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{{ $cacheDb }}{REDIS_URL_PARAMS}"
|
||||
{{- end }}
|
||||
{{- if .Values.cache.celeryUrl }}
|
||||
CELERY_REDIS_URL = {{ .Values.cache.celeryUrl | quote }}
|
||||
{{- else if not .Values.cache.cacheUrl }}
|
||||
{{- $celeryDb := include "superset.redis.celeryDb" . }}
|
||||
CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{{ $celeryDb }}{REDIS_URL_PARAMS}"
|
||||
{{- else }}
|
||||
{{- if or .Values.config.celeryConfig (not .Values.cache.enabled) }}
|
||||
{{- /* Custom celeryConfig provided or cache disabled - OK */}}
|
||||
{{- else }}
|
||||
{{- fail "CONFIGURATION ERROR: cache.cacheUrl is set but cache.celeryUrl is not set. When using cacheUrl, you must also set celeryUrl for Celery to work. Alternatively, set config.celeryConfig to provide a custom Celery configuration." }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end}}
|
||||
|
||||
{{- /* Cache Configuration */}}
|
||||
{{- if .Values.config.cacheConfig }}
|
||||
CACHE_CONFIG = json.loads({{ .Values.config.cacheConfig | toJson | quote }})
|
||||
{{- else if .Values.cache.enabled }}
|
||||
# Build Redis URLs
|
||||
CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_DB', 1)}{REDIS_URL_PARAMS}"
|
||||
CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_CELERY_DB', 0)}{REDIS_URL_PARAMS}"
|
||||
|
||||
MAPBOX_API_KEY = env('MAPBOX_API_KEY', '')
|
||||
CACHE_CONFIG = {
|
||||
'CACHE_TYPE': 'RedisCache',
|
||||
'CACHE_DEFAULT_TIMEOUT': {{ .Values.cache.defaultTimeout | default (.Values.config.cacheDefaultTimeout | default 86400) | int }},
|
||||
'CACHE_KEY_PREFIX': {{ .Values.cache.keyPrefix | default "superset_" | quote }},
|
||||
'CACHE_REDIS_URL': CACHE_REDIS_URL,
|
||||
'CACHE_TYPE': 'RedisCache',
|
||||
'CACHE_DEFAULT_TIMEOUT': 300,
|
||||
'CACHE_KEY_PREFIX': 'superset_',
|
||||
'CACHE_REDIS_URL': CACHE_REDIS_URL,
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.config.dataCacheConfig }}
|
||||
DATA_CACHE_CONFIG = json.loads({{ .Values.config.dataCacheConfig | toJson | quote }})
|
||||
{{- else if .Values.config.cacheConfig }}
|
||||
DATA_CACHE_CONFIG = CACHE_CONFIG
|
||||
{{- else if .Values.cache.enabled }}
|
||||
DATA_CACHE_CONFIG = CACHE_CONFIG
|
||||
{{- end }}
|
||||
|
||||
{{- /* SQLLAB_ASYNC_TIME_LIMIT_SEC - Required for async_queries module import (default: 6 hours) */}}
|
||||
{{- if .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC }}
|
||||
SQLLAB_ASYNC_TIME_LIMIT_SEC = {{ .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC | int }}
|
||||
{{- else }}
|
||||
from datetime import timedelta
|
||||
SQLLAB_ASYNC_TIME_LIMIT_SEC = int(timedelta(hours=6).total_seconds())
|
||||
{{- end }}
|
||||
|
||||
{{- /* Celery Configuration */}}
|
||||
{{- if .Values.config.celeryConfig }}
|
||||
{{- if kindIs "string" .Values.config.celeryConfig }}
|
||||
{{ .Values.config.celeryConfig }}
|
||||
{{- else }}
|
||||
class CeleryConfig:
|
||||
{{- range $key, $value := .Values.config.celeryConfig }}
|
||||
{{ $key }} = json.loads({{ $value | toJson | quote }})
|
||||
{{- end }}
|
||||
|
||||
{{- if hasKey .Values.config.celeryConfig "imports" }}
|
||||
CELERY_IMPORTS = CeleryConfig.imports
|
||||
{{- else }}
|
||||
CELERY_IMPORTS = ()
|
||||
{{- end }}
|
||||
CELERY_CONFIG = CeleryConfig
|
||||
{{- end }}
|
||||
{{- else if .Values.cache.enabled }}
|
||||
from celery.schedules import crontab
|
||||
from datetime import timedelta
|
||||
if os.getenv("SQLALCHEMY_DATABASE_URI"):
|
||||
SQLALCHEMY_DATABASE_URI = os.getenv("SQLALCHEMY_DATABASE_URI")
|
||||
else:
|
||||
{{- if eq .Values.supersetNode.connections.db_type "postgresql" }}
|
||||
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
|
||||
{{- else if eq .Values.supersetNode.connections.db_type "mysql" }}
|
||||
SQLALCHEMY_DATABASE_URI = f"mysql+mysqldb://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
|
||||
{{- else }}
|
||||
{{ fail (printf "Unsupported database type: %s. Please use 'postgresql' or 'mysql'." .Values.supersetNode.connections.db_type) }}
|
||||
{{- end }}
|
||||
|
||||
class CeleryConfig:
|
||||
imports = (
|
||||
"superset.sql_lab",
|
||||
"superset.tasks.scheduler",
|
||||
"superset.tasks.thumbnails",
|
||||
"superset.tasks.cache",
|
||||
)
|
||||
broker_connection_retry_on_startup = True
|
||||
worker_prefetch_multiplier = 10
|
||||
task_acks_late = True
|
||||
broker_url = CELERY_REDIS_URL
|
||||
result_backend = CELERY_REDIS_URL
|
||||
task_annotations = {
|
||||
"sql_lab.get_sql_results": {
|
||||
"rate_limit": "100/s",
|
||||
},
|
||||
}
|
||||
beat_schedule = {
|
||||
"reports.scheduler": {
|
||||
"task": "reports.scheduler",
|
||||
"schedule": crontab(minute="*", hour="*"),
|
||||
"options": {"expires": int(timedelta(weeks=1).total_seconds())},
|
||||
},
|
||||
"reports.prune_log": {
|
||||
"task": "reports.prune_log",
|
||||
"schedule": crontab(minute=0, hour=0),
|
||||
},
|
||||
}
|
||||
imports = ("superset.sql_lab", )
|
||||
broker_url = CELERY_REDIS_URL
|
||||
result_backend = CELERY_REDIS_URL
|
||||
|
||||
CELERY_IMPORTS = CeleryConfig.imports
|
||||
CELERY_CONFIG = CeleryConfig
|
||||
{{- end }}
|
||||
|
||||
{{- /* Celery Worker Health Check - File-based health probes for Kubernetes */}}
|
||||
{{- if and .Values.supersetWorker.healthCheck .Values.supersetWorker.healthCheck.enabled }}
|
||||
# Celery Worker Health Check Configuration
|
||||
import threading
|
||||
from celery import bootsteps
|
||||
from celery.signals import worker_ready, worker_shutdown, worker_init
|
||||
|
||||
_readiness_file = {{ .Values.supersetWorker.healthCheck.readinessFile | default "/tmp/celery_worker_ready" | quote }}
|
||||
_liveness_file = {{ .Values.supersetWorker.healthCheck.livenessFile | default "/tmp/celery_worker_alive" | quote }}
|
||||
_heartbeat_interval = {{ .Values.supersetWorker.healthCheck.livenessHeartbeatInterval | default 10 | int }}
|
||||
_liveness_thread = None
|
||||
_liveness_stop_event = None
|
||||
|
||||
@worker_ready.connect
|
||||
def create_ready_file(sender, **kwargs):
|
||||
try:
|
||||
open(_readiness_file, 'w').close()
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not create readiness file: {e}")
|
||||
|
||||
@worker_shutdown.connect
|
||||
def remove_ready_file(sender, **kwargs):
|
||||
global _liveness_thread, _liveness_stop_event
|
||||
if _liveness_stop_event:
|
||||
_liveness_stop_event.set()
|
||||
if _liveness_thread:
|
||||
_liveness_thread.join(timeout=5)
|
||||
try:
|
||||
if os.path.exists(_readiness_file):
|
||||
os.remove(_readiness_file)
|
||||
if os.path.exists(_liveness_file):
|
||||
os.remove(_liveness_file)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not remove health check files: {e}")
|
||||
|
||||
@worker_init.connect
|
||||
def start_liveness_heartbeat(sender, **kwargs):
|
||||
global _liveness_thread, _liveness_stop_event
|
||||
_liveness_stop_event = threading.Event()
|
||||
|
||||
def update_liveness():
|
||||
while not _liveness_stop_event.is_set():
|
||||
try:
|
||||
with open(_liveness_file, 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not update liveness file: {e}")
|
||||
_liveness_stop_event.wait(_heartbeat_interval)
|
||||
|
||||
_liveness_thread = threading.Thread(target=update_liveness, daemon=True)
|
||||
_liveness_thread.start()
|
||||
{{- else }}
|
||||
CELERY_WORKER_HEALTH_CHECK_ENABLED = False
|
||||
{{- end }}
|
||||
|
||||
{{- /* Results Backend */}}
|
||||
{{- $redisHostForBackend := include "superset.redis.host" . }}
|
||||
{{- $redisPortForBackend := include "superset.redis.port" . }}
|
||||
{{- $redisPasswordForBackend := include "superset.redis.password" . }}
|
||||
{{- if .Values.config.resultsBackend }}
|
||||
{{- if kindIs "string" .Values.config.resultsBackend }}
|
||||
RESULTS_BACKEND = {{ .Values.config.resultsBackend }}
|
||||
{{- else }}
|
||||
RESULTS_BACKEND = RedisCache(
|
||||
host={{ $redisHostForBackend | quote }},
|
||||
{{- if $redisPasswordForBackend }}
|
||||
password={{ $redisPasswordForBackend | quote }},
|
||||
{{- end }}
|
||||
port={{ $redisPortForBackend | int }},
|
||||
key_prefix={{ .Values.cache.resultsBackendKeyPrefix | default "superset_results" | quote }},
|
||||
{{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
|
||||
ssl=True,
|
||||
ssl_cert_reqs={{ .Values.cache.ssl.ssl_cert_reqs | default "required" | quote }},
|
||||
{{- end }}
|
||||
host=env('REDIS_HOST'),
|
||||
{{- if .Values.supersetNode.connections.redis_password }}
|
||||
password=env('REDIS_PASSWORD'),
|
||||
{{- end }}
|
||||
port=env('REDIS_PORT'),
|
||||
key_prefix='superset_results',
|
||||
{{- if .Values.supersetNode.connections.redis_ssl.enabled }}
|
||||
ssl=True,
|
||||
ssl_cert_reqs=env('REDIS_SSL_CERT_REQS'),
|
||||
{{- end }}
|
||||
)
|
||||
{{- end }}
|
||||
{{- else if .Values.cache.enabled }}
|
||||
RESULTS_BACKEND = RedisCache(
|
||||
host={{ $redisHostForBackend | quote }},
|
||||
{{- if $redisPasswordForBackend }}
|
||||
password={{ $redisPasswordForBackend | quote }},
|
||||
{{- end }}
|
||||
port={{ $redisPortForBackend | int }},
|
||||
key_prefix={{ .Values.cache.resultsBackendKeyPrefix | default "superset_results" | quote }},
|
||||
{{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
|
||||
ssl=True,
|
||||
ssl_cert_reqs={{ .Values.cache.ssl.ssl_cert_reqs | default "required" | quote }},
|
||||
{{- end }}
|
||||
)
|
||||
{{- end }}
|
||||
|
||||
{{- /* Global Async Queries Cache Backend */}}
|
||||
{{- $redisUserForGaq := include "superset.redis.user" . }}
|
||||
{{- if .Values.config.GLOBAL_ASYNC_QUERIES_CACHE_BACKEND }}
|
||||
GLOBAL_ASYNC_QUERIES_CACHE_BACKEND = json.loads({{ .Values.config.GLOBAL_ASYNC_QUERIES_CACHE_BACKEND | toJson | quote }})
|
||||
{{- else if .Values.cache.enabled }}
|
||||
GLOBAL_ASYNC_QUERIES_CACHE_BACKEND = {
|
||||
"CACHE_TYPE": "RedisCache",
|
||||
"CACHE_REDIS_HOST": {{ $redisHostForBackend | quote }},
|
||||
"CACHE_REDIS_PORT": {{ $redisPortForBackend | int }},
|
||||
{{- if $redisUserForGaq }}
|
||||
"CACHE_REDIS_USER": {{ $redisUserForGaq | quote }},
|
||||
{{- end }}
|
||||
{{- if $redisPasswordForBackend }}
|
||||
"CACHE_REDIS_PASSWORD": {{ $redisPasswordForBackend | quote }},
|
||||
{{- else }}
|
||||
"CACHE_REDIS_PASSWORD": "",
|
||||
{{- end }}
|
||||
"CACHE_REDIS_DB": {{ .Values.cache.asyncQueries.db | default .Values.cache.cacheDb | default 0 | int }},
|
||||
"CACHE_KEY_PREFIX": {{ .Values.cache.asyncQueries.keyPrefix | default "qc-" | quote }},
|
||||
"CACHE_DEFAULT_TIMEOUT": {{ .Values.cache.asyncQueries.timeout | default 86400 | int }},
|
||||
{{- if and .Values.cache.sentinel .Values.cache.sentinel.enabled }}
|
||||
{{- if .Values.cache.sentinel.sentinels }}
|
||||
"CACHE_REDIS_SENTINELS": {{ .Values.cache.sentinel.sentinels | toJson }},
|
||||
{{- else }}
|
||||
{{- fail "CONFIGURATION ERROR: cache.sentinel.enabled is true but cache.sentinel.sentinels is not set. You must provide Sentinel host(s) in cache.sentinel.sentinels (e.g., [['sentinel-host', 26379]])." }}
|
||||
{{- end }}
|
||||
"CACHE_REDIS_SENTINEL_MASTER": {{ .Values.cache.sentinel.master | default "mymaster" | quote }},
|
||||
{{- if .Values.cache.sentinel.password }}
|
||||
"CACHE_REDIS_SENTINEL_PASSWORD": {{ .Values.cache.sentinel.password | quote }},
|
||||
{{- else }}
|
||||
"CACHE_REDIS_SENTINEL_PASSWORD": None,
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
|
||||
"CACHE_REDIS_SSL": True,
|
||||
"CACHE_REDIS_SSL_CERTFILE": {{ if .Values.cache.ssl.certfile }}{{ .Values.cache.ssl.certfile | quote }}{{ else }}None{{ end }},
|
||||
"CACHE_REDIS_SSL_KEYFILE": {{ if .Values.cache.ssl.keyfile }}{{ .Values.cache.ssl.keyfile | quote }}{{ else }}None{{ end }},
|
||||
"CACHE_REDIS_SSL_CERT_REQS": {{ .Values.cache.ssl.ssl_cert_reqs | default "required" | quote }},
|
||||
"CACHE_REDIS_SSL_CA_CERTS": {{ if .Values.cache.ssl.ca_certs }}{{ .Values.cache.ssl.ca_certs | quote }}{{ else }}None{{ end }},
|
||||
{{- else }}
|
||||
"CACHE_REDIS_SSL": False,
|
||||
"CACHE_REDIS_SSL_CERTFILE": None,
|
||||
"CACHE_REDIS_SSL_KEYFILE": None,
|
||||
"CACHE_REDIS_SSL_CERT_REQS": {{ .Values.cache.ssl.ssl_cert_reqs | default "required" | quote }},
|
||||
"CACHE_REDIS_SSL_CA_CERTS": None,
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Global Async Queries Results Backend */}}
|
||||
{{- if .Values.config.GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND }}
|
||||
GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND = json.loads({{ .Values.config.GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND | toJson | quote }})
|
||||
{{- else if .Values.cache.enabled }}
|
||||
GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND = {
|
||||
"backend": "redis",
|
||||
"host": {{ $redisHostForBackend | quote }},
|
||||
"port": {{ $redisPortForBackend | int }},
|
||||
"prefix": {{ .Values.cache.asyncQueries.keyPrefix | default "qc-" | quote }},
|
||||
"db": {{ .Values.cache.asyncQueries.db | default .Values.cache.cacheDb | default 0 | int }},
|
||||
{{- if $redisPasswordForBackend }}
|
||||
"password": {{ $redisPasswordForBackend | quote }},
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Feature Flags */}}
|
||||
{{- if .Values.featureFlags }}
|
||||
FEATURE_FLAGS = {
|
||||
{{- range $key, $value := .Values.featureFlags }}
|
||||
{{- if kindIs "bool" $value }}
|
||||
"{{ $key }}": {{ if $value }}True{{ else }}False{{ end }},
|
||||
{{- else if kindIs "string" $value }}
|
||||
"{{ $key }}": {{ $value | quote }},
|
||||
{{- else if kindIs "float64" $value }}
|
||||
"{{ $key }}": {{ $value }},
|
||||
{{- else if kindIs "int" $value }}
|
||||
"{{ $key }}": {{ $value }},
|
||||
{{- else if kindIs "invalid" $value }}
|
||||
"{{ $key }}": None,
|
||||
{{- else }}
|
||||
"{{ $key }}": json.loads({{ $value | toJson | quote }}),
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{- /* FAB Security API - Required for List Roles view in 6.0.0+ */}}
|
||||
{{- if not (hasKey .Values.config "FAB_ADD_SECURITY_API") }}
|
||||
FAB_ADD_SECURITY_API = True
|
||||
{{- end }}
|
||||
{{- if not (hasKey .Values.config "FAB_ADD_SECURITY_VIEWS") }}
|
||||
FAB_ADD_SECURITY_VIEWS = True
|
||||
{{- end }}
|
||||
|
||||
{{- /* Global Async Queries Transport - Auto-configure for websockets if enabled */}}
|
||||
{{- if .Values.config.GLOBAL_ASYNC_QUERIES_TRANSPORT }}
|
||||
GLOBAL_ASYNC_QUERIES_TRANSPORT = {{ .Values.config.GLOBAL_ASYNC_QUERIES_TRANSPORT | quote }}
|
||||
{{- else if .Values.supersetWebsockets.enabled }}
|
||||
GLOBAL_ASYNC_QUERIES_TRANSPORT = "ws"
|
||||
{{- else }}
|
||||
GLOBAL_ASYNC_QUERIES_TRANSPORT = "polling"
|
||||
{{- end }}
|
||||
|
||||
{{- /* Global Async Queries WebSocket URL */}}
|
||||
{{- $wsUrl := "" }}
|
||||
{{- if .Values.config.GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL }}
|
||||
{{- $wsUrl = .Values.config.GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL }}
|
||||
GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL = {{ $wsUrl | quote }}
|
||||
{{- else if and .Values.supersetWebsockets.enabled .Values.supersetWebsockets.websocketUrl }}
|
||||
{{- $wsUrl = .Values.supersetWebsockets.websocketUrl }}
|
||||
GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL = {{ $wsUrl | quote }}
|
||||
{{- else if .Values.supersetWebsockets.enabled }}
|
||||
{{- $wsServiceName := .Values.cluster.websocketServiceName }}
|
||||
{{- if not $wsServiceName }}
|
||||
{{- $wsServiceName = printf "%s-ws" (include "superset.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- $wsPort := .Values.supersetWebsockets.service.port | default 8080 }}
|
||||
{{- $wsPath := "/ws" }}
|
||||
{{- $clusterDomain := .Values.cluster.domain | default ".svc.cluster.local" }}
|
||||
{{- $wsUrl = printf "ws://%s.%s%s:%d%s" $wsServiceName .Release.Namespace $clusterDomain $wsPort $wsPath }}
|
||||
GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL = {{ $wsUrl | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Global Async Queries JWT Secret */}}
|
||||
{{- if .Values.config.GLOBAL_ASYNC_QUERIES_JWT_SECRET }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_SECRET = {{ .Values.config.GLOBAL_ASYNC_QUERIES_JWT_SECRET | quote }}
|
||||
{{- else if and .Values.supersetWebsockets.enabled .Values.supersetWebsockets.config.jwtSecret }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_SECRET = {{ .Values.supersetWebsockets.config.jwtSecret | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Global Async Queries JWT Cookie Settings */}}
|
||||
{{- if hasKey .Values.config "GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE" }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = {{ .Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE | toString | title }}
|
||||
{{- else if and .Values.supersetWebsockets.enabled (or (hasPrefix "wss://" $wsUrl) .Values.ingress.tls) }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = True
|
||||
{{- else if .Values.supersetWebsockets.enabled }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = False
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE = {{ .Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE | quote }}
|
||||
{{- else if .Values.supersetWebsockets.enabled }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE = "Lax"
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME = {{ .Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME | quote }}
|
||||
{{- else if and .Values.supersetWebsockets.enabled .Values.supersetWebsockets.config.jwtCookieName }}
|
||||
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME = {{ .Values.supersetWebsockets.config.jwtCookieName | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Content Security Policy (CSP) */}}
|
||||
{{- if and .Values.supersetWebsockets.enabled $wsUrl (not (hasKey .Values.config "TALISMAN_CONFIG")) }}
|
||||
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/",
|
||||
"ows.terrestris.de",
|
||||
"https://cdn.document360.io",
|
||||
],
|
||||
"worker-src": ["'self'", "blob:"],
|
||||
"connect-src": [
|
||||
"'self'",
|
||||
{{ $wsUrl | quote }},
|
||||
"https://api.mapbox.com",
|
||||
"https://events.mapbox.com",
|
||||
"https://tile.openstreetmap.org",
|
||||
"https://tile.osm.ch",
|
||||
],
|
||||
"object-src": "'none'",
|
||||
"style-src": [
|
||||
"'self'",
|
||||
"'unsafe-inline'",
|
||||
],
|
||||
"script-src": ["'self'", "'strict-dynamic'"],
|
||||
},
|
||||
"content_security_policy_nonce_in": ["script-src"],
|
||||
{{- if or (hasPrefix "wss://" $wsUrl) .Values.ingress.tls }}
|
||||
"force_https": True,
|
||||
"session_cookie_secure": True,
|
||||
{{- else }}
|
||||
"force_https": False,
|
||||
"session_cookie_secure": False,
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{- /* General Configuration - iterate through all config values */}}
|
||||
{{- range $key, $value := .Values.config }}
|
||||
{{- if and (ne $key "cacheConfig") (ne $key "dataCacheConfig") (ne $key "celeryConfig") (ne $key "resultsBackend") (ne $key "GLOBAL_ASYNC_QUERIES_CACHE_BACKEND") (ne $key "GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND") (ne $key "GLOBAL_ASYNC_QUERIES_TRANSPORT") (ne $key "GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL") (ne $key "GLOBAL_ASYNC_QUERIES_JWT_SECRET") (ne $key "GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE") (ne $key "GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE") (ne $key "GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME") (ne $key "TALISMAN_CONFIG") (ne $key "SQLLAB_ASYNC_TIME_LIMIT_SEC") (ne $key "SQLALCHEMY_TRACK_MODIFICATIONS") }}
|
||||
{{- if kindIs "map" $value }}
|
||||
{{ $key }} = json.loads({{ $value | toJson | quote }})
|
||||
{{- else if kindIs "slice" $value }}
|
||||
{{ $key }} = json.loads({{ $value | toJson | quote }})
|
||||
{{- else if kindIs "bool" $value }}
|
||||
{{ $key }} = {{ if $value }}True{{ else }}False{{ end }}
|
||||
{{- else if kindIs "string" $value }}
|
||||
{{- if or (hasPrefix "f\"" $value) (hasPrefix "F\"" $value) (hasPrefix "r\"" $value) (hasPrefix "R\"" $value) (hasPrefix "b\"" $value) (hasPrefix "B\"" $value) }}
|
||||
{{ $key }} = {{ $value }}
|
||||
{{- else }}
|
||||
{{ $key }} = {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- else if kindIs "invalid" $value }}
|
||||
{{ $key }} = None
|
||||
{{- else }}
|
||||
{{ $key }} = {{ $value | toJson }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Custom Config Overrides */}}
|
||||
{{- if .Values.configOverrides }}
|
||||
# Custom Overrides
|
||||
{{ if .Values.configOverrides }}
|
||||
# Overrides
|
||||
{{- range $key, $value := .Values.configOverrides }}
|
||||
# {{ $key }}
|
||||
{{ tpl $value $ }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.configOverridesFiles }}
|
||||
{{ if .Values.configOverridesFiles }}
|
||||
# Overrides from files
|
||||
{{- $files := .Files }}
|
||||
{{- range $key, $value := .Values.configOverridesFiles }}
|
||||
@@ -680,84 +144,29 @@ TALISMAN_CONFIG = {
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- end -}}
|
||||
|
||||
{{- define "superset.initScript" -}}
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
echo "Upgrading DB schema..."
|
||||
superset db upgrade
|
||||
echo "Initializing roles and permissions..."
|
||||
superset init
|
||||
echo "Init job: Creating admin user and loading initial data..."
|
||||
{{- if .Values.init.createAdmin }}
|
||||
echo "Creating admin user (if not present)..."
|
||||
if superset fab list-users 2>/dev/null | grep -qF {{ printf "username:%s" .Values.init.adminUser.username | squote }}; then
|
||||
echo "Admin user already exists, skipping."
|
||||
else
|
||||
superset fab create-admin \
|
||||
--username {{ .Values.init.adminUser.username | squote }} \
|
||||
--firstname {{ .Values.init.adminUser.firstname | squote }} \
|
||||
--lastname {{ .Values.init.adminUser.lastname | squote }} \
|
||||
--email {{ .Values.init.adminUser.email | squote }} \
|
||||
--password {{ .Values.init.adminUser.password | squote }}
|
||||
fi
|
||||
{{- else }}
|
||||
echo "Skipping admin creation (init.createAdmin=false)"
|
||||
{{- end }}
|
||||
{{- if .Values.init.loadExamples }}
|
||||
echo "Loading examples..."
|
||||
superset load_examples
|
||||
{{- else }}
|
||||
echo "Skipping examples (init.loadExamples=false)"
|
||||
{{- end }}
|
||||
if [ -f "{{ .Values.extraConfigMountPath }}/import_datasources.yaml" ]; then
|
||||
echo "Importing database connections..."
|
||||
superset import_datasources -p {{ .Values.extraConfigMountPath }}/import_datasources.yaml
|
||||
fi
|
||||
echo "Init job complete."
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Deprecation warnings — returns a newline-separated list of active deprecation messages,
|
||||
or empty string when no deprecated keys are set. Rendered in NOTES.txt after install/upgrade.
|
||||
*/}}
|
||||
{{- define "superset.deprecationWarnings" -}}
|
||||
{{- $conn := include "_superset.legacyConn" . | fromJson -}}
|
||||
{{- if gt (len (keys $conn)) 0 }}
|
||||
- supersetNode.connections.* is deprecated; use database.* and cache.* (auto-mapped for now). See UPGRADING.md
|
||||
{{- end }}
|
||||
{{- if .Values.serviceAccountName }}
|
||||
- root serviceAccountName is deprecated; use serviceAccount.name (auto-mapped for now). See UPGRADING.md
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "supersetNode.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: web
|
||||
{{- end }}
|
||||
|
||||
{{- define "supersetCeleryBeat.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: celerybeat
|
||||
app: {{ include "superset.name" . }}-celerybeat
|
||||
release: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "supersetCeleryFlower.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: flower
|
||||
app: {{ include "superset.name" . }}-flower
|
||||
release: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "supersetNode.selectorLabels" -}}
|
||||
app: {{ include "superset.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "supersetWebsockets.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: websocket
|
||||
app: {{ include "superset.name" . }}-ws
|
||||
release: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "supersetWorker.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: worker
|
||||
app: {{ include "superset.name" . }}-worker
|
||||
release: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
@@ -24,7 +24,13 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}-extra-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.labels" . | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
data:
|
||||
{{- range $path, $config := .Values.extraConfigs }}
|
||||
{{ $path }}: |
|
||||
|
||||
@@ -24,7 +24,13 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}-celerybeat
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "celerybeat" "root" .) | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}-celerybeat
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetCeleryBeat.deploymentAnnotations }}
|
||||
annotations: {{- toYaml .Values.supersetCeleryBeat.deploymentAnnotations | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -37,12 +43,9 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/superset_config.py: {{ include "superset.config" . | sha256sum }}
|
||||
checksum/superset_config.py: {{ include "superset-config" . | sha256sum }}
|
||||
checksum/superset_bootstrap.sh: {{ tpl .Values.bootstrapScript . | sha256sum }}
|
||||
checksum/database: {{ .Values.database | toYaml | sha256sum }}
|
||||
checksum/redis: {{ .Values.cache | toYaml | sha256sum }}
|
||||
checksum/config: {{ .Values.config | toYaml | sha256sum }}
|
||||
checksum/featureFlags: {{ .Values.featureFlags | toYaml | sha256sum }}
|
||||
checksum/connections: {{ .Values.supersetNode.connections | toYaml | sha256sum }}
|
||||
checksum/extraConfigs: {{ .Values.extraConfigs | toYaml | sha256sum }}
|
||||
checksum/extraSecrets: {{ .Values.extraSecrets | toYaml | sha256sum }}
|
||||
checksum/extraSecretEnv: {{ .Values.extraSecretEnv | toYaml | sha256sum }}
|
||||
@@ -55,11 +58,12 @@ spec:
|
||||
{{- if .Values.supersetCeleryBeat.podAnnotations }}
|
||||
{{- toYaml .Values.supersetCeleryBeat.podAnnotations | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.globalPodAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "supersetCeleryBeat.selectorLabels" . | nindent 8 }}
|
||||
app: "{{ template "superset.name" . }}-celerybeat"
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetCeleryBeat.podLabels }}
|
||||
{{- toYaml .Values.supersetCeleryBeat.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -24,7 +24,13 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}-flower
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "flower" "root" .) | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}-flower
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetCeleryFlower.deploymentAnnotations }}
|
||||
annotations: {{- toYaml .Values.supersetCeleryFlower.deploymentAnnotations | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -36,16 +42,17 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: {{ include "superset.config" . | sha256sum }}
|
||||
checksum/config: {{ include "superset-config" . | sha256sum }}
|
||||
checksum/secrets: {{ tpl (toJson .Values.extraSecretEnv) . | sha256sum }}
|
||||
{{- if .Values.supersetCeleryFlower.podAnnotations }}
|
||||
{{- toYaml .Values.supersetCeleryFlower.podAnnotations | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.globalPodAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "supersetCeleryFlower.selectorLabels" . | nindent 8 }}
|
||||
app: "{{ template "superset.name" . }}-flower"
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetCeleryFlower.podLabels }}
|
||||
{{- toYaml .Values.supersetCeleryFlower.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -23,9 +23,15 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}-worker
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "worker" "root" .) | nindent 4 }}
|
||||
{{- with .Values.supersetWorker.deploymentLabels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}-worker
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetWorker.deploymentLabels }}
|
||||
{{- toYaml .Values.supersetWorker.deploymentLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetWorker.deploymentAnnotations }}
|
||||
annotations: {{- toYaml .Values.supersetWorker.deploymentAnnotations | nindent 4 }}
|
||||
@@ -43,12 +49,9 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/superset_config.py: {{ include "superset.config" . | sha256sum }}
|
||||
checksum/superset_config.py: {{ include "superset-config" . | sha256sum }}
|
||||
checksum/superset_bootstrap.sh: {{ tpl .Values.bootstrapScript . | sha256sum }}
|
||||
checksum/database: {{ .Values.database | toYaml | sha256sum }}
|
||||
checksum/redis: {{ .Values.cache | toYaml | sha256sum }}
|
||||
checksum/config: {{ .Values.config | toYaml | sha256sum }}
|
||||
checksum/featureFlags: {{ .Values.featureFlags | toYaml | sha256sum }}
|
||||
checksum/connections: {{ .Values.supersetNode.connections | toYaml | sha256sum }}
|
||||
checksum/extraConfigs: {{ .Values.extraConfigs | toYaml | sha256sum }}
|
||||
checksum/extraSecrets: {{ .Values.extraSecrets | toYaml | sha256sum }}
|
||||
checksum/extraSecretEnv: {{ .Values.extraSecretEnv | toYaml | sha256sum }}
|
||||
@@ -61,11 +64,12 @@ spec:
|
||||
{{- if .Values.supersetWorker.podAnnotations }}
|
||||
{{- toYaml .Values.supersetWorker.podAnnotations | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.globalPodAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "supersetWorker.selectorLabels" . | nindent 8 }}
|
||||
app: {{ template "superset.name" . }}-worker
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetWorker.podLabels }}
|
||||
{{- toYaml .Values.supersetWorker.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -24,7 +24,13 @@ metadata:
|
||||
name: "{{ template "superset.fullname" . }}-ws"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "websocket" "root" .) | nindent 4 }}
|
||||
app: "{{ template "superset.name" . }}-ws"
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetWebsockets.deploymentAnnotations }}
|
||||
annotations: {{- toYaml .Values.supersetWebsockets.deploymentAnnotations | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -44,11 +50,12 @@ spec:
|
||||
{{- if .Values.supersetWebsockets.podAnnotations }}
|
||||
{{- toYaml .Values.supersetWebsockets.podAnnotations | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.globalPodAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "supersetWebsockets.selectorLabels" . | nindent 8 }}
|
||||
app: "{{ template "superset.name" . }}-ws"
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetWebsockets.podLabels }}
|
||||
{{- toYaml .Values.supersetWebsockets.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -23,9 +23,15 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "web" "root" .) | nindent 4 }}
|
||||
{{- with .Values.supersetNode.deploymentLabels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetNode.deploymentLabels }}
|
||||
{{- toYaml .Values.supersetNode.deploymentLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetNode.deploymentAnnotations }}
|
||||
annotations: {{- toYaml .Values.supersetNode.deploymentAnnotations | nindent 4 }}
|
||||
@@ -44,13 +50,10 @@ spec:
|
||||
metadata:
|
||||
annotations:
|
||||
# Force reload on config changes
|
||||
checksum/superset_config.py: {{ include "superset.config" . | sha256sum }}
|
||||
checksum/superset_init.sh: {{ include "superset.initScript" . | sha256sum }}
|
||||
checksum/superset_config.py: {{ include "superset-config" . | sha256sum }}
|
||||
checksum/superset_init.sh: {{ tpl .Values.init.initscript . | sha256sum }}
|
||||
checksum/superset_bootstrap.sh: {{ tpl .Values.bootstrapScript . | sha256sum }}
|
||||
checksum/database: {{ .Values.database | toYaml | sha256sum }}
|
||||
checksum/redis: {{ .Values.cache | toYaml | sha256sum }}
|
||||
checksum/config: {{ .Values.config | toYaml | sha256sum }}
|
||||
checksum/featureFlags: {{ .Values.featureFlags | toYaml | sha256sum }}
|
||||
checksum/connections: {{ .Values.supersetNode.connections | toYaml | sha256sum }}
|
||||
checksum/extraConfigs: {{ .Values.extraConfigs | toYaml | sha256sum }}
|
||||
checksum/extraSecrets: {{ .Values.extraSecrets | toYaml | sha256sum }}
|
||||
checksum/extraSecretEnv: {{ .Values.extraSecretEnv | toYaml | sha256sum }}
|
||||
@@ -63,11 +66,12 @@ spec:
|
||||
{{- if .Values.supersetNode.podAnnotations }}
|
||||
{{- toYaml .Values.supersetNode.podAnnotations | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.globalPodAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "supersetNode.selectorLabels" . | nindent 8 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetNode.podLabels }}
|
||||
{{- toYaml .Values.supersetNode.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -23,7 +23,13 @@ kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "superset.fullname" . }}-hpa
|
||||
labels:
|
||||
{{- include "superset.labels" . | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
|
||||
@@ -23,7 +23,13 @@ kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "superset.fullname" . }}-hpa-worker
|
||||
labels:
|
||||
{{- include "superset.labels" . | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
|
||||
@@ -25,7 +25,13 @@ metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "ingress" "root" .) | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations: {{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -24,7 +24,13 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}-init-db
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "init" "root" .) | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.init.jobAnnotations }}
|
||||
annotations: {{- toYaml .Values.init.jobAnnotations | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -36,7 +42,9 @@ spec:
|
||||
annotations: {{- toYaml .Values.init.podAnnotations | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "superset.componentSelectorLabels" (dict "component" "init" "root" .) | nindent 8 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
job: {{ template "superset.fullname" . }}-init-db
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 8 }}
|
||||
|
||||
@@ -27,7 +27,13 @@ kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "superset.fullname" $ }}-celerybeat-pdb
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "celerybeat" "root" $) | nindent 4 }}
|
||||
app: {{ template "superset.name" $ }}-celerybeat
|
||||
chart: {{ template "superset.chart" $ }}
|
||||
release: {{ $.Release.Name }}
|
||||
heritage: {{ $.Release.Service }}
|
||||
{{- if $.Values.extraLabels }}
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
|
||||
@@ -27,7 +27,13 @@ kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "superset.fullname" $ }}-flower-pdb
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "flower" "root" $) | nindent 4 }}
|
||||
app: {{ template "superset.name" $ }}-flower
|
||||
chart: {{ template "superset.chart" $ }}
|
||||
release: {{ $.Release.Name }}
|
||||
heritage: {{ $.Release.Service }}
|
||||
{{- if $.Values.extraLabels }}
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
|
||||
@@ -27,7 +27,13 @@ kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "superset.fullname" $ }}-worker-pdb
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "worker" "root" $) | nindent 4 }}
|
||||
app: {{ template "superset.name" $ }}-worker
|
||||
chart: {{ template "superset.chart" $ }}
|
||||
release: {{ $.Release.Name }}
|
||||
heritage: {{ $.Release.Service }}
|
||||
{{- if $.Values.extraLabels }}
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
|
||||
@@ -27,7 +27,13 @@ kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "superset.fullname" $ }}-ws-pdb
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "websocket" "root" $) | nindent 4 }}
|
||||
app: {{ template "superset.name" $ }}-ws
|
||||
chart: {{ template "superset.chart" $ }}
|
||||
release: {{ $.Release.Name }}
|
||||
heritage: {{ $.Release.Service }}
|
||||
{{- if $.Values.extraLabels }}
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
|
||||
@@ -27,7 +27,13 @@ kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "superset.fullname" $ }}-pdb
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "web" "root" $) | nindent 4 }}
|
||||
app: {{ template "superset.name" $ }}
|
||||
chart: {{ template "superset.chart" $ }}
|
||||
release: {{ $.Release.Name }}
|
||||
heritage: {{ $.Release.Service }}
|
||||
{{- if $.Values.extraLabels }}
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
|
||||
@@ -23,31 +23,33 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}-env
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.labels" . | nindent 4 }}
|
||||
app: {{ template "superset.fullname" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: "{{ .Release.Name }}"
|
||||
heritage: "{{ .Release.Service }}"
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: {{ include "superset.db.host" . | quote }}
|
||||
DB_PORT: {{ include "superset.db.port" . | quote }}
|
||||
DB_USER: {{ include "superset.db.user" . | quote }}
|
||||
DB_PASS: {{ include "superset.db.password" . | quote }}
|
||||
DB_NAME: {{ include "superset.db.name" . | quote }}
|
||||
{{- if .Values.database.ssl.enabled }}
|
||||
DB_SSL_MODE: {{ .Values.database.ssl.mode | default "require" | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.cache.enabled }}
|
||||
REDIS_HOST: {{ include "superset.redis.host" . | quote }}
|
||||
REDIS_PORT: {{ include "superset.redis.port" . | quote }}
|
||||
REDIS_USER: {{ include "superset.redis.user" . | quote }}
|
||||
{{- if include "superset.redis.password" . }}
|
||||
REDIS_PASSWORD: {{ include "superset.redis.password" . | quote }}
|
||||
{{- end }}
|
||||
REDIS_DB: {{ include "superset.redis.cacheDb" . | quote }}
|
||||
REDIS_CELERY_DB: {{ include "superset.redis.celeryDb" . | quote }}
|
||||
REDIS_PROTO: {{ include "superset.redis.proto" . | quote }}
|
||||
{{- if .Values.cache.driver }}
|
||||
REDIS_DRIVER: {{ .Values.cache.driver | quote }}
|
||||
REDIS_HOST: {{ tpl .Values.supersetNode.connections.redis_host . | quote }}
|
||||
REDIS_USER: {{ .Values.supersetNode.connections.redis_user | quote }}
|
||||
{{- if .Values.supersetNode.connections.redis_password }}
|
||||
REDIS_PASSWORD: {{ .Values.supersetNode.connections.redis_password | quote }}
|
||||
{{- end }}
|
||||
REDIS_PORT: {{ .Values.supersetNode.connections.redis_port | quote }}
|
||||
REDIS_PROTO: {{ if .Values.supersetNode.connections.redis_ssl.enabled }}"rediss"{{ else }}"redis"{{ end }}
|
||||
REDIS_DRIVER: {{ .Values.supersetNode.connections.redis_driver | quote }}
|
||||
REDIS_DB: {{ .Values.supersetNode.connections.redis_cache_db | quote }}
|
||||
REDIS_CELERY_DB: {{ .Values.supersetNode.connections.redis_celery_db | quote }}
|
||||
{{- if .Values.supersetNode.connections.redis_ssl.enabled }}
|
||||
REDIS_SSL_CERT_REQS: {{ .Values.supersetNode.connections.redis_ssl.ssl_cert_reqs | default "CERT_NONE" | quote }}
|
||||
{{- end }}
|
||||
DB_HOST: {{ tpl .Values.supersetNode.connections.db_host . | quote }}
|
||||
DB_PORT: {{ .Values.supersetNode.connections.db_port | quote }}
|
||||
DB_USER: {{ .Values.supersetNode.connections.db_user | quote }}
|
||||
DB_PASS: {{ .Values.supersetNode.connections.db_pass | quote }}
|
||||
DB_NAME: {{ .Values.supersetNode.connections.db_name | quote }}
|
||||
{{- if .Values.extraSecretEnv }}
|
||||
{{- range $key, $value := .Values.extraSecretEnv }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
|
||||
@@ -23,13 +23,19 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.labels" . | nindent 4 }}
|
||||
app: {{ template "superset.fullname" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: "{{ .Release.Name }}"
|
||||
heritage: "{{ .Release.Service }}"
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
superset_config.py: |
|
||||
{{- include "superset.config" . | nindent 4 }}
|
||||
{{- include "superset-config" . | nindent 4 }}
|
||||
superset_init.sh: |
|
||||
{{- include "superset.initScript" . | nindent 4 }}
|
||||
{{- tpl .Values.init.initscript . | nindent 4 }}
|
||||
superset_bootstrap.sh: |
|
||||
{{- tpl .Values.bootstrapScript . | nindent 4 }}
|
||||
|
||||
|
||||
@@ -24,7 +24,13 @@ metadata:
|
||||
name: "{{ template "superset.fullname" . }}-ws-config"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.labels" . | nindent 4 }}
|
||||
app: {{ template "superset.fullname" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: "{{ .Release.Name }}"
|
||||
heritage: "{{ .Release.Service }}"
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
config.json: |
|
||||
|
||||
@@ -24,7 +24,13 @@ metadata:
|
||||
name: "{{ template "superset.fullname" . }}-flower"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "flower" "root" .) | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.supersetCeleryFlower.service.annotations }}
|
||||
annotations: {{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -39,7 +45,8 @@ spec:
|
||||
nodePort: {{ .Values.supersetCeleryFlower.service.nodePort.http }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "supersetCeleryFlower.selectorLabels" . | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}-flower
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Values.supersetCeleryFlower.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.supersetCeleryFlower.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
|
||||
@@ -24,7 +24,13 @@ metadata:
|
||||
name: "{{ template "superset.fullname" . }}-ws"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "websocket" "root" .) | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.supersetWebsockets.service.annotations }}
|
||||
annotations: {{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -39,7 +45,8 @@ spec:
|
||||
nodePort: {{ .Values.supersetWebsockets.service.nodePort.http }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "supersetWebsockets.selectorLabels" . | nindent 4 }}
|
||||
app: "{{ template "superset.name" . }}-ws"
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Values.supersetWebsockets.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.supersetWebsockets.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
|
||||
@@ -23,7 +23,13 @@ metadata:
|
||||
name: {{ template "superset.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "web" "root" .) | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.service.annotations }}
|
||||
annotations: {{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -38,7 +44,8 @@ spec:
|
||||
nodePort: {{ .Values.service.nodePort.http }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "supersetNode.selectorLabels" . | nindent 4 }}
|
||||
app: {{ template "superset.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Values.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
|
||||
@@ -24,11 +24,17 @@ metadata:
|
||||
name: {{ include "superset.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
helm.sh/chart: {{ include "superset.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- if semverCompare "> 1.6" .Capabilities.KubeVersion.GitVersion }}
|
||||
kubernetes.io/cluster-service: "true"
|
||||
{{- end }}
|
||||
addonmanager.kubernetes.io/mode: Reconcile
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.serviceAccount.annotations }}
|
||||
annotations: {{- toYaml .Values.serviceAccount.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -1,132 +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.
|
||||
#
|
||||
suite: config checksums + global pod annotations
|
||||
templates:
|
||||
- deployment.yaml
|
||||
- deployment-worker.yaml
|
||||
- deployment-beat.yaml
|
||||
- deployment-flower.yaml
|
||||
- deployment-ws.yaml
|
||||
tests:
|
||||
- it: main deployment has new config checksums, not the old connections checksum
|
||||
template: deployment.yaml
|
||||
asserts:
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/database"]'
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/config"]'
|
||||
- notExists:
|
||||
path: 'spec.template.metadata.annotations["checksum/connections"]'
|
||||
- it: main deployment applies globalPodAnnotations
|
||||
template: deployment.yaml
|
||||
set:
|
||||
globalPodAnnotations:
|
||||
team: data
|
||||
asserts:
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.team'
|
||||
value: data
|
||||
- it: globalPodAnnotations coexist with per-component podAnnotations on deployment.yaml
|
||||
template: deployment.yaml
|
||||
set:
|
||||
globalPodAnnotations:
|
||||
global: "yes"
|
||||
supersetNode:
|
||||
podAnnotations:
|
||||
component: "yes"
|
||||
asserts:
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.global'
|
||||
value: "yes"
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.component'
|
||||
value: "yes"
|
||||
- it: worker deployment has config and database checksums
|
||||
template: deployment-worker.yaml
|
||||
asserts:
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/database"]'
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/config"]'
|
||||
- it: worker deployment applies globalPodAnnotations
|
||||
template: deployment-worker.yaml
|
||||
set:
|
||||
globalPodAnnotations:
|
||||
team: data
|
||||
asserts:
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.team'
|
||||
value: data
|
||||
- it: beat deployment has config and database checksums
|
||||
template: deployment-beat.yaml
|
||||
set:
|
||||
supersetCeleryBeat:
|
||||
enabled: true
|
||||
asserts:
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/database"]'
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/config"]'
|
||||
- it: beat deployment applies globalPodAnnotations
|
||||
template: deployment-beat.yaml
|
||||
set:
|
||||
supersetCeleryBeat:
|
||||
enabled: true
|
||||
globalPodAnnotations:
|
||||
team: data
|
||||
asserts:
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.team'
|
||||
value: data
|
||||
- it: flower deployment has config checksum
|
||||
template: deployment-flower.yaml
|
||||
set:
|
||||
supersetCeleryFlower:
|
||||
enabled: true
|
||||
asserts:
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/config"]'
|
||||
- it: flower deployment applies globalPodAnnotations
|
||||
template: deployment-flower.yaml
|
||||
set:
|
||||
supersetCeleryFlower:
|
||||
enabled: true
|
||||
globalPodAnnotations:
|
||||
team: data
|
||||
asserts:
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.team'
|
||||
value: data
|
||||
- it: websockets deployment has wsconfig checksum
|
||||
template: deployment-ws.yaml
|
||||
set:
|
||||
supersetWebsockets:
|
||||
enabled: true
|
||||
asserts:
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/wsconfig"]'
|
||||
- it: websockets deployment applies globalPodAnnotations
|
||||
template: deployment-ws.yaml
|
||||
set:
|
||||
supersetWebsockets:
|
||||
enabled: true
|
||||
globalPodAnnotations:
|
||||
team: data
|
||||
asserts:
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.team'
|
||||
value: data
|
||||
@@ -1,94 +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.
|
||||
#
|
||||
suite: superset_config.py rendering
|
||||
templates:
|
||||
- secret-superset-config.yaml
|
||||
tests:
|
||||
- it: builds SQLALCHEMY_DATABASE_URI from env with percent-encoded creds
|
||||
set: {database: {host: pg.svc, port: 5432, user: su, password: pw, name: sset}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'SQLALCHEMY_DATABASE_URI = f"postgresql\+psycopg2://\{quote\(env\(.DB_USER'}
|
||||
- it: honors database.uri override
|
||||
set: {database.uri: "postgresql://x:y@h:5432/d"}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'SQLALCHEMY_DATABASE_URI = "postgresql://x:y@h:5432/d"'}
|
||||
- it: imports required for env/json handling are present
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'import json'}
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'from urllib\.parse import quote'}
|
||||
- it: redis creds are percent-encoded and read from env
|
||||
set: {cache: {enabled: true, password: "p@ss"}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'quote\(env\(.REDIS_PASSWORD'}
|
||||
- it: config map values render via json.loads
|
||||
set: {config: {MY_MAP: {enabled: true}}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'MY_MAP = json\.loads\('}
|
||||
- it: config nil values render as None
|
||||
set: {config: {MY_NIL: null}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'MY_NIL = None'}
|
||||
- it: supersetWorker healthCheck enabled renders readiness file path
|
||||
set: {supersetWorker: {healthCheck: {enabled: true}}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: '/tmp/celery_worker_ready'}
|
||||
- it: SQLALCHEMY_TRACK_MODIFICATIONS defaults False
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'SQLALCHEMY_TRACK_MODIFICATIONS = False'}
|
||||
- it: renders feature flags
|
||||
set: {featureFlags: {ALERT_REPORTS: true}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: '"ALERT_REPORTS": True'}
|
||||
- it: SQLALCHEMY_TRACK_MODIFICATIONS user-set true renders Python True
|
||||
set: {config: {SQLALCHEMY_TRACK_MODIFICATIONS: true}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'SQLALCHEMY_TRACK_MODIFICATIONS = True'}
|
||||
- it: celeryConfig without imports emits a safe empty CELERY_IMPORTS (no AttributeError)
|
||||
set: {config: {celeryConfig: {broker_url: "redis://x"}}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'CELERY_IMPORTS = \(\)'}
|
||||
- notMatchRegex: {path: 'stringData["superset_config.py"]', pattern: 'CELERY_IMPORTS = CeleryConfig\.imports'}
|
||||
- it: legacy db_type maps to the SQLAlchemy driver (deprecation path)
|
||||
set: {supersetNode: {connections: {db_type: "postgresql+pg8000"}}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'SQLALCHEMY_DATABASE_URI = f"postgresql\+pg8000://'}
|
||||
- it: init script single-quotes the admin username (no shell injection)
|
||||
set: {init: {createAdmin: true, adminUser: {password: "x"}}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_init.sh"]', pattern: "grep -qF 'username:"}
|
||||
- notMatchRegex: {path: 'stringData["superset_init.sh"]', pattern: 'create-admin[\s\S]*\|\| true'}
|
||||
- it: sentinel disabled does not fail render
|
||||
set: {cache: {enabled: true, sentinel: {enabled: false}}}
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 1
|
||||
- it: ssl certfile path is quoted
|
||||
set: {cache: {enabled: true, ssl: {enabled: true, certfile: "/etc/ssl/cert.pem"}}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: '"CACHE_REDIS_SSL_CERTFILE": "/etc/ssl/cert.pem"'}
|
||||
- it: explicit JWT cookie secure false is respected
|
||||
set: {supersetWebsockets: {enabled: true}, config: {GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE: false}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = False'}
|
||||
- it: celeryConfig non-string values render as valid Python via json.loads
|
||||
set: {config: {celeryConfig: {broker_url: "redis://x", task_acks_late: true}}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: 'task_acks_late = json\.loads\('}
|
||||
- it: featureFlags non-scalar values render as valid Python via json.loads
|
||||
set: {featureFlags: {SOME_MAP: {nested: true}}}
|
||||
asserts:
|
||||
- matchRegex: {path: 'stringData["superset_config.py"]', pattern: '"SOME_MAP": json\.loads\('}
|
||||
@@ -1,28 +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.
|
||||
#
|
||||
suite: deprecation path does not fail render
|
||||
templates:
|
||||
- secret-superset-config.yaml
|
||||
tests:
|
||||
- it: legacy supersetNode.connections still renders (no fail)
|
||||
set: {supersetNode.connections.db_host: legacy}
|
||||
asserts:
|
||||
- hasDocuments: {count: 1}
|
||||
- it: legacy root serviceAccountName still renders (no fail)
|
||||
set: {serviceAccountName: my-sa}
|
||||
asserts:
|
||||
- hasDocuments: {count: 1}
|
||||
@@ -1,63 +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.
|
||||
#
|
||||
suite: superset_init.sh rendering
|
||||
templates:
|
||||
- secret-superset-config.yaml
|
||||
tests:
|
||||
- it: renders superset db upgrade in init script
|
||||
asserts:
|
||||
- matchRegex:
|
||||
path: 'stringData["superset_init.sh"]'
|
||||
pattern: 'superset db upgrade'
|
||||
- it: renders superset init in init script
|
||||
asserts:
|
||||
- matchRegex:
|
||||
path: 'stringData["superset_init.sh"]'
|
||||
pattern: 'superset init'
|
||||
- it: renders db upgrade before admin creation
|
||||
set:
|
||||
init:
|
||||
createAdmin: true
|
||||
adminUser:
|
||||
username: admin
|
||||
firstname: Admin
|
||||
lastname: User
|
||||
email: admin@example.com
|
||||
password: adminpass
|
||||
asserts:
|
||||
- matchRegex:
|
||||
path: 'stringData["superset_init.sh"]'
|
||||
pattern: 'superset db upgrade'
|
||||
- matchRegex:
|
||||
path: 'stringData["superset_init.sh"]'
|
||||
pattern: 'superset init'
|
||||
- matchRegex:
|
||||
path: 'stringData["superset_init.sh"]'
|
||||
pattern: 'fab create-admin'
|
||||
- it: admin creation is idempotent and does not swallow real failures
|
||||
set:
|
||||
init:
|
||||
createAdmin: true
|
||||
adminUser:
|
||||
password: "x"
|
||||
asserts:
|
||||
- matchRegex:
|
||||
path: 'stringData["superset_init.sh"]'
|
||||
pattern: 'superset fab list-users'
|
||||
- notMatchRegex:
|
||||
path: 'stringData["superset_init.sh"]'
|
||||
pattern: 'create-admin.*\|\| true'
|
||||
@@ -1,520 +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.
|
||||
#
|
||||
suite: Label Consistency Tests
|
||||
templates:
|
||||
- deployment.yaml
|
||||
- deployment-worker.yaml
|
||||
- deployment-beat.yaml
|
||||
- deployment-flower.yaml
|
||||
- deployment-ws.yaml
|
||||
- service.yaml
|
||||
- service-ws.yaml
|
||||
- service-flower.yaml
|
||||
- init-job.yaml
|
||||
- ingress.yaml
|
||||
- configmap-superset.yaml
|
||||
- secret-superset-config.yaml
|
||||
- secret-ws.yaml
|
||||
- pdb.yaml
|
||||
- pdb-worker.yaml
|
||||
- pdb-beat.yaml
|
||||
- pdb-flower.yaml
|
||||
- pdb-ws.yaml
|
||||
|
||||
# These tests validate that Kubernetes recommended labels are consistently applied
|
||||
# across all chart resources per https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
|
||||
#
|
||||
# Required Labels (app.kubernetes.io/):
|
||||
# - name: The name of the application
|
||||
# - instance: A unique name identifying the instance of an application
|
||||
# - version: The current version of the application
|
||||
# - component: The component within the architecture
|
||||
# - part-of: The name of a higher level application this one is part of
|
||||
# - managed-by: The tool being used to manage the operation of an application
|
||||
#
|
||||
# Helm-specific Labels:
|
||||
# - helm.sh/chart: The chart name and version
|
||||
|
||||
tests:
|
||||
# =============================================================================
|
||||
# Main Deployment Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on main deployment
|
||||
template: deployment.yaml
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/version"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/managed-by"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/part-of"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["helm.sh/chart"]
|
||||
|
||||
- it: should have correct component label on main deployment
|
||||
template: deployment.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: web
|
||||
|
||||
- it: should have part-of label set to superset on main deployment
|
||||
template: deployment.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/part-of"]
|
||||
value: superset
|
||||
|
||||
# =============================================================================
|
||||
# Worker Deployment Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on worker deployment
|
||||
template: deployment-worker.yaml
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/version"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/managed-by"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/part-of"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on worker deployment
|
||||
template: deployment-worker.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: worker
|
||||
|
||||
# =============================================================================
|
||||
# Celery Beat Deployment Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on celerybeat deployment
|
||||
template: deployment-beat.yaml
|
||||
set:
|
||||
supersetCeleryBeat.enabled: true
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on celerybeat deployment
|
||||
template: deployment-beat.yaml
|
||||
set:
|
||||
supersetCeleryBeat.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: celerybeat
|
||||
|
||||
# =============================================================================
|
||||
# Flower Deployment Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on flower deployment
|
||||
template: deployment-flower.yaml
|
||||
set:
|
||||
supersetCeleryFlower.enabled: true
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on flower deployment
|
||||
template: deployment-flower.yaml
|
||||
set:
|
||||
supersetCeleryFlower.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: flower
|
||||
|
||||
# =============================================================================
|
||||
# WebSocket Deployment Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on websocket deployment
|
||||
template: deployment-ws.yaml
|
||||
set:
|
||||
supersetWebsockets.enabled: true
|
||||
supersetWebsockets.config.jwtSecret: "test-secret-for-unit-test"
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on websocket deployment
|
||||
template: deployment-ws.yaml
|
||||
set:
|
||||
supersetWebsockets.enabled: true
|
||||
supersetWebsockets.config.jwtSecret: "test-secret-for-unit-test"
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: websocket
|
||||
|
||||
# =============================================================================
|
||||
# Service Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on main service
|
||||
template: service.yaml
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on main service
|
||||
template: service.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: web
|
||||
|
||||
- it: should have all recommended labels on websocket service
|
||||
template: service-ws.yaml
|
||||
set:
|
||||
supersetWebsockets.enabled: true
|
||||
supersetWebsockets.config.jwtSecret: "test-secret-for-unit-test"
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on websocket service
|
||||
template: service-ws.yaml
|
||||
set:
|
||||
supersetWebsockets.enabled: true
|
||||
supersetWebsockets.config.jwtSecret: "test-secret-for-unit-test"
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: websocket
|
||||
|
||||
- it: should have all recommended labels on flower service
|
||||
template: service-flower.yaml
|
||||
set:
|
||||
supersetCeleryFlower.enabled: true
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on flower service
|
||||
template: service-flower.yaml
|
||||
set:
|
||||
supersetCeleryFlower.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: flower
|
||||
|
||||
# =============================================================================
|
||||
# Init Job Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on init job
|
||||
template: init-job.yaml
|
||||
set:
|
||||
init.enabled: true
|
||||
init.createAdmin: true
|
||||
init.adminUser.password: "test-password"
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on init job
|
||||
template: init-job.yaml
|
||||
set:
|
||||
init.enabled: true
|
||||
init.createAdmin: true
|
||||
init.adminUser.password: "test-password"
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: init
|
||||
|
||||
# =============================================================================
|
||||
# Ingress Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on ingress
|
||||
template: ingress.yaml
|
||||
set:
|
||||
ingress.enabled: true
|
||||
ingress.hosts:
|
||||
- host: superset.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on ingress
|
||||
template: ingress.yaml
|
||||
set:
|
||||
ingress.enabled: true
|
||||
ingress.hosts:
|
||||
- host: superset.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: ingress
|
||||
|
||||
# =============================================================================
|
||||
# Selector Label Consistency
|
||||
#
|
||||
# These use value assertions (not isNotNull) on purpose: a missing/misscoped
|
||||
# release name renders as the string "<no value>", which is non-null and would
|
||||
# silently pass isNotNull. Asserting the concrete value catches that class of
|
||||
# bug, and asserting the pod template labels equal the selector guards the
|
||||
# immutable spec.selector.matchLabels <-> pod label invariant.
|
||||
# =============================================================================
|
||||
- it: should set selector matchLabels to concrete values on main deployment
|
||||
template: deployment.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/name"]
|
||||
value: superset
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/component"]
|
||||
value: web
|
||||
|
||||
- it: should match pod template labels to the selector on main deployment
|
||||
template: deployment.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/name"]
|
||||
value: superset
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/component"]
|
||||
value: web
|
||||
|
||||
- it: should set selector matchLabels to concrete values on worker deployment
|
||||
template: deployment-worker.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/component"]
|
||||
value: worker
|
||||
|
||||
- it: should match pod template labels to the selector on worker deployment
|
||||
template: deployment-worker.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/component"]
|
||||
value: worker
|
||||
|
||||
# =============================================================================
|
||||
# Extra Labels Support
|
||||
# =============================================================================
|
||||
- it: should include extraLabels when specified
|
||||
template: deployment.yaml
|
||||
set:
|
||||
extraLabels:
|
||||
custom-label: custom-value
|
||||
environment: production
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels.custom-label
|
||||
value: custom-value
|
||||
- equal:
|
||||
path: metadata.labels.environment
|
||||
value: production
|
||||
|
||||
- it: should include extraLabels in service
|
||||
template: service.yaml
|
||||
set:
|
||||
extraLabels:
|
||||
custom-label: custom-value
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels.custom-label
|
||||
value: custom-value
|
||||
|
||||
# =============================================================================
|
||||
# ConfigMap / Secret Labels
|
||||
# =============================================================================
|
||||
- it: should have recommended labels on extra-config configmap
|
||||
template: configmap-superset.yaml
|
||||
set:
|
||||
extraConfigs:
|
||||
custom.py: "FOO = 1"
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/managed-by"]
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/part-of"]
|
||||
value: superset
|
||||
|
||||
- it: should have recommended labels on superset config secret
|
||||
template: secret-superset-config.yaml
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/part-of"]
|
||||
value: superset
|
||||
|
||||
- it: should have recommended labels on websocket config secret
|
||||
template: secret-ws.yaml
|
||||
set:
|
||||
supersetWebsockets.enabled: true
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
|
||||
# =============================================================================
|
||||
# PodDisruptionBudget Labels (metadata must match the selector)
|
||||
# =============================================================================
|
||||
- it: should have recommended labels and matching selector on main pdb
|
||||
template: pdb.yaml
|
||||
set:
|
||||
supersetNode.podDisruptionBudget.enabled: true
|
||||
supersetNode.podDisruptionBudget.maxUnavailable: null
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: web
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/component"]
|
||||
value: web
|
||||
|
||||
- it: should set correct component on worker pdb
|
||||
template: pdb-worker.yaml
|
||||
set:
|
||||
supersetWorker.podDisruptionBudget.enabled: true
|
||||
supersetWorker.podDisruptionBudget.maxUnavailable: null
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: worker
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/component"]
|
||||
value: worker
|
||||
|
||||
- it: should set correct component on celerybeat pdb
|
||||
template: pdb-beat.yaml
|
||||
set:
|
||||
supersetCeleryBeat.podDisruptionBudget.enabled: true
|
||||
supersetCeleryBeat.podDisruptionBudget.maxUnavailable: null
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: celerybeat
|
||||
|
||||
- it: should set correct component on flower pdb
|
||||
template: pdb-flower.yaml
|
||||
set:
|
||||
supersetCeleryFlower.podDisruptionBudget.enabled: true
|
||||
supersetCeleryFlower.podDisruptionBudget.maxUnavailable: null
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: flower
|
||||
|
||||
- it: should set correct component on websocket pdb
|
||||
template: pdb-ws.yaml
|
||||
set:
|
||||
supersetWebsockets.enabled: true
|
||||
supersetWebsockets.podDisruptionBudget.enabled: true
|
||||
supersetWebsockets.podDisruptionBudget.maxUnavailable: null
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: websocket
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/component"]
|
||||
value: websocket
|
||||
|
||||
- it: should use recommended labels on init job pod template
|
||||
template: init-job.yaml
|
||||
set:
|
||||
init.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/component"]
|
||||
value: init
|
||||
- isNotNull:
|
||||
path: spec.template.metadata.labels.job
|
||||
@@ -1,71 +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.
|
||||
#
|
||||
suite: secret-env schema + deprecation mapping
|
||||
templates:
|
||||
- secret-env.yaml
|
||||
tests:
|
||||
- it: emits DB_* and REDIS_* from new schema
|
||||
set:
|
||||
database: {host: pg.svc, port: 5432, user: su, password: pw, name: superset}
|
||||
cache: {enabled: true, host: rd.svc, port: 6379, cacheDb: 1, celeryDb: 0}
|
||||
asserts:
|
||||
- equal: {path: 'stringData.DB_HOST', value: pg.svc}
|
||||
- equal: {path: 'stringData.DB_PORT', value: "5432"}
|
||||
- equal: {path: 'stringData.REDIS_HOST', value: rd.svc}
|
||||
- it: maps ALL legacy supersetNode.connections.* keys (deprecation path, no fail)
|
||||
set:
|
||||
cache:
|
||||
enabled: true
|
||||
supersetNode:
|
||||
connections:
|
||||
db_host: legacy-pg
|
||||
db_port: "5555"
|
||||
db_user: legacy-user
|
||||
db_pass: legacy-pass
|
||||
db_name: legacy-name
|
||||
redis_host: legacy-rd
|
||||
redis_port: "6380"
|
||||
redis_cache_db: "7"
|
||||
redis_celery_db: "8"
|
||||
redis_driver: rediss
|
||||
asserts:
|
||||
- equal: {path: 'stringData.DB_HOST', value: legacy-pg}
|
||||
- equal: {path: 'stringData.DB_PORT', value: "5555"}
|
||||
- equal: {path: 'stringData.DB_USER', value: legacy-user}
|
||||
- equal: {path: 'stringData.DB_PASS', value: legacy-pass}
|
||||
- equal: {path: 'stringData.DB_NAME', value: legacy-name}
|
||||
- equal: {path: 'stringData.REDIS_HOST', value: legacy-rd}
|
||||
- equal: {path: 'stringData.REDIS_PORT', value: "6380"}
|
||||
- equal: {path: 'stringData.REDIS_DB', value: "7"}
|
||||
- equal: {path: 'stringData.REDIS_CELERY_DB', value: "8"}
|
||||
- equal: {path: 'stringData.REDIS_PROTO', value: rediss}
|
||||
- it: new-schema values still win over legacy when both are set
|
||||
set:
|
||||
database: {host: new-host, port: 1234}
|
||||
supersetNode:
|
||||
connections: {db_host: old-host, db_port: "9999"}
|
||||
asserts:
|
||||
- equal: {path: 'stringData.DB_HOST', value: new-host}
|
||||
- equal: {path: 'stringData.DB_PORT', value: "1234"}
|
||||
- it: emits REDIS_DRIVER when cache.driver set
|
||||
set: {cache: {enabled: true, driver: "rediss+managed"}}
|
||||
asserts:
|
||||
- equal: {path: 'stringData.REDIS_DRIVER', value: "rediss+managed"}
|
||||
- it: omits redis vars when cache disabled
|
||||
set: {cache.enabled: false}
|
||||
asserts:
|
||||
- notExists: {path: 'stringData.REDIS_HOST'}
|
||||
@@ -1,28 +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.
|
||||
#
|
||||
suite: serviceAccountName resolution
|
||||
templates:
|
||||
- serviceaccount.yaml
|
||||
tests:
|
||||
- it: uses serviceAccount.name when set
|
||||
set: {serviceAccount: {create: true, name: my-sa}}
|
||||
asserts:
|
||||
- equal: {path: 'metadata.name', value: my-sa}
|
||||
- it: falls back to legacy root serviceAccountName (deprecation path)
|
||||
set: {serviceAccount: {create: true}, serviceAccountName: legacy-sa}
|
||||
asserts:
|
||||
- equal: {path: 'metadata.name', value: legacy-sa}
|
||||
@@ -1,30 +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.
|
||||
#
|
||||
suite: values defaults
|
||||
templates:
|
||||
- secret-env.yaml
|
||||
tests:
|
||||
- it: renders with new database defaults
|
||||
set:
|
||||
database.host: db.example
|
||||
cache.enabled: true
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 1
|
||||
- equal:
|
||||
path: 'stringData.DB_HOST'
|
||||
value: db.example
|
||||
@@ -1,140 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"database": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"uri": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"driver": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"host": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"port": {
|
||||
"type": ["integer", "string", "null"]
|
||||
},
|
||||
"user": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"password": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"name": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"ssl": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"driver": {
|
||||
"type": "string"
|
||||
},
|
||||
"host": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"port": {
|
||||
"type": ["integer", "string", "null"]
|
||||
},
|
||||
"cacheDb": {
|
||||
"type": ["integer", "string", "null"]
|
||||
},
|
||||
"celeryDb": {
|
||||
"type": ["integer", "string", "null"]
|
||||
},
|
||||
"ssl": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cluster": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"databaseServiceName": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"redisServiceName": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"websocketServiceName": {
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"featureFlags": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"serviceAccount": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"create": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"annotations": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"globalPodAnnotations": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"image": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"repository": {
|
||||
"type": "string"
|
||||
},
|
||||
"tag": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"pullPolicy": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,30 +28,9 @@ nameOverride: ~
|
||||
# -- Provide a name to override the full names of resources
|
||||
fullnameOverride: ~
|
||||
|
||||
# -- Kubernetes cluster configuration
|
||||
# Used for constructing service URLs between chart components
|
||||
cluster:
|
||||
# -- Kubernetes cluster domain (default: .svc.cluster.local)
|
||||
# Override if using a custom cluster domain
|
||||
domain: ".svc.cluster.local"
|
||||
# -- Database service name (default: {{ .Release.Name }}-postgresql)
|
||||
# Override if using a different service name for the database
|
||||
databaseServiceName: ~
|
||||
# -- Redis service name (default: {{ .Release.Name }}-redis-headless)
|
||||
# Override if using a different service name for Redis
|
||||
redisServiceName: ~
|
||||
# -- WebSocket service name (default: {{ .Release.Name }}-ws)
|
||||
# Override if using a different service name for the WebSocket service
|
||||
websocketServiceName: ~
|
||||
|
||||
# -- Labels to be added to all resources
|
||||
extraLabels: {}
|
||||
|
||||
# -- Global pod annotations to be added to all pods
|
||||
# Use this to set annotations that apply to all Superset components
|
||||
# Component-specific podAnnotations will be merged with these global annotations
|
||||
globalPodAnnotations: {}
|
||||
|
||||
# -- User ID directive. This user must have enough permissions to run the bootstrap script
|
||||
# Running containers as root is not recommended in production. Change this to another UID - e.g. 1000 to be more secure
|
||||
runAsUser: 0
|
||||
@@ -67,8 +46,6 @@ serviceAccountName: ~
|
||||
serviceAccount:
|
||||
# -- Create custom service account for Superset. If create: true and serviceAccountName is not provided, `superset.fullname` will be used.
|
||||
create: false
|
||||
# -- Service account name to use (if not specified, defaults to release name + chart name)
|
||||
name: ""
|
||||
annotations: {}
|
||||
|
||||
# -- Install additional packages and do any other bootstrap configuration in this script
|
||||
@@ -267,89 +244,6 @@ hostAliases: []
|
||||
# - nodns.my.lan
|
||||
# ip: 18.27.36.45
|
||||
|
||||
# -- Database connection configuration for the Superset metadata database
|
||||
database:
|
||||
# -- Full database URI (overrides host/port/user/pass/name if set)
|
||||
# Example: "postgresql+psycopg2://user:pass@host:5432/dbname"
|
||||
uri: ~
|
||||
# -- Database driver used when uri is not set (default: postgresql+psycopg2 when unset;
|
||||
# legacy supersetNode.connections.db_type is honored when this is unset)
|
||||
driver: ~
|
||||
# -- Database host (default: {{ .Release.Name }}-postgresql)
|
||||
host: ~
|
||||
# -- Database port (default: 5432 when unset; legacy supersetNode.connections.db_port is honored)
|
||||
port: ~
|
||||
# -- Database user (default: superset, resolved via superset.db.user)
|
||||
user: ~
|
||||
# -- Database password (default: superset, resolved via superset.db.password)
|
||||
# ⚠️ CHANGE THIS for production
|
||||
password: ~
|
||||
# -- Database name (default: superset, resolved via superset.db.name)
|
||||
name: ~
|
||||
# -- Database SSL configuration
|
||||
ssl:
|
||||
enabled: false
|
||||
mode: require
|
||||
|
||||
# -- Redis cache configuration for Superset
|
||||
# Redis is optional but recommended for caching and Celery.
|
||||
# If redis.enabled (chart dependency) is true, defaults point to the chart's Redis instance.
|
||||
cache:
|
||||
# -- Enable Redis-based features (cache, Celery). Set to false to disable Redis usage entirely.
|
||||
enabled: true
|
||||
# -- Full Redis cache URL (overrides host/port/user/pass if set)
|
||||
cacheUrl: ~
|
||||
# -- Full Redis Celery URL (overrides host/port/user/pass if set)
|
||||
celeryUrl: ~
|
||||
# -- Redis host (default: {{ .Release.Name }}-redis-headless)
|
||||
host: ~
|
||||
# -- Redis port (default: 6379 when unset; legacy supersetNode.connections.redis_port is honored)
|
||||
port: ~
|
||||
# -- Redis user (optional, for Redis ACL)
|
||||
user: ""
|
||||
# -- Redis password
|
||||
password: ~
|
||||
# -- Redis database number for cache (default: 1 when unset; legacy redis_cache_db is honored)
|
||||
cacheDb: ~
|
||||
# -- Redis database number for Celery (default: 0 when unset; legacy redis_celery_db is honored)
|
||||
celeryDb: ~
|
||||
# -- Cache key prefix
|
||||
keyPrefix: "superset_"
|
||||
# -- Default cache timeout in seconds
|
||||
defaultTimeout: 86400
|
||||
# -- Results backend key prefix
|
||||
resultsBackendKeyPrefix: "superset_results"
|
||||
# -- Async queries configuration
|
||||
asyncQueries:
|
||||
keyPrefix: "qc-"
|
||||
timeout: 86400
|
||||
# -- Redis Sentinel configuration (optional)
|
||||
sentinel: ~
|
||||
# -- Redis SSL configuration
|
||||
ssl:
|
||||
enabled: false
|
||||
ssl_cert_reqs: required
|
||||
certfile: ~
|
||||
keyfile: ~
|
||||
ca_certs: ~
|
||||
# -- Custom Redis driver (e.g. TLS/managed variants); overrides the redis proto in URLs when set.
|
||||
# Ports the legacy supersetNode.connections.redis_driver escape hatch.
|
||||
driver: ""
|
||||
|
||||
# -- Superset configuration properties
|
||||
# Set any configuration property from superset/config.py here
|
||||
# See https://github.com/apache/superset/blob/master/superset/config.py for all available options
|
||||
config: {}
|
||||
# SECRET_KEY: "your-secret-key-here"
|
||||
# ROW_LIMIT: 50000
|
||||
# DEBUG: false
|
||||
|
||||
# -- Feature flags configuration
|
||||
# See https://github.com/apache/superset/blob/master/RESOURCES/FEATURE_FLAGS.md
|
||||
featureFlags: {}
|
||||
# ALERT_REPORTS: true
|
||||
# DASHBOARD_RBAC: true
|
||||
|
||||
# Superset node configuration
|
||||
supersetNode:
|
||||
replicas:
|
||||
@@ -376,8 +270,28 @@ supersetNode:
|
||||
- "/bin/sh"
|
||||
- "-c"
|
||||
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; exec /usr/bin/run-server.sh"
|
||||
# DEPRECATED: use database.* and cache.* instead (still honored if set). See UPGRADING.md
|
||||
connections: {}
|
||||
connections:
|
||||
# -- Change in case of bringing your own redis and then also set redis.enabled:false
|
||||
redis_host: "{{ .Release.Name }}-redis-headless"
|
||||
redis_port: "6379"
|
||||
redis_user: ""
|
||||
# redis_password: superset
|
||||
redis_cache_db: "1"
|
||||
redis_celery_db: "0"
|
||||
# Or SSL port is usually 6380
|
||||
# Update following for using Redis with SSL
|
||||
redis_ssl:
|
||||
enabled: false
|
||||
ssl_cert_reqs: CERT_NONE
|
||||
redis_driver: ""
|
||||
# You need to change below configuration incase bringing own PostgresSQL instance and also set postgresql.enabled:false
|
||||
# -- Database type for Superset metadata (Supported types: "postgresql", "mysql")
|
||||
db_type: "postgresql"
|
||||
db_host: "{{ .Release.Name }}-postgresql"
|
||||
db_port: "5432"
|
||||
db_user: superset
|
||||
db_pass: superset
|
||||
db_name: superset
|
||||
env: {}
|
||||
# -- If true, forces deployment to reload on each upgrade
|
||||
forceReload: false
|
||||
@@ -594,17 +508,6 @@ supersetWorker:
|
||||
startupProbe: {}
|
||||
# -- No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic)
|
||||
readinessProbe: {}
|
||||
# -- Celery worker file-based health check (worker writes readiness/liveness files via signals;
|
||||
# point supersetWorker.readinessProbe/livenessProbe at these files to use them)
|
||||
healthCheck:
|
||||
# -- Enable the file-based Celery worker health check
|
||||
enabled: false
|
||||
# -- Readiness file (created when the worker is ready, removed on shutdown)
|
||||
readinessFile: "/tmp/celery_worker_ready"
|
||||
# -- Liveness file (touched periodically by a heartbeat thread)
|
||||
livenessFile: "/tmp/celery_worker_alive"
|
||||
# -- Seconds between liveness heartbeats
|
||||
livenessHeartbeatInterval: 10
|
||||
# -- Set priorityClassName for supersetWorker pods
|
||||
priorityClassName: ~
|
||||
|
||||
@@ -967,11 +870,8 @@ init:
|
||||
requests:
|
||||
cpu: "250m"
|
||||
memory: "128Mi"
|
||||
# -- DEPRECATED: this field is no longer used by the chart.
|
||||
# The init script is rendered entirely from the internal `superset.initScript` template
|
||||
# (which runs `superset db upgrade`, `superset init`, admin creation, and examples).
|
||||
# Any customization placed here is silently ignored. See UPGRADING.md.
|
||||
# @default -- unused; kept for backwards-compatibility only
|
||||
# -- A Superset init script
|
||||
# @default -- a script to create admin user and initialize roles
|
||||
initscript: |-
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
@@ -44,17 +44,17 @@ dependencies = [
|
||||
# explicitly to keep fresh ``pip install apache-superset`` working
|
||||
# without the ``base.txt`` lock file (#40962).
|
||||
"cachetools>=6.2.1, <7",
|
||||
"celery>=5.6.3, <6.0.0",
|
||||
"celery>=5.3.6, <6.0.0",
|
||||
"click>=8.4.0",
|
||||
"click-option-group",
|
||||
"colorama",
|
||||
"flask-cors>=6.0.5, <7.0",
|
||||
"croniter>=6.2.2",
|
||||
"cron-descriptor",
|
||||
"cryptography>=49.0.0, <50.0.0",
|
||||
"cryptography>=48.0.0, <49.0.0",
|
||||
"deprecation>=2.1.0, <2.2.0",
|
||||
"flask>=2.2.5, <4.0.0",
|
||||
"flask-appbuilder>=5.2.2, <6.0.0",
|
||||
"flask-appbuilder>=5.2.1, <6.0.0",
|
||||
"flask-caching>=2.1.0, <3",
|
||||
"flask-compress>=1.13, <2.0",
|
||||
"flask-talisman>=1.0.0, <2.0",
|
||||
@@ -64,7 +64,7 @@ dependencies = [
|
||||
"flask-wtf>=1.3.0, <2.0",
|
||||
"geopy",
|
||||
"greenlet<=3.5.1, >=3.5.1",
|
||||
"gunicorn>=26.0.0, <27; sys_platform != 'win32'",
|
||||
"gunicorn>=25.3.0, <26; sys_platform != 'win32'",
|
||||
"hashids>=1.3.1, <2",
|
||||
# holidays>=0.45 required for security fix
|
||||
"holidays>=0.45, <1",
|
||||
@@ -77,7 +77,7 @@ dependencies = [
|
||||
# Flask-AppBuilder workaround. Tracking issue:
|
||||
# https://github.com/apache/superset/issues/33162
|
||||
"marshmallow>=3.0, <5",
|
||||
"marshmallow-union>=0.1.15.post1",
|
||||
"marshmallow-union>=0.1",
|
||||
"msgpack>=1.2.0, <1.3",
|
||||
"nh3>=0.3.5, <0.4",
|
||||
"numpy>1.23.5, <2.3",
|
||||
@@ -101,14 +101,13 @@ dependencies = [
|
||||
"pyyaml>=6.0.3, <7.0.0",
|
||||
"PyJWT>=2.4.0, <3.0",
|
||||
"redis>=5.0.0, <6.0",
|
||||
"rison>=2.0.1, <3.0",
|
||||
"selenium>=4.45.0, <5.0",
|
||||
"rison>=2.0.0, <3.0",
|
||||
"selenium>=4.44.0, <5.0",
|
||||
"shillelagh[gsheetsapi]>=1.4.4, <2.0",
|
||||
"sshtunnel>=0.4.0, <0.5",
|
||||
"simplejson>=4.1.1",
|
||||
"slack_sdk>=3.43.0, <4",
|
||||
"slack_sdk>=3.19.0, <4",
|
||||
"sqlalchemy>=1.4, <2",
|
||||
"sqlalchemy-continuum>=1.6.0, <2.0.0",
|
||||
"sqlalchemy-utils>=0.42.1, <0.43", # expanding lowerbound to work with pydoris
|
||||
"sqlglot>=30.8.0, <31",
|
||||
# newer pandas needs 0.9+
|
||||
@@ -128,7 +127,7 @@ aurora-data-api = ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"]
|
||||
bigquery = [
|
||||
"pandas-gbq>=0.19.1",
|
||||
"sqlalchemy-bigquery>=1.17.0",
|
||||
"google-cloud-bigquery>=3.42.1",
|
||||
"google-cloud-bigquery>=3.10.0",
|
||||
]
|
||||
clickhouse = ["clickhouse-connect>=1.1.1, <2.0"]
|
||||
cockroachdb = ["cockroachdb>=0.3.5, <0.4"]
|
||||
@@ -138,7 +137,7 @@ d1 = [
|
||||
"sqlalchemy-d1>=0.1.0",
|
||||
"dbapi-d1>=0.1.0",
|
||||
]
|
||||
databend = ["databend-sqlalchemy>=0.5.5, <1.0"]
|
||||
databend = ["databend-sqlalchemy>=0.3.2, <1.0"]
|
||||
databricks = [
|
||||
"databricks-sql-connector==4.2.6",
|
||||
"databricks-sqlalchemy==1.0.5",
|
||||
@@ -155,17 +154,17 @@ elasticsearch = ["elasticsearch-dbapi>=0.2.13, <0.3.0"]
|
||||
exasol = ["sqlalchemy-exasol>=2.4.0, <8.0"]
|
||||
excel = ["xlrd>=2.0.2, <2.1"]
|
||||
fastmcp = [
|
||||
"fastmcp>=3.4.2,<4.0",
|
||||
"fastmcp>=3.2.4,<4.0",
|
||||
# tiktoken backs the response-size-guard token estimator. Without
|
||||
# it, the middleware falls back to a coarser character-based
|
||||
# heuristic that under-counts JSON-heavy MCP responses.
|
||||
"tiktoken>=0.13.0,<1.0",
|
||||
]
|
||||
firebird = ["sqlalchemy-firebird>=0.8.0, <2.2"]
|
||||
firebird = ["sqlalchemy-firebird>=0.7.0, <2.2"]
|
||||
firebolt = ["firebolt-sqlalchemy>=1.0.0, <2"]
|
||||
gevent = ["gevent>=26.4.0"]
|
||||
gsheets = ["shillelagh[gsheetsapi]>=1.4.4, <2"]
|
||||
hana = ["hdbcli==2.28.21", "sqlalchemy_hana==3.0.3"]
|
||||
hana = ["hdbcli==2.28.21", "sqlalchemy_hana==0.4.0"]
|
||||
hive = [
|
||||
"pyhive[hive]>=0.6.5;python_version<'3.11'",
|
||||
"pyhive[hive_pure_sasl]>=0.7.0",
|
||||
@@ -173,23 +172,23 @@ hive = [
|
||||
"thrift>=0.23.0, <1.0.0",
|
||||
"thrift_sasl>=0.4.3, < 1.0.0",
|
||||
]
|
||||
impala = ["impyla>=0.24.0, <0.25"]
|
||||
impala = ["impyla>0.16.2, <0.23"]
|
||||
kusto = ["sqlalchemy-kusto>=3.1.2, <4"]
|
||||
kylin = ["kylinpy>=2.8.4, <2.9"]
|
||||
kylin = ["kylinpy>=2.8.1, <2.9"]
|
||||
mssql = ["pymssql>=2.3.13, <3"]
|
||||
# motherduck is an alias for duckdb - MotherDuck works via the duckdb driver
|
||||
motherduck = ["apache-superset[duckdb]"]
|
||||
mysql = ["mysqlclient>=2.2.8, <3"]
|
||||
mysql = ["mysqlclient>=2.1.0, <3"]
|
||||
ocient = [
|
||||
"sqlalchemy-ocient>=1.0.0, <4",
|
||||
"sqlalchemy-ocient>=1.0.0",
|
||||
"pyocient>=1.0.15, <4",
|
||||
"shapely",
|
||||
"geojson",
|
||||
]
|
||||
oracle = ["oracledb>=2.0.0, <5"]
|
||||
parseable = ["sqlalchemy-parseable>=0.1.6,<0.2.0"]
|
||||
parseable = ["sqlalchemy-parseable>=0.1.3,<0.2.0"]
|
||||
pinot = ["pinotdb>=5.0.0, <10.0.0"]
|
||||
playwright = ["playwright>=1.61.0, <2"]
|
||||
playwright = ["playwright>=1.60.0, <2"]
|
||||
postgres = ["psycopg2-binary==2.9.12"]
|
||||
presto = ["pyhive[presto]>=0.6.5"]
|
||||
trino = ["trino>=0.337.0"]
|
||||
@@ -197,8 +196,8 @@ prophet = ["prophet>=1.1.6, <2"]
|
||||
redshift = ["sqlalchemy-redshift>=0.8.1, <0.9"]
|
||||
risingwave = ["sqlalchemy-risingwave"]
|
||||
shillelagh = ["shillelagh[all]>=1.4.4, <2"]
|
||||
singlestore = ["sqlalchemy-singlestoredb>=1.2.1, <2"]
|
||||
snowflake = ["snowflake-sqlalchemy>=1.10.2, <2"]
|
||||
singlestore = ["sqlalchemy-singlestoredb>=1.1.1, <2"]
|
||||
snowflake = ["snowflake-sqlalchemy>=1.2.4, <2"]
|
||||
sqlite = ["syntaqlite>=0.1.0,<0.5.0"]
|
||||
spark = [
|
||||
"pyhive[hive]>=0.6.5;python_version<'3.11'",
|
||||
@@ -210,14 +209,14 @@ tdengine = [
|
||||
"taospy>=2.8.9",
|
||||
"taos-ws-py>=0.6.9"
|
||||
]
|
||||
teradata = ["teradatasql>=20.0.0.62"]
|
||||
teradata = ["teradatasql>=16.20.0.23"]
|
||||
thumbnails = [] # deprecated, will be removed in 7.0
|
||||
vertica = ["sqlalchemy-vertica-python>= 0.6.3, < 0.7"]
|
||||
netezza = ["nzalchemy>=11.0.2, < 11.2"]
|
||||
netezza = ["nzalchemy>=11.0.2"]
|
||||
starrocks = ["starrocks>=1.3.3, <2"]
|
||||
doris = ["pydoris>=1.0.0, <2.0.0"]
|
||||
oceanbase = ["oceanbase_py>=0.0.1.2"]
|
||||
ydb = ["ydb-sqlalchemy>=0.1.22", "ydb-sqlglot-plugin>=0.2.8"]
|
||||
ydb = ["ydb-sqlalchemy>=0.1.22", "ydb-sqlglot-plugin>=0.2.5"]
|
||||
development = [
|
||||
# no bounds for apache-superset-extensions-cli until a stable version
|
||||
"apache-superset-extensions-cli",
|
||||
@@ -236,7 +235,7 @@ development = [
|
||||
"pyfakefs",
|
||||
"pyinstrument>=5.1.2,<6",
|
||||
"pylint",
|
||||
"pytest<10.0.0", # cap below the next major until validated; the earlier <8 pin (current_app proxy timing) no longer reproduces
|
||||
"pytest<8.0.0", # hairy issue with pytest >=8 where current_app proxies are not set in time
|
||||
"pytest-asyncio",
|
||||
"pytest-cov",
|
||||
"pytest-mock",
|
||||
@@ -376,7 +375,6 @@ select = [
|
||||
|
||||
ignore = [
|
||||
"S101",
|
||||
"PT001", # pytest-fixture-incorrect-parentheses-style: different ruff versions disagree
|
||||
"PT006",
|
||||
"T201",
|
||||
"N999",
|
||||
|
||||
@@ -26,7 +26,7 @@ filelock>=3.20.3,<4.0.0
|
||||
brotli>=1.2.0,<2.0.0
|
||||
numexpr>=2.9.0
|
||||
# Security: CVE-2026-34073 (MEDIUM) - Improper Certificate Validation
|
||||
cryptography>=49.0.0,<50.0.0
|
||||
cryptography>=48.0.0,<49.0.0
|
||||
# Security: Snyk - XSS vulnerability in Mako templates
|
||||
mako>=1.3.11,<2.0.0
|
||||
# Security: CVE-2024-52338 (CRITICAL) - Deserialization of untrusted data in IPC/Parquet readers
|
||||
|
||||