Flask-SQLAlchemy integration
revmischa opened this issue · 3 comments
Trying to use this with Flask-SQLAlchemy:
# configure options for create_engine
engine_opts = app.config.get("SQLALCHEMY_ENGINE_OPTIONS", {})
if app.config.get("AURORA_DATA_API_ENABLED"):
# configure sqlalchemy-aurora-data-api
rds_secret_arn = app.config.get("RDS_SECRET_ARN")
aurora_cluster_arn = app.config.get("AURORA_CLUSTER_ARN")
db_name = app.config.get("DATABASE_NAME")
conn_url = f"postgresql+auroradataapi://:@/{db_name}"
app.config["DATABASE_URL"] = conn_url
# augment connect_args
connect_args = engine_opts.get("connect_args", {})
connect_args["aurora_cluster_arn"] = aurora_cluster_arn
connect_args["secret_arn"] = rds_secret_arn
engine_opts["connect_args"] = connect_args
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = engine_opts
Getting this error:
"errorMessage": "(psycopg2.ProgrammingError) invalid dsn: invalid connection option \"aurora_cluster_arn\"\n\n(Background on this error at: http://sqlalche.me/e/f405)",
"errorType": "ProgrammingError",
"stackTrace": [
" File \"/var/task/TEMPLATE/commands.py\", line 55, in init_handler\n from TEMPLATE.app import app\n",
" File \"/var/task/TEMPLATE/app.py\", line 4, in <module>\n app = create_app()\n",
" File \"/var/task/TEMPLATE/create_app.py\", line 36, in create_app\n configure_database(app)\n",
" File \"/var/task/TEMPLATE/create_app.py\", line 108, in configure_database\n raise ex\n",
" File \"/var/task/TEMPLATE/create_app.py\", line 105, in configure_database\n db.session.execute(\"SELECT 1\").scalar()\n",
" File \"/var/task/sqlalchemy/orm/scoping.py\", line 162, in do\n return getattr(self.registry(), name)(*args, **kwargs)\n",
" File \"/var/task/aws_xray_sdk/ext/sqlalchemy/util/decorators.py\", line 61, in wrapper\n res = func(*args, **kw)\n",
" File \"/var/task/sqlalchemy/orm/session.py\", line 1268, in execute\n return self._connection_for_bind(bind, close_with_result=True).execute(\n",
" File \"/var/task/sqlalchemy/orm/session.py\", line 1130, in _connection_for_bind\n engine, execution_options\n",
" File \"/var/task/sqlalchemy/orm/session.py\", line 431, in _connection_for_bind\n conn = bind._contextual_connect()\n",
" File \"/var/task/sqlalchemy/engine/base.py\", line 2242, in _contextual_connect\n self._wrap_pool_connect(self.pool.connect, None),\n",
" File \"/var/task/sqlalchemy/engine/base.py\", line 2280, in _wrap_pool_connect\n e, dialect, self\n",
" File \"/var/task/sqlalchemy/engine/base.py\", line 1547, in _handle_dbapi_exception_noconnection\n util.raise_from_cause(sqlalchemy_exception, exc_info)\n",
" File \"/var/task/sqlalchemy/util/compat.py\", line 398, in raise_from_cause\n reraise(type(exception), exception, tb=exc_tb, cause=cause)\n",
" File \"/var/task/sqlalchemy/util/compat.py\", line 152, in reraise\n raise value.with_traceback(tb)\n",
" File \"/var/task/sqlalchemy/engine/base.py\", line 2276, in _wrap_pool_connect\n return fn()\n",
" File \"/var/task/sqlalchemy/pool/base.py\", line 363, in connect\n return _ConnectionFairy._checkout(self)\n",
" File \"/var/task/sqlalchemy/pool/base.py\", line 760, in _checkout\n fairy = _ConnectionRecord.checkout(pool)\n",
" File \"/var/task/sqlalchemy/pool/base.py\", line 492, in checkout\n rec = pool._do_get()\n",
" File \"/var/task/sqlalchemy/pool/impl.py\", line 139, in _do_get\n self._dec_overflow()\n",
" File \"/var/task/sqlalchemy/util/langhelpers.py\", line 68, in __exit__\n compat.reraise(exc_type, exc_value, exc_tb)\n",
" File \"/var/task/sqlalchemy/util/compat.py\", line 153, in reraise\n raise value\n",
" File \"/var/task/sqlalchemy/pool/impl.py\", line 136, in _do_get\n return self._create_connection()\n",
" File \"/var/task/sqlalchemy/pool/base.py\", line 308, in _create_connection\n return _ConnectionRecord(self)\n",
" File \"/var/task/sqlalchemy/pool/base.py\", line 437, in __init__\n self.__connect(first_connect_check=True)\n",
" File \"/var/task/sqlalchemy/pool/base.py\", line 639, in __connect\n connection = pool._invoke_creator(self)\n",
" File \"/var/task/sqlalchemy/engine/strategies.py\", line 114, in connect\n return dialect.connect(*cargs, **cparams)\n",
" File \"/var/task/sqlalchemy/engine/default.py\", line 482, in connect\n return self.dbapi.connect(*cargs, **cparams)\n",
" File \"/opt/python/psycopg2/__init__.py\", line 125, in connect\n dsn = _ext.make_dsn(dsn, **kwargs)\n",
" File \"/opt/python/psycopg2/extensions.py\", line 174, in make_dsn\n parse_dsn(dsn)\n"
]
}
If I try configuring it purely using environment variables, after I perform my first query:
I verified that AURORA_CLUSTER_ARN
is arn:aws:secretsmanager:eu-west-1:11:cluster:TEMPLATE-x
in environment
(botocore.errorfactory.BadRequestException) An error occurred (BadRequestException) when calling the BeginTransaction operation: Invalid cluster arn: arn:aws:secretsmanager:eu-west-1:11:cluster:TEMPLATE-x\n[SQL: select version()]"
on AWS lambda
Your option names seem to be really confused. For example, you specify an option called DATABASE_URL
, but you should be specifying SQLALCHEMY_DATABASE_URI
. Your error message is coming from a psycopg2 driver, not from this package. And in the last error you pasted, the cluster ARN is somehow getting mangled with SQL - I have no idea where the SQL is coming from, but there is no place in this package that mixes the two.
The following snippet works for me:
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+auroradataapi://:@/' + os.environ["AURORA_DB_NAME"]
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {
"connect_args": {
"aurora_cluster_arn": "arn:aws:rds:us-east-1:NNNNNNNNNNNN:cluster:database-1",
"secret_arn": "arn:aws:secretsmanager:us-east-1:NNNNNNNNNNNN:secret:database-1"
}
}
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def __repr__(self):
return '<User %r>' % self.username
db.create_all()
My app converts DATABASE_URL to SQLALCHEMY_DATABASE_URI (for compatibility with platforms like Heroku). I don't know why psycopg2 is being used instead of this driver. The combining of SQL and cluster ARN definitely looks odd, I agree. I thought it may be a bug somewhere. I double-checked the connection string variable and it doesn't include the SQL.