taler-merchant-dbconfig (5348B)
1 #!/bin/bash 2 # This file is part of GNU TALER. 3 # Copyright (C) 2023 Taler Systems SA 4 # 5 # TALER is free software; you can redistribute it and/or modify it under the 6 # terms of the GNU Lesser General Public License as published by the Free Software 7 # Foundation; either version 2.1, or (at your option) any later version. 8 # 9 # TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 12 # 13 # You should have received a copy of the GNU Lesser General Public License along with 14 # TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 # 16 # @author Christian Grothoff 17 # 18 # 19 # Error checking on 20 set -eu 21 22 RESET_DB=0 23 SKIP_DBINIT=0 24 DBUSER="taler-merchant-httpd" 25 CFGFILE="/etc/taler-merchant/taler-merchant.conf" 26 27 # Parse command-line options 28 while getopts 'c:hrsu:' OPTION; do 29 case "$OPTION" in 30 c) 31 CFGFILE="$OPTARG" 32 ;; 33 h) 34 echo 'Supported options:' 35 echo " -c FILENAME -- use configuration FILENAME (default: $CFGFILE)" 36 echo " -h -- print this help text" 37 echo " -r -- reset database (dangerous)" 38 echo " -s -- skip database initialization" 39 echo " -u USER -- taler-merchant to be run by USER (default: $DBUSER)" 40 exit 0 41 ;; 42 r) 43 RESET_DB="1" 44 ;; 45 s) 46 SKIP_DBINIT="1" 47 ;; 48 u) 49 DBUSER="$OPTARG" 50 ;; 51 ?) 52 echo 'Invalid command-line option; use -h for help.' >&2 53 exit 1 54 ;; 55 esac 56 done 57 58 if ! id postgres >/dev/null; then 59 echo "Could not find 'postgres' user. Please install Postgresql first" 60 exit 1 61 fi 62 63 if [ "$(id -u)" -ne 0 ]; then 64 echo "This script must be run as root" 65 exit 1 66 fi 67 68 if [ 0 = "$SKIP_DBINIT" ]; then 69 if ! command -v taler-merchant-dbinit >/dev/null 2>&1; then 70 echo "Required 'taler-merchant-dbinit' not found in PATH." >&2 71 echo "Install package 'taler-merchant' (same suite as libgnunet)." >&2 72 exit 1 73 fi 74 DBINIT=$(command -v taler-merchant-dbinit) 75 # Binary may exist but fail to load (e.g. missing libgnunet). 76 DBINIT_ERR=$(mktemp) 77 if ! "$DBINIT" -v >"$DBINIT_ERR" 2>&1; then 78 echo "Required 'taler-merchant-dbinit' is installed ($DBINIT) but failed to run:" >&2 79 sed 's/^/ /' "$DBINIT_ERR" >&2 || true 80 rm -f "$DBINIT_ERR" 81 echo "Common cause: missing or mismatched shared libraries (often libgnunet)." >&2 82 echo "Try: ldd \"$DBINIT\" | grep 'not found'" >&2 83 echo "Install matching libgnunet packages for this Debian suite, then re-run." >&2 84 exit 1 85 fi 86 rm -f "$DBINIT_ERR" 87 fi 88 89 if ! id "$DBUSER" >/dev/null; then 90 echo "Could not find '$DBUSER' user. Please set it up first" 91 exit 1 92 fi 93 94 # Resolve and validate the target before making any database changes. The 95 # provisioning commands below administer the default local PostgreSQL cluster. 96 DBPATH=$(taler-merchant-config \ 97 -c "$CFGFILE" \ 98 -s merchantdb-postgres \ 99 -o CONFIG) 100 101 if [[ ! "$DBPATH" =~ ^postgres:///([a-zA-Z0-9_.-]+)$ ]]; then 102 echo "Database provisioning requires postgres:///NAME (letters, digits, _, . or -)." >&2 103 echo "For other connections, provision the database separately and run taler-merchant-dbinit -c $CFGFILE as the database owner." >&2 104 exit 1 105 fi 106 DBNAME="${BASH_REMATCH[1]}" 107 108 # Query the catalogs explicitly: failure to connect is not evidence that a 109 # role or database is absent. -X ignores psqlrc, and SQL errors must be fatal. 110 ROLE_EXISTS=$(sudo -i -u postgres psql -X -At \ 111 --set=ON_ERROR_STOP=1 --dbname=postgres --set=dbuser="$DBUSER" <<'EOF' 112 SELECT EXISTS (SELECT FROM pg_roles WHERE rolname = :'dbuser'); 113 EOF 114 ) 115 if [ "$ROLE_EXISTS" = f ]; then 116 echo "Creating database user $DBUSER." >&2 117 sudo -i -u postgres createuser -- "$DBUSER" 118 elif [ "$ROLE_EXISTS" != t ]; then 119 echo "Could not determine whether database user $DBUSER exists." >&2 120 exit 1 121 fi 122 123 # Required during migrations; this does not restore other privileges that an 124 # administrator may have revoked from the database owner. 125 sudo -i -u postgres psql -X --set=ON_ERROR_STOP=1 \ 126 --dbname=postgres --set=dbuser="$DBUSER" <<'EOF' 127 GRANT SET ON PARAMETER session_replication_role TO :"dbuser"; 128 EOF 129 130 DB_EXISTS=$(sudo -i -u postgres psql -X -At \ 131 --set=ON_ERROR_STOP=1 --dbname=postgres --set=dbname="$DBNAME" <<'EOF' 132 SELECT EXISTS (SELECT FROM pg_database WHERE datname = :'dbname'); 133 EOF 134 ) 135 case "$DB_EXISTS" in 136 t) 137 if [ 1 = "$RESET_DB" ]; then 138 echo "Deleting existing database $DBNAME." >&2 139 sudo -i -u postgres dropdb -- "$DBNAME" 140 DB_EXISTS=f 141 else 142 echo "Database '$DBNAME' already exists, continuing anyway." >&2 143 fi 144 ;; 145 f) ;; 146 *) 147 echo "Could not determine whether database $DBNAME exists." >&2 148 exit 1 149 ;; 150 esac 151 152 if [ "$DB_EXISTS" = f ]; then 153 echo "Creating database $DBNAME." >&2 154 sudo -i -u postgres createdb -O "$DBUSER" -- "$DBNAME" 155 fi 156 157 if [ 0 = "$SKIP_DBINIT" ]; then 158 echo "Initializing or upgrading database $DBNAME." >&2 159 if ! sudo -u "$DBUSER" "$DBINIT" -c "$CFGFILE"; then 160 echo "Failed to initialize database schema." >&2 161 echo "Command was: sudo -u $DBUSER $DBINIT -c $CFGFILE" >&2 162 echo "Re-run that command for full errors; ensure Postgres is up and CONFIG is correct." >&2 163 exit 1 164 fi 165 fi 166 167 echo "Database configuration finished." 1>&2 168 169 exit 0