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

feat(jans-pycloudlib): detect JSON data format #10009

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions jans-pycloudlib/jans/pycloudlib/persistence/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from sqlalchemy import event
from ldif import LDIFParser
from ldap3.utils import dn as dnutils
from pymysql.err import ProgrammingError

from jans.pycloudlib.utils import encode_text
from jans.pycloudlib.utils import safe_render
Expand Down Expand Up @@ -265,6 +266,7 @@ def engine(self) -> Engine:

if self.dialect == "mysql":
event.listen(self._engine, "first_connect", set_mysql_strict_mode)
event.listen(self._engine, "first_connect", maybe_simple_json)

# initialized engine
return self._engine
Expand Down Expand Up @@ -654,3 +656,46 @@ def sync_sql_password(manager: Manager) -> None:
def get_sql_password(manager: Manager | None = None):
password_file = get_sql_password_file()
return get_password_from_file(password_file)


def maybe_simple_json(dbapi_connection, connection_record):
if "MYSQL_SIMPLE_JSON" in os.environ or os.path.isfile("/tmp/mysql_simple_json.sh"): # nosec: B108
return

logger.info("Checking for JSON data format to determine MYSQL_SIMPLE_JSON env var")

is_simple_json = True
cursor = dbapi_connection.cursor()

try:
# extract the value of `jansAppConf.jansSmtpConf` of jans-auth to check the data format, whether it's using legacy `{"v": []}` or new `[]` format;
# note that we choose `jansAppConf.jansSmtpConf` column for several reasons:
#
# - it's one of few JSON columns available in the table alongside `jansDbAuth` (deprecated) and `jansEmail`
# - the column is likely will not be removed/changed
cursor.execute("SELECT jansSmtpConf FROM jansAppConf WHERE doc_id='jans-auth';")

if result := cursor.fetchone():
for value in result:
if isinstance(json.loads(value), dict):
is_simple_json = False
break
except ProgrammingError as exc:
# missing table or column will raise ProgrammingError
logger.warning(f"Unable to detect JSON data format automatically; reason={exc.args[1]}; fallback to default value")
finally:
# cleanup resource
cursor.close()

# configure env var
env_value = str(is_simple_json).lower()

logger.info(f"Configuring env var MYSQL_SIMPLE_JSON={env_value}")

# set env var for current python process
os.environ["MYSQL_SIMPLE_JSON"] = env_value

# write the source file since we cannot set env var directly to parent process
# the source file need to be executed externally
with open("/tmp/mysql_simple_json.sh", "w") as f: # nosec: B108
f.write(f"export MYSQL_SIMPLE_JSON={env_value}")
Loading