make_full_schema.sh 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #!/usr/bin/env bash
  2. #
  3. # This script generates SQL files for creating a brand new Synapse DB with the latest
  4. # schema, on both SQLite3 and Postgres.
  5. #
  6. # It does so by having Synapse generate an up-to-date SQLite DB, then running
  7. # synapse_port_db to convert it to Postgres. It then dumps the contents of both.
  8. export PGHOST="localhost"
  9. POSTGRES_DB_NAME="synapse_full_schema.$$"
  10. SQLITE_SCHEMA_FILE="schema.sql.sqlite"
  11. SQLITE_ROWS_FILE="rows.sql.sqlite"
  12. POSTGRES_SCHEMA_FILE="full.sql.postgres"
  13. POSTGRES_ROWS_FILE="rows.sql.postgres"
  14. REQUIRED_DEPS=("matrix-synapse" "psycopg2")
  15. usage() {
  16. echo
  17. echo "Usage: $0 -p <postgres_username> -o <path> [-c] [-n] [-h]"
  18. echo
  19. echo "-p <postgres_username>"
  20. echo " Username to connect to local postgres instance. The password will be requested"
  21. echo " during script execution."
  22. echo "-c"
  23. echo " CI mode. Prints every command that the script runs."
  24. echo "-o <path>"
  25. echo " Directory to output full schema files to."
  26. echo "-h"
  27. echo " Display this help text."
  28. }
  29. while getopts "p:co:h" opt; do
  30. case $opt in
  31. p)
  32. export PGUSER=$OPTARG
  33. ;;
  34. c)
  35. # Print all commands that are being executed
  36. set -x
  37. ;;
  38. o)
  39. command -v realpath > /dev/null || (echo "The -o flag requires the 'realpath' binary to be installed" && exit 1)
  40. OUTPUT_DIR="$(realpath "$OPTARG")"
  41. ;;
  42. h)
  43. usage
  44. exit
  45. ;;
  46. \?)
  47. echo "ERROR: Invalid option: -$OPTARG" >&2
  48. usage
  49. exit
  50. ;;
  51. esac
  52. done
  53. # Check that required dependencies are installed
  54. unsatisfied_requirements=()
  55. for dep in "${REQUIRED_DEPS[@]}"; do
  56. pip show "$dep" --quiet || unsatisfied_requirements+=("$dep")
  57. done
  58. if [ ${#unsatisfied_requirements} -ne 0 ]; then
  59. echo "Please install the following python packages: ${unsatisfied_requirements[*]}"
  60. exit 1
  61. fi
  62. if [ -z "$PGUSER" ]; then
  63. echo "No postgres username supplied"
  64. usage
  65. exit 1
  66. fi
  67. if [ -z "$OUTPUT_DIR" ]; then
  68. echo "No output directory supplied"
  69. usage
  70. exit 1
  71. fi
  72. # Create the output directory if it doesn't exist
  73. mkdir -p "$OUTPUT_DIR"
  74. read -rsp "Postgres password for '$PGUSER': " PGPASSWORD
  75. echo ""
  76. export PGPASSWORD
  77. # Exit immediately if a command fails
  78. set -e
  79. # cd to root of the synapse directory
  80. cd "$(dirname "$0")/.."
  81. # Create temporary SQLite and Postgres homeserver db configs and key file
  82. TMPDIR=$(mktemp -d)
  83. KEY_FILE=$TMPDIR/test.signing.key # default Synapse signing key path
  84. SQLITE_CONFIG=$TMPDIR/sqlite.conf
  85. SQLITE_DB=$TMPDIR/homeserver.db
  86. POSTGRES_CONFIG=$TMPDIR/postgres.conf
  87. # Ensure these files are delete on script exit
  88. # TODO: the trap should also drop the temp postgres DB
  89. trap 'rm -rf $TMPDIR' EXIT
  90. cat > "$SQLITE_CONFIG" <<EOF
  91. server_name: "test"
  92. signing_key_path: "$KEY_FILE"
  93. macaroon_secret_key: "abcde"
  94. report_stats: false
  95. database:
  96. name: "sqlite3"
  97. args:
  98. database: "$SQLITE_DB"
  99. # Suppress the key server warning.
  100. trusted_key_servers: []
  101. EOF
  102. cat > "$POSTGRES_CONFIG" <<EOF
  103. server_name: "test"
  104. signing_key_path: "$KEY_FILE"
  105. macaroon_secret_key: "abcde"
  106. report_stats: false
  107. database:
  108. name: "psycopg2"
  109. args:
  110. user: "$PGUSER"
  111. host: "$PGHOST"
  112. password: "$PGPASSWORD"
  113. database: "$POSTGRES_DB_NAME"
  114. # Suppress the key server warning.
  115. trusted_key_servers: []
  116. EOF
  117. # Generate the server's signing key.
  118. echo "Generating SQLite3 db schema..."
  119. python -m synapse.app.homeserver --generate-keys -c "$SQLITE_CONFIG"
  120. # Make sure the SQLite3 database is using the latest schema and has no pending background update.
  121. echo "Running db background jobs..."
  122. synapse/_scripts/update_synapse_database.py --database-config "$SQLITE_CONFIG" --run-background-updates
  123. # Create the PostgreSQL database.
  124. echo "Creating postgres database..."
  125. createdb --lc-collate=C --lc-ctype=C --template=template0 "$POSTGRES_DB_NAME"
  126. echo "Running db background jobs..."
  127. synapse/_scripts/update_synapse_database.py --database-config "$POSTGRES_CONFIG" --run-background-updates
  128. # Delete schema_version, applied_schema_deltas and applied_module_schemas tables
  129. # Also delete any shadow tables from fts4
  130. echo "Dropping unwanted db tables..."
  131. SQL="
  132. DROP TABLE schema_version;
  133. DROP TABLE applied_schema_deltas;
  134. DROP TABLE applied_module_schemas;
  135. "
  136. sqlite3 "$SQLITE_DB" <<< "$SQL"
  137. psql "$POSTGRES_DB_NAME" -w <<< "$SQL"
  138. echo "Dumping SQLite3 schema to '$OUTPUT_DIR/$SQLITE_SCHEMA_FILE' and '$OUTPUT_DIR/$SQLITE_ROWS_FILE'..."
  139. sqlite3 "$SQLITE_DB" ".schema --indent" > "$OUTPUT_DIR/$SQLITE_SCHEMA_FILE"
  140. sqlite3 "$SQLITE_DB" ".dump --data-only --nosys" > "$OUTPUT_DIR/$SQLITE_ROWS_FILE"
  141. echo "Dumping Postgres schema to '$OUTPUT_DIR/$POSTGRES_SCHEMA_FILE' and '$OUTPUT_DIR/$POSTGRES_ROWS_FILE'..."
  142. pg_dump --format=plain --schema-only --no-tablespaces --no-acl --no-owner "$POSTGRES_DB_NAME" | sed -e '/^$/d' -e '/^--/d' -e 's/public\.//g' -e '/^SET /d' -e '/^SELECT /d' > "$OUTPUT_DIR/$POSTGRES_SCHEMA_FILE"
  143. pg_dump --format=plain --data-only --inserts --no-tablespaces --no-acl --no-owner "$POSTGRES_DB_NAME" | sed -e '/^$/d' -e '/^--/d' -e 's/public\.//g' -e '/^SET /d' -e '/^SELECT /d' > "$OUTPUT_DIR/$POSTGRES_ROWS_FILE"
  144. echo "Cleaning up temporary Postgres database..."
  145. dropdb $POSTGRES_DB_NAME
  146. echo "Done! Files dumped to: $OUTPUT_DIR"