From 834d68a47e0649dc9b3cb3ff640bb56d171aeec9 Mon Sep 17 00:00:00 2001 From: Austin Alvarado Date: Wed, 22 Mar 2023 10:07:10 -0600 Subject: [PATCH] docs: fix DB migration, add sqlite migration helper script --- docs/database_migration.md | 24 +++++++++++++++++++----- scripts/sqlite_dump_commands.sh | 9 +++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 scripts/sqlite_dump_commands.sh diff --git a/docs/database_migration.md b/docs/database_migration.md index c595938..cf29b81 100644 --- a/docs/database_migration.md +++ b/docs/database_migration.md @@ -28,13 +28,14 @@ If it succeeds, you can proceed to the next step. ## Create a dump of existing data -We want to dump (almost) all existing values to some file - the exception being the `metadata` table. Be sure to stop/pause LLDAP during this step, as some +We want to dump (almost) all existing values to some file - the exception being the `metadata` table (and sometimes +the `sqlite_sequence` table, when it exists). Be sure to stop/pause LLDAP during this step, as some databases (SQLite in this example) will give an error if LLDAP is in the middle of a write. The dump should consist just INSERT statements. There are various ways to do this, but a simple enough way is filtering a -whole database dump. For example: +whole database dump. This repo contains [a script](/scripts/sqlite_dump_commands.sh) to generate SQLite commands for creating an appropriate dump: ``` -sqlite3 /path/to/lldap/config/users.db .dump | grep "^INSERT" | grep -v "^INSERT INTO metadata" > /path/to/dump.sql +./sqlite_dump_commands.sh | sqlite3 /path/to/lldap/config/users.db > /path/to/dump.sql ``` ## Sanitize data @@ -56,12 +57,25 @@ sed -i -r -e "s/X'([[:xdigit:]]+'[^'])/'\\\x\\1/g" \ ### To MySQL -MySQL mostly cooperates, but it gets some errors if you don't escape the `groups` table. Run the +MySQL mostly cooperates, but it gets some errors if you don't escape the `groups` table. It also uses +backticks to escape table name instead of quotes. Run the following command to wrap all table names in backticks for good measure, and wrap the inserts in a transaction: ``` -sed -i -r -e 's/^INSERT INTO ([a-zA-Z0-9_]+) /INSERT INTO `\1` /' \ +sed -i -r -e 's/^INSERT INTO "?([a-zA-Z0-9_]+)"?/INSERT INTO `\1`/' \ +-e '1s/^/START TRANSACTION;\n/' \ +-e '$aCOMMIT;' /path/to/dump.sql +``` + +### To MariaDB + +While MariaDB is supposed to be identical to MySQL, it doesn't support timezone offsets on DATETIME +strings. Use the following command to remove those and perform the additional MySQL sanitization: + +``` +sed -i -r -e "s/([^']'[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{9})\+00:00'([^'])/\1'\2/g" \ +-e 's/^INSERT INTO "?([a-zA-Z0-9_]+)"?/INSERT INTO `\1`/' \ -e '1s/^/START TRANSACTION;\n/' \ -e '$aCOMMIT;' /path/to/dump.sql ``` diff --git a/scripts/sqlite_dump_commands.sh b/scripts/sqlite_dump_commands.sh new file mode 100644 index 0000000..4b5778e --- /dev/null +++ b/scripts/sqlite_dump_commands.sh @@ -0,0 +1,9 @@ +#! /bin/bash + +tables=("users" "groups" "memberships" "jwt_refresh_storage" "jwt_storage" "password_reset_tokens") +echo ".header on" + +for table in ${tables[@]}; do + echo ".mode insert $table" + echo "select * from $table;" +done \ No newline at end of file