-
Notifications
You must be signed in to change notification settings - Fork 14.3k
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(databases): test connection api #10723
Conversation
Codecov Report
@@ Coverage Diff @@
## master #10723 +/- ##
==========================================
+ Coverage 65.40% 65.56% +0.15%
==========================================
Files 802 803 +1
Lines 37872 37956 +84
Branches 3561 3561
==========================================
+ Hits 24770 24884 +114
+ Misses 12996 12966 -30
Partials 106 106
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
be08ed2
to
9794ebd
Compare
9794ebd
to
edc6c3f
Compare
b5e32ec
to
2493ae9
Compare
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.
A good bit of progress here! I've made a couple of recommendations on code structure. I think we could do a better job of centralizing the error handling coming out of SQLAlchemy to one location. We could potentially raise custom error classes that bring with them an associated response code and message - it looks like the language is the same between the endpoints, and that would DRY things up further. Happy to discuss the feedback if that would be helpful!
superset/databases/dao.py
Outdated
logger = logging.getLogger(__name__) | ||
|
||
|
||
class DatabaseDAO(BaseDAO): |
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.
This probably makes more sense as a Command rather than a DAO since it is more of a business operation.
superset/databases/dao.py
Outdated
# with the safe URI, we assume we should retrieve the decrypted URI to test | ||
# the connection. | ||
if db_name: | ||
existing_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.
This database lookup would be a good candidate for a DAO method.
superset/databases/dao.py
Outdated
uri = existing_database.sqlalchemy_uri_decrypted | ||
|
||
# this is the database instance that will be tested | ||
database = 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.
Here through line 70 could also potentially be a DAO method - something like build_db_for_connection_test
superset/databases/api.py
Outdated
encrypted_extra=json.dumps(request.json.get("encrypted_extra", {})), | ||
) | ||
return self.response(200, message="OK") | ||
except CertificateException as ex: |
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.
This breaks encapsulation a little bit. We're relying on SQLAlchemy errors to decide the response format. Ideally we'd capture these errors in the DAO or Command and transform them into a Superset-specific exception. That could allow us to group, for instance, the module loading errors at a lower level.
superset/databases/api.py
Outdated
return self.response(200, message="OK") | ||
except CertificateException as ex: | ||
logger.info("Certificate exception") | ||
return self.response(500, message=ex.message) |
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.
Since this is a connection test endpoint, let's return a 400 for this instead of a 500. We expect connection failures.
@@ -1162,7 +1133,7 @@ def testconn( # pylint: disable=too-many-return-statements,no-self-use | |||
logger.warning("Stopped an unsafe database connection") | |||
return json_error_response(_(str(ex)), 400) | |||
except Exception as ex: # pylint: disable=broad-except | |||
logger.error("Unexpected error %s", type(ex).__name__) | |||
logger.warning("Unexpected error %s", type(ex).__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.
👍
superset/databases/api.py
Outdated
except OperationalError: | ||
logger.warning("Connection failed") | ||
return self.response( | ||
500, message="Connection failed, please check your connection settings" |
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 we're missing the _()
function that will hook these messages up with their associated translations.
superset/databases/api.py
Outdated
except (NoSuchModuleError, ModuleNotFoundError): | ||
logger.info("Invalid driver") | ||
driver_name = make_url(uri).drivername | ||
message = "Could not load database driver: %s" % (driver_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 we could use an f-string here.
2493ae9
to
64317de
Compare
346385a
to
9a0e20f
Compare
c17e9f0
to
65ff87b
Compare
65ff87b
to
df82f00
Compare
df82f00
to
ebee553
Compare
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 - thanks for all the work on this!
7d185b1
to
20de464
Compare
LGTM!! |
* test connection api on databases * update test connection tests * update database api test and open api description * moved test connection to commands * update error message * fix isort * fix mypy * fix black * fix mypy pre commit
SUMMARY
/api/v1/database/test_connection
TEST PLAN
ADDITIONAL INFORMATION