-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
feat: create function for get_sqla_engine with context #21790
Conversation
Codecov Report
@@ Coverage Diff @@
## master #21790 +/- ##
==========================================
+ Coverage 66.18% 67.06% +0.87%
==========================================
Files 1805 1805
Lines 69066 69416 +350
Branches 7369 7369
==========================================
+ Hits 45712 46554 +842
+ Misses 21448 20955 -493
- Partials 1906 1907 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
…tunnel-refactor-get-sqla-engine
…tunnel-refactor-get-sqla-engine
…tunnel-refactor-get-sqla-engine
d53079d
to
03029dd
Compare
03029dd
to
c006017
Compare
@@ -362,6 +362,18 @@ def get_effective_user(self, object_url: URL) -> Optional[str]: | |||
else None | |||
) | |||
|
|||
@contextmanager | |||
def get_sqla_engine_with_context( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the difference between having this new get_sqla_engine_with_context
with the decorator VS using it in our existing get_sqla_engine
? I Mean, couldn't we just use the existing one and make use or not of the new functionality the decorator brings when needed? or would that mean changing a ton of places where the get_sqla_engine
is being used right now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now there's no difference, but Hugh is planning to add support for SSH tunneling, which would require a setup phase before the engine is created, and a teardown after. In order for the SSH tunnel to work everywhere we will need to replace all existing calls with the new context manager.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh ok ok, makes sense then 😎 thanks!
db = make_url(model.get_sqla_engine().url).database | ||
self.assertEqual("prod", db) | ||
with model.get_sqla_engine_with_context() as engine: | ||
db = make_url(engine.url).database |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see we have this make_url_safe
here: superset/databases/utils.py
, would that serve the same purpose? If so, can we change to that one or must we keep using this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make_url_safe
prevents password from showing up in the logs when make_url
fails for some reason. It should always be used in production, but in the tests it's fine to use make_url
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to know 👍 Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the plan for modifying the files in superset/
?
perm_data = ROLE_TABLES_PERM_DATA.copy() | ||
perm_data["database"][0]["schema"][0]["name"] = schema | ||
|
||
response = self.client.post( | ||
"/superset/override_role_permissions/", | ||
data=json.dumps(perm_data), | ||
content_type="application/json", | ||
) | ||
self.assertEqual(201, response.status_code) | ||
response = self.client.post( | ||
"/superset/override_role_permissions/", | ||
data=json.dumps(perm_data), | ||
content_type="application/json", | ||
) | ||
self.assertEqual(201, response.status_code) | ||
|
||
updated_override_me = security_manager.find_role("override_me") | ||
self.assertEqual(1, len(updated_override_me.permissions)) | ||
birth_names = self.get_table(name="birth_names") | ||
self.assertEqual( | ||
birth_names.perm, updated_override_me.permissions[0].view_menu.name | ||
) | ||
self.assertEqual( | ||
"datasource_access", updated_override_me.permissions[0].permission.name | ||
) | ||
updated_override_me = security_manager.find_role("override_me") | ||
self.assertEqual(1, len(updated_override_me.permissions)) | ||
birth_names = self.get_table(name="birth_names") | ||
self.assertEqual( | ||
birth_names.perm, updated_override_me.permissions[0].view_menu.name | ||
) | ||
self.assertEqual( | ||
"datasource_access", updated_override_me.permissions[0].permission.name | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this doesn't have to be inside the context manager.
override_me = security_manager.find_role("override_me") | ||
override_me.permissions.append( | ||
security_manager.find_permission_view_menu( | ||
view_menu_name=self.get_table(name="energy_usage").perm, | ||
permission_name="datasource_access", | ||
) | ||
) | ||
) | ||
db.session.flush() | ||
db.session.flush() | ||
|
||
perm_data = ROLE_TABLES_PERM_DATA.copy() | ||
perm_data["database"][0]["schema"][0]["name"] = schema | ||
perm_data = ROLE_TABLES_PERM_DATA.copy() | ||
perm_data["database"][0]["schema"][0]["name"] = schema | ||
|
||
response = self.client.post( | ||
"/superset/override_role_permissions/", | ||
data=json.dumps(perm_data), | ||
content_type="application/json", | ||
) | ||
self.assertEqual(201, response.status_code) | ||
updated_override_me = security_manager.find_role("override_me") | ||
self.assertEqual(1, len(updated_override_me.permissions)) | ||
birth_names = self.get_table(name="birth_names") | ||
self.assertEqual( | ||
birth_names.perm, updated_override_me.permissions[0].view_menu.name | ||
) | ||
self.assertEqual( | ||
"datasource_access", updated_override_me.permissions[0].permission.name | ||
) | ||
response = self.client.post( | ||
"/superset/override_role_permissions/", | ||
data=json.dumps(perm_data), | ||
content_type="application/json", | ||
) | ||
self.assertEqual(201, response.status_code) | ||
updated_override_me = security_manager.find_role("override_me") | ||
self.assertEqual(1, len(updated_override_me.permissions)) | ||
birth_names = self.get_table(name="birth_names") | ||
self.assertEqual( | ||
birth_names.perm, updated_override_me.permissions[0].view_menu.name | ||
) | ||
self.assertEqual( | ||
"datasource_access", updated_override_me.permissions[0].permission.name | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
@@ -362,6 +362,18 @@ def get_effective_user(self, object_url: URL) -> Optional[str]: | |||
else None | |||
) | |||
|
|||
@contextmanager | |||
def get_sqla_engine_with_context( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually I think we want to rename this to get_sqla_engine
, since we want this to be the one and only way to create an engine.
with database.get_sqla_engine_with_context() as engine: | ||
engine.execute("CREATE TABLE test_table AS SELECT 1 as first, 2 as second") | ||
engine.execute("INSERT INTO test_table (first, second) VALUES (1, 2)") | ||
engine.execute("INSERT INTO test_table (first, second) VALUES (3, 4)") | ||
|
||
yield db.session | ||
database.get_sqla_engine().execute("DROP TABLE test_table") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too?
I initially wanted to take incremental approach with 1 first to verify the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
SUMMARY
First step in allowing enabling ssh tunneling by allowing the
get_sqla_engine
function to be a context manager. This will allow us to add logic before and after yielding the engine for spinning up and tearing down the tunnel on each connection.BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
TESTING INSTRUCTIONS
ADDITIONAL INFORMATION