Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Allow superset to be deployed under a prefixed URL #30134

Open
wants to merge 23 commits into
base: master
Choose a base branch
from

Conversation

martyngigg
Copy link
Contributor

@martyngigg martyngigg commented Sep 3, 2024

SUMMARY

Introduces changes in the front and backend to allow Superset to be deployed under a prefixed-URL path rather than the root of the domain.

The backend superset.app:create_app has been augemented with a new app_root argument that accepts a root path for the application. This is passed through the FLASK_APP environment variable or the flask --app cli argument. When the path is not / a middleware is created that intercepts paths and updates them to strip the app_root and forward them to the rest of the application. This was inspired by Application Dispatching.

The backend has also been refactored to avoid using hardcoded paths in redirects and instead uses Flask.url_for to construct all references.

The frontend has been updated to include the prefix in any resource links along with two new helper utilities, assetUrl & pathUtils, to help construct the paths. The SupersetClient has been updated to remove the unused baseUrl field and rename it as basePath such that the object can be initialized with the base path and calling any endpoints through this class can use the same relative link as before. QUESTION: Have I broken an API here?

Documentation has been added to the "Configuring Superset" pages that demonstrate how to use the new arugment.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

TESTING INSTRUCTIONS

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@rusackas
Copy link
Member

rusackas commented Sep 5, 2024

Thanks for tackling this... it's a popular request, no doubt about it. If you think it's relevant, we might also want to add an entry in the documentation somewhere.

@martyngigg
Copy link
Contributor Author

Thanks for tackling this... it's a popular request, no doubt about it. If you think it's relevant, we might also want to add an entry in the documentation somewhere.

Yes agreed I definitely need to add some documentation for how to use this. I wanted to wait until I was more confident that the general approach was acceptable before working on describing how to use it. In terms of a review as part of #26319 is there anything I need to do at the moment?

);
this.baseUrl = url.href.replace(/\/+$/, ''); // always strip trailing slash
this.basePath = basePath.replace(/\/+$/, ''); // always strip trailing slash

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data High

This
regular expression
that depends on
library input
may run slow on strings with many repetitions of '/'.
This
regular expression
that depends on
library input
may run slow on strings with many repetitions of '/'.
@mistercrunch
Copy link
Member

mistercrunch commented Sep 19, 2024

I think this may be quite an undertaking and might have to be tackled in phases. Would love to see this done :)

I remember giving it a shot early on in the project at least once, and never wrapped up the work. My main advice would be to avoid taking in side mission or bigger refactor while tackling this.

@@ -17,19 +17,23 @@
#
set -e

# zstd exe is required by simple-zstd package
apt-get update
apt-get install -y zstd
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a recent fix in master for this

@ravikantkml
Copy link

Thanks for tackling this... it's a popular request, no doubt about it. If you think it's relevant, we might also want to add an entry in the documentation somewhere.

Yes agreed I definitely need to add some documentation for how to use this. I wanted to wait until I was more confident that the general approach was acceptable before working on describing how to use it. In terms of a review as part of #26319 is there anything I need to do at the moment?

Thanks for these changes.
Can you please mention values for BASE_PATH and ASSET_BASE_URL. Just wanted to check these changes with superset and nginx.

@kasper-rutten
Copy link

For what it's worth, we've been running this fork to serve superset on a path prefix in a Kubernetes(K3S) + traefik context without any problems so far. Though testing has been limited.

Thanks for the work so far

@martyngigg martyngigg force-pushed the allow_prefixed_paths branch from 93d66c7 to 09a05b3 Compare October 15, 2024 14:23
@github-actions github-actions bot added the doc Namespace | Anything related to documentation label Oct 15, 2024
@martyngigg martyngigg force-pushed the allow_prefixed_paths branch from 09a05b3 to fe3b01a Compare October 15, 2024 14:51
@martyngigg
Copy link
Contributor Author

Thanks for tackling this... it's a popular request, no doubt about it. If you think it's relevant, we might also want to add an entry in the documentation somewhere.

Yes agreed I definitely need to add some documentation for how to use this. I wanted to wait until I was more confident that the general approach was acceptable before working on describing how to use it. In terms of a review as part of #26319 is there anything I need to do at the moment?

Thanks for these changes. Can you please mention values for BASE_PATH and ASSET_BASE_URL. Just wanted to check these changes with superset and nginx.

Sorry for the delay in replying to this. I've had zero time to spend on this lately.

The latest commits rebase on the current master and I have also added some documentation to the configuring superset pages that describe the new variables with an example nginx.conf. Does that help?

@martyngigg
Copy link
Contributor Author

@rusackas I think this is ready for review but in terms of it being related to SIP-112 is that the right thing to do in terms of the process?

@rusackas
Copy link
Member

If you think it's ready for review, I'd say you can go ahead and move it from Draft to "Ready for Review" - though it looks like CI might need a little more love still.

As for the SIP, since @sfirke reopened the GitHub issue, I set the SIP itself back to "pre-discussion" state for its official consensus. Did you want to re-kindle that pre-existing SIP, or would it be easier to open a new one? I'm happy to help you carry that SIP through to fruition if you'd like. Feel free to DM me on slack if it's easier.

@ascendlin
Copy link

When clicking on the user list or role list, and then clicking on datasets, a 404 error appears.

@ravikantkml
Copy link

Thanks for tackling this... it's a popular request, no doubt about it. If you think it's relevant, we might also want to add an entry in the documentation somewhere.

Yes agreed I definitely need to add some documentation for how to use this. I wanted to wait until I was more confident that the general approach was acceptable before working on describing how to use it. In terms of a review as part of #26319 is there anything I need to do at the moment?

Thanks for these changes. Can you please mention values for BASE_PATH and ASSET_BASE_URL. Just wanted to check these changes with superset and nginx.

Sorry for the delay in replying to this. I've had zero time to spend on this lately.

The latest commits rebase on the current master and I have also added some documentation to the configuring superset pages that describe the new variables with an example nginx.conf. Does that help?

Thanks a lot for the response.
We tried the changes as recommended and observed that most of the things are working when we specify prefix. However there are few things where prefix is not applied correctly as shown in the image below (chart menu has prefix applied correctly)
image

Also dashboard menu items export to PDF/image not working (Dashboard -> Download -> Export to PDF/Download as Image)

@ravikantkml
Copy link

Thanks for tackling this... it's a popular request, no doubt about it. If you think it's relevant, we might also want to add an entry in the documentation somewhere.

Yes agreed I definitely need to add some documentation for how to use this. I wanted to wait until I was more confident that the general approach was acceptable before working on describing how to use it. In terms of a review as part of #26319 is there anything I need to do at the moment?

Thanks for these changes. Can you please mention values for BASE_PATH and ASSET_BASE_URL. Just wanted to check these changes with superset and nginx.

Sorry for the delay in replying to this. I've had zero time to spend on this lately.
The latest commits rebase on the current master and I have also added some documentation to the configuring superset pages that describe the new variables with an example nginx.conf. Does that help?

Thanks a lot for the response. We tried the changes as recommended and observed that most of the things are working when we specify prefix. However there are few things where prefix is not applied correctly as shown in the image below (chart menu has prefix applied correctly) image

Also dashboard menu items export to PDF/image not working (Dashboard -> Download -> Export to PDF/Download as Image)

I tried to fix above issue of missing prefixes in top-level menu. Please check this PR 2

@Dinesh-4320
Copy link

The solution really works. Solved a long term issue in our deployment behind proxies. Hoping to get merged soon with official code base

@harri2012
Copy link

Very good, looking forward to merging the code soon

@watercraft
Copy link

For whom it may concern, I'm testing with a port of this work to 3.1.1rc1 available from watercraft:superset branch prefix

@jeanpommier
Copy link

Hi,
Good job there, thank you very much for tackling this. I have just discovered that Superset did not support that and was feeling disappointed.

I can see this PR is still flagged as DRAFT. What's left to do to get it "Ready for Review" ?

@martyngigg do you need help in completing this PR ? I'm quite a superset newbie, but I'm willing to provide some help if necessary to get this merged.

Docker version of superset_config sets ENABLE_PROXY_FIX=True
if BASE_PATH not empty.
Also simplifies Nginx server block so it no longer
needs modifying when a prefix is set or not - simply
set the BASE_PATH/ASSET_BASE_URL environment variables
when running docker compose and it will take case of the
rest.
If not an empty string, a new middleware class is attached
to the wsgi_app callable that intercepts each request and
transforms the SCRIPT_NAME & PATH_INFO
variables in the request environment so that the rest of
the code still sees non-prefixed paths yet the application
itself appears to sit on a common subpath.

A new environment variable SUPERSET_APP_ROOT has been
introduced into the docker config to control the value
of the application root.
Adjusted Flask app templates to include the static_assets_prefix
and webpack build dir while rendering. This removes the need to rebuild
the frontend in order to Superset it at a different application prefix.
@martyngigg martyngigg force-pushed the allow_prefixed_paths branch from 9b77478 to e0eb2ed Compare January 20, 2025 17:37
@martyngigg martyngigg marked this pull request as ready for review January 20, 2025 17:38
Copy link

korbit-ai bot commented Jan 20, 2025

Korbit doesn't automatically review large (500+ lines changed) pull requests such as this one. If you want me to review anyway, use /korbit-review.

@dosubot dosubot bot added change:backend Requires changing the backend change:frontend Requires changing the frontend labels Jan 20, 2025
Comment on lines +158 to +160
window.location.href = ensureBasePath(
`/superset/dashboard/${resp.json.result.id}/`,
);

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -193,7 +194,7 @@
),
buttonStyle: 'tertiary',
onClick: () => {
window.location.assign('/chart/add');
window.location.assign(ensureBasePath('/chart/add'));

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -196,19 +197,20 @@
),
buttonStyle: 'tertiary',
onClick: () => {
window.location.assign('/dashboard/new');
window.location.assign(ensureBasePath('/dashboard/new'));

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -171,7 +173,7 @@
<Button
buttonStyle="primary"
onClick={() => {
window.location.href = favRedirects[tableName];
window.location.href = ensureBasePath(favRedirects[tableName]);

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -313,11 +314,11 @@
>
{isFrontendRoute(window.location.pathname) ? (
<GenericLink className="navbar-brand" to={brand.path}>
<img src={brand.icon} alt={brand.alt} />
<img src={assetUrl(brand.icon)} alt={brand.alt} />

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -460,7 +461,7 @@
{menu.label}
</Link>
) : (
<a href={menu.url}>
<a href={ensureBasePath(menu.url || '')}>

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -495,7 +496,9 @@
{isFrontendRoute(child.url) ? (
<Link to={child.url || ''}>{menuItemDisplay}</Link>
) : (
<a href={child.url}>{menuItemDisplay}</a>
<a href={ensureBasePath(child.url || '')}>

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -264,7 +266,7 @@
name: t('View All »'),
buttonStyle: 'link',
onClick: () => {
window.location.href = '/savedqueryview/list';
window.location.href = ensureBasePath('/savedqueryview/list');

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -277,7 +278,7 @@
};

const onLayerAdd = (id?: number) => {
window.location.href = `/annotationlayer/${id}/annotation`;
window.location.href = ensureBasePath(`/annotationlayer/${id}/annotation`);

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
@@ -682,7 +683,7 @@
),
buttonStyle: 'primary',
onClick: () => {
window.location.assign('/dashboard/new');
window.location.assign(ensureBasePath('/dashboard/new'));

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Related to the REST API change:backend Requires changing the backend change:frontend Requires changing the frontend doc Namespace | Anything related to documentation packages review:draft size/XL
Projects
None yet
Development

Successfully merging this pull request may close these issues.