db.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. # Global
  2. database_set_default_ports() {
  3. # Set default ports for MySQL and PostgreSQL
  4. mysql_default="3306"
  5. pgsql_default="5432"
  6. # Handle missing values for both $PORT and $port
  7. # however don't override both at once or custom ports will be overridden.
  8. if [ -z "$PORT" ]; then
  9. if [ "$type" = 'mysql' ]; then
  10. PORT="$mysql_default"
  11. fi
  12. if [ "$type" = 'pgsql' ]; then
  13. PORT="$pgsql_default"
  14. fi
  15. fi
  16. if [ -z "$port" ]; then
  17. if [ "$type" = 'mysql' ]; then
  18. port="$mysql_default"
  19. fi
  20. if [ "$type" = 'pgsql' ]; then
  21. port="$pgsql_default"
  22. fi
  23. fi
  24. }
  25. # MySQL
  26. mysql_connect() {
  27. host_str=$(grep "HOST='$1'" $HESTIA/conf/mysql.conf)
  28. parse_object_kv_list "$host_str"
  29. if [ -z $PORT ]; then PORT=3306; fi
  30. if [ -z $HOST ] || [ -z $USER ] || [ -z $PASSWORD ]; then
  31. echo "Error: mysql config parsing failed"
  32. log_event "$E_PARSING" "$ARGUMENTS"
  33. exit $E_PARSING
  34. fi
  35. mycnf="$HESTIA/conf/.mysql.$HOST"
  36. if [ ! -e "$mycnf" ]; then
  37. echo "[client]">$mycnf
  38. echo "host='$HOST'" >> $mycnf
  39. echo "user='$USER'" >> $mycnf
  40. echo "password='$PASSWORD'" >> $mycnf
  41. echo "port='$PORT'" >> $mycnf
  42. chmod 600 $mycnf
  43. else
  44. mypw=$(grep password $mycnf|cut -f 2 -d \')
  45. if [ "$mypw" != "$PASSWORD" ]; then
  46. echo "[client]">$mycnf
  47. echo "host='$HOST'" >> $mycnf
  48. echo "user='$USER'" >> $mycnf
  49. echo "password='$PASSWORD'" >> $mycnf
  50. echo "port='$PORT'" >> $mycnf
  51. chmod 660 $mycnf
  52. fi
  53. fi
  54. mysql_out=$(mktemp)
  55. mysql --defaults-file=$mycnf -e 'SELECT VERSION()' > $mysql_out 2>&1
  56. if [ '0' -ne "$?" ]; then
  57. if [ "$notify" != 'no' ]; then
  58. echo -e "Can't connect to MySQL $HOST\n$(cat $mysql_out)" |\
  59. $SENDMAIL -s "$subj" $email
  60. fi
  61. rm -f $mysql_out
  62. echo "Error: Connection to $HOST failed"
  63. log_event "$E_CONNECT" "$ARGUMENTS"
  64. exit $E_CONNECT
  65. fi
  66. mysql_ver=$(cat $mysql_out |tail -n1 |cut -f 1 -d -)
  67. mysql_fork="mysql"
  68. check_mysql_fork=$(grep "MariaDB" $mysql_out)
  69. if [ ! -z "$check_mysql_fork" ]; then
  70. mysql_fork="mariadb"
  71. fi
  72. rm -f $mysql_out
  73. }
  74. mysql_query() {
  75. sql_tmp=$(mktemp)
  76. echo "$1" > $sql_tmp
  77. mysql --defaults-file=$mycnf < "$sql_tmp" 2>/dev/null
  78. rm -f "$sql_tmp"
  79. }
  80. mysql_dump() {
  81. err="/tmp/e.mysql"
  82. mysqldump --defaults-file=$mycnf --single-transaction --routines -r $1 $2 2> $err
  83. if [ '0' -ne "$?" ]; then
  84. rm -rf $tmpdir
  85. if [ "$notify" != 'no' ]; then
  86. echo -e "Can't dump database $database\n$(cat $err)" |\
  87. $SENDMAIL -s "$subj" $email
  88. fi
  89. echo "Error: dump $database failed"
  90. log_event "$E_DB" "$ARGUMENTS"
  91. exit $E_DB
  92. fi
  93. }
  94. # PostgreSQL
  95. psql_connect() {
  96. host_str=$(grep "HOST='$1'" $HESTIA/conf/pgsql.conf)
  97. parse_object_kv_list "$host_str"
  98. export PGPASSWORD="$PASSWORD"
  99. if [ -z $PORT ]; then PORT=5432; fi
  100. if [ -z $HOST ] || [ -z $USER ] || [ -z $PASSWORD ] || [ -z $TPL ]; then
  101. echo "Error: postgresql config parsing failed"
  102. log_event "$E_PARSING" "$ARGUMENTS"
  103. exit $E_PARSING
  104. fi
  105. psql -h $HOST -U $USER -p $PORT -c "SELECT VERSION()" > /dev/null 2>/tmp/e.psql
  106. if [ '0' -ne "$?" ]; then
  107. if [ "$notify" != 'no' ]; then
  108. echo -e "Can't connect to PostgreSQL $HOST\n$(cat /tmp/e.psql)" |\
  109. $SENDMAIL -s "$subj" $email
  110. fi
  111. echo "Error: Connection to $HOST failed"
  112. log_event "$E_CONNECT" "$ARGUMENTS"
  113. exit $E_CONNECT
  114. fi
  115. }
  116. psql_query() {
  117. sql_tmp=$(mktemp)
  118. echo "$1" > $sql_tmp
  119. psql -h $HOST -U $USER -f "$sql_tmp" 2>/dev/null
  120. rm -f $sql_tmp
  121. }
  122. psql_dump() {
  123. pg_dump -h $HOST -U $USER -c --inserts -O -x -f $1 $2 2>/tmp/e.psql
  124. if [ '0' -ne "$?" ]; then
  125. rm -rf $tmpdir
  126. if [ "$notify" != 'no' ]; then
  127. echo -e "Can't dump database $database\n$(cat /tmp/e.psql)" |\
  128. $SENDMAIL -s "$subj" $email
  129. fi
  130. echo "Error: dump $database failed"
  131. log_event "$E_DB" "$ARGUMENTS"
  132. exit $E_DB
  133. fi
  134. }
  135. # Get database host
  136. get_next_dbhost() {
  137. if [ -z "$host" ] || [ "$host" == 'default' ]; then
  138. IFS=$'\n'
  139. host='EMPTY_DB_HOST'
  140. config="$HESTIA/conf/$type.conf"
  141. host_str=$(grep "SUSPENDED='no'" $config)
  142. check_row=$(echo "$host_str"|wc -l)
  143. if [ 0 -lt "$check_row" ]; then
  144. if [ 1 -eq "$check_row" ]; then
  145. for db in $host_str; do
  146. parse_object_kv_list "$db"
  147. if [ "$MAX_DB" -gt "$U_DB_BASES" ]; then
  148. host=$HOST
  149. fi
  150. done
  151. else
  152. old_weight='100'
  153. for db in $host_str; do
  154. parse_object_kv_list "$db"
  155. let weight="$U_DB_BASES * 100 / $MAX_DB" >/dev/null 2>&1
  156. if [ "$old_weight" -gt "$weight" ]; then
  157. host="$HOST"
  158. old_weight="$weight"
  159. fi
  160. done
  161. fi
  162. fi
  163. fi
  164. }
  165. # Database charset validation
  166. is_charset_valid() {
  167. host_str=$(grep "HOST='$host'" $HESTIA/conf/$type.conf)
  168. parse_object_kv_list "$host_str"
  169. if [ -z "$(echo $CHARSETS | grep -wi $charset )" ]; then
  170. echo "Error: charset $charset not exist"
  171. log_event "$E_NOTEXIST" "$ARGUMENTS"
  172. exit $E_NOTEXIST
  173. fi
  174. }
  175. # Increase database host value
  176. increase_dbhost_values() {
  177. host_str=$(grep "HOST='$host'" $HESTIA/conf/$type.conf)
  178. parse_object_kv_list "$host_str"
  179. old_dbbases="U_DB_BASES='$U_DB_BASES'"
  180. new_dbbases="U_DB_BASES='$((U_DB_BASES + 1))'"
  181. if [ -z "$U_SYS_USERS" ]; then
  182. old_users="U_SYS_USERS=''"
  183. new_users="U_SYS_USERS='$user'"
  184. else
  185. old_users="U_SYS_USERS='$U_SYS_USERS'"
  186. new_users="U_SYS_USERS='$U_SYS_USERS'"
  187. if [ -z "$(echo $U_SYS_USERS|sed "s/,/\n/g"|grep -w $user)" ]; then
  188. old_users="U_SYS_USERS='$U_SYS_USERS'"
  189. new_users="U_SYS_USERS='$U_SYS_USERS,$user'"
  190. fi
  191. fi
  192. sed -i "s/$old_dbbases/$new_dbbases/g" $HESTIA/conf/$type.conf
  193. sed -i "s/$old_users/$new_users/g" $HESTIA/conf/$type.conf
  194. }
  195. # Decrease database host value
  196. decrease_dbhost_values() {
  197. host_str=$(grep "HOST='$HOST'" $HESTIA/conf/$TYPE.conf)
  198. parse_object_kv_list "$host_str"
  199. old_dbbases="U_DB_BASES='$U_DB_BASES'"
  200. new_dbbases="U_DB_BASES='$((U_DB_BASES - 1))'"
  201. old_users="U_SYS_USERS='$U_SYS_USERS'"
  202. U_SYS_USERS=$(echo "$U_SYS_USERS" |\
  203. sed "s/,/\n/g"|\
  204. sed "s/^$user$//g"|\
  205. sed "/^$/d"|\
  206. sed ':a;N;$!ba;s/\n/,/g')
  207. new_users="U_SYS_USERS='$U_SYS_USERS'"
  208. sed -i "s/$old_dbbases/$new_dbbases/g" $HESTIA/conf/$TYPE.conf
  209. sed -i "s/$old_users/$new_users/g" $HESTIA/conf/$TYPE.conf
  210. }
  211. # Create MySQL database
  212. add_mysql_database() {
  213. mysql_connect $host
  214. query="CREATE DATABASE \`$database\` CHARACTER SET $charset"
  215. mysql_query "$query" > /dev/null
  216. query="GRANT ALL ON \`$database\`.* TO \`$dbuser\`@\`%\`
  217. IDENTIFIED BY '$dbpass'"
  218. mysql_query "$query" > /dev/null
  219. query="GRANT ALL ON \`$database\`.* TO \`$dbuser\`@localhost
  220. IDENTIFIED BY '$dbpass'"
  221. mysql_query "$query" > /dev/null
  222. if [ "$(echo $mysql_ver |cut -d '.' -f2)" -ge 7 ]; then
  223. md5=$(mysql_query "SHOW CREATE USER \`$dbuser\`" 2>/dev/null)
  224. md5=$(echo "$md5" |grep password |cut -f8 -d \')
  225. else
  226. md5=$(mysql_query "SHOW GRANTS FOR \`$dbuser\`" 2>/dev/null)
  227. md5=$(echo "$md5" |grep PASSW|tr ' ' '\n' |tail -n1 |cut -f 2 -d \')
  228. fi
  229. }
  230. # Create PostgreSQL database
  231. add_pgsql_database() {
  232. psql_connect $host
  233. query="CREATE ROLE $dbuser WITH LOGIN PASSWORD '$dbpass'"
  234. psql_query "$query" > /dev/null
  235. query="CREATE DATABASE $database OWNER $dbuser"
  236. if [ "$TPL" = 'template0' ]; then
  237. query="$query ENCODING '$charset' TEMPLATE $TPL"
  238. else
  239. query="$query TEMPLATE $TPL"
  240. fi
  241. psql_query "$query" > /dev/null
  242. query="GRANT ALL PRIVILEGES ON DATABASE $database TO $dbuser"
  243. psql_query "$query" > /dev/null
  244. query="GRANT CONNECT ON DATABASE template1 to $dbuser"
  245. psql_query "$query" > /dev/null
  246. query="SELECT rolpassword FROM pg_authid WHERE rolname='$dbuser';"
  247. md5=$(psql_query "$query" | grep md5 | cut -f 2 -d \ )
  248. }
  249. # Check if database host do not exist in config
  250. is_dbhost_new() {
  251. if [ -e "$HESTIA/conf/$type.conf" ]; then
  252. check_host=$(grep "HOST='$host'" $HESTIA/conf/$type.conf)
  253. if [ ! -z "$check_host" ]; then
  254. echo "Error: db host exist"
  255. log_event "$E_EXISTS" "$ARGUMENTS"
  256. exit $E_EXISTS
  257. fi
  258. fi
  259. }
  260. # Get database values
  261. get_database_values() {
  262. parse_object_kv_list $(grep "DB='$database'" $USER_DATA/db.conf)
  263. }
  264. # Change MySQL database password
  265. change_mysql_password() {
  266. mysql_connect $HOST
  267. query="GRANT ALL ON \`$database\`.* TO \`$DBUSER\`@\`%\`
  268. IDENTIFIED BY '$dbpass'"
  269. mysql_query "$query" > /dev/null
  270. query="GRANT ALL ON \`$database\`.* TO \`$DBUSER\`@localhost
  271. IDENTIFIED BY '$dbpass'"
  272. mysql_query "$query" > /dev/null
  273. if [ "$(echo $mysql_ver |cut -d '.' -f2)" -ge 7 ]; then
  274. md5=$(mysql_query "SHOW CREATE USER \`$DBUSER\`" 2>/dev/null)
  275. md5=$(echo "$md5" |grep password |cut -f8 -d \')
  276. else
  277. md5=$(mysql_query "SHOW GRANTS FOR \`$DBUSER\`" 2>/dev/null)
  278. md5=$(echo "$md5" |grep PASSW|tr ' ' '\n' |tail -n1 |cut -f 2 -d \')
  279. fi
  280. }
  281. # Change PostgreSQL database password
  282. change_pgsql_password() {
  283. psql_connect $HOST
  284. query="ALTER ROLE $DBUSER WITH LOGIN PASSWORD '$dbpass'"
  285. psql_query "$query" > /dev/null
  286. query="SELECT rolpassword FROM pg_authid WHERE rolname='$DBUSER';"
  287. md5=$(psql_query "$query" | grep md5 |cut -f 2 -d \ )
  288. }
  289. # Delete MySQL database
  290. delete_mysql_database() {
  291. mysql_connect $HOST
  292. query="DROP DATABASE \`$database\`"
  293. mysql_query "$query" > /dev/null
  294. query="REVOKE ALL ON \`$database\`.* FROM \`$DBUSER\`@\`%\`"
  295. mysql_query "$query" > /dev/null
  296. query="REVOKE ALL ON \`$database\`.* FROM \`$DBUSER\`@localhost"
  297. mysql_query "$query" > /dev/null
  298. if [ "$(grep "DBUSER='$DBUSER'" $USER_DATA/db.conf |wc -l)" -lt 2 ]; then
  299. query="DROP USER '$DBUSER'@'%'"
  300. mysql_query "$query" > /dev/null
  301. query="DROP USER '$DBUSER'@'localhost'"
  302. mysql_query "$query" > /dev/null
  303. fi
  304. }
  305. # Delete PostgreSQL database
  306. delete_pgsql_database() {
  307. psql_connect $HOST
  308. query="REVOKE ALL PRIVILEGES ON DATABASE $database FROM $DBUSER"
  309. psql_query "$query" > /dev/null
  310. query="DROP DATABASE $database"
  311. psql_query "$query" > /dev/null
  312. if [ "$(grep "DBUSER='$DBUSER'" $USER_DATA/db.conf |wc -l)" -lt 2 ]; then
  313. query="REVOKE CONNECT ON DATABASE template1 FROM $db_user"
  314. psql_query "$query" > /dev/null
  315. query="DROP ROLE $db_user"
  316. psql_query "$query" > /dev/null
  317. fi
  318. }
  319. # Dump MySQL database
  320. dump_mysql_database() {
  321. mysql_connect $HOST
  322. mysql_dump $dump $database
  323. query="SHOW GRANTS FOR '$DBUSER'@'localhost'"
  324. mysql_query "$query" | grep -v "Grants for" > $grants
  325. query="SHOW GRANTS FOR '$DBUSER'@'%'"
  326. mysql_query "$query" | grep -v "Grants for" > $grants
  327. }
  328. # Dump PostgreSQL database
  329. dump_pgsql_database() {
  330. psql_connect $HOST
  331. psql_dump $dump $database
  332. query="SELECT rolpassword FROM pg_authid WHERE rolname='$DBUSER';"
  333. md5=$(psql_query "$query" | head -n1 | cut -f 2 -d \ )
  334. pw_str="UPDATE pg_authid SET rolpassword='$md5' WHERE rolname='$DBUSER';"
  335. gr_str="GRANT ALL PRIVILEGES ON DATABASE $database to '$DBUSER'"
  336. echo -e "$pw_str\n$gr_str" >> $grants
  337. }
  338. # Check if database server is in use
  339. is_dbhost_free() {
  340. host_str=$(grep "HOST='$host'" $HESTIA/conf/$type.conf)
  341. parse_object_kv_list "$host_str"
  342. if [ 0 -ne "$U_DB_BASES" ]; then
  343. echo "Error: host $HOST is used"
  344. log_event "$E_INUSE" "$ARGUMENTS"
  345. exit $E_INUSE
  346. fi
  347. }
  348. # Suspend MySQL database
  349. suspend_mysql_database() {
  350. mysql_connect $HOST
  351. query="REVOKE ALL ON \`$database\`.* FROM \`$DBUSER\`@\`%\`"
  352. mysql_query "$query" > /dev/null
  353. query="REVOKE ALL ON \`$database\`.* FROM \`$DBUSER\`@localhost"
  354. mysql_query "$query" > /dev/null
  355. }
  356. # Suspend PostgreSQL database
  357. suspend_pgsql_database() {
  358. psql_connect $HOST
  359. query="REVOKE ALL PRIVILEGES ON $database FROM $DBUSER"
  360. psql_query "$query" > /dev/null
  361. }
  362. # Unsuspend MySQL database
  363. unsuspend_mysql_database() {
  364. mysql_connect $HOST
  365. query="GRANT ALL ON \`$database\`.* FROM \`$DBUSER\`@\`%\`"
  366. mysql_query "$query" > /dev/null
  367. query="GRANT ALL ON \`$database\`.* TO \`$DBUSER\`@localhost"
  368. mysql_query "$query" > /dev/null
  369. }
  370. # Unsuspend PostgreSQL database
  371. unsuspend_pgsql_database() {
  372. psql_connect $HOST
  373. query="GRANT ALL PRIVILEGES ON DATABASE $database TO $DBUSER"
  374. psql_query "$query" > /dev/null
  375. }
  376. # Get MySQL disk usage
  377. get_mysql_disk_usage() {
  378. mysql_connect $HOST
  379. query="SELECT SUM( data_length + index_length ) / 1024 / 1024 'Size'
  380. FROM information_schema.TABLES WHERE table_schema='$database'"
  381. usage=$(mysql_query "$query" |tail -n1)
  382. if [ "$usage" == '' ] || [ "$usage" == 'NULL' ] || [ "${usage:0:1}" -eq '0' ]; then
  383. usage=1
  384. fi
  385. export LC_ALL=C
  386. usage=$(printf "%0.f\n" $usage)
  387. }
  388. # Get PostgreSQL disk usage
  389. get_pgsql_disk_usage() {
  390. psql_connect $HOST
  391. query="SELECT pg_database_size('$database');"
  392. usage=$(psql_query "$query")
  393. usage=$(echo "$usage" | grep -v "-" | grep -v 'row' | sed "/^$/d")
  394. usage=$(echo "$usage" | grep -v "pg_database_size" | awk '{print $1}')
  395. if [ -z "$usage" ]; then
  396. usage=0
  397. fi
  398. usage=$(($usage / 1048576))
  399. if [ "$usage" -eq '0' ]; then
  400. usage=1
  401. fi
  402. }
  403. # Delete MySQL user
  404. delete_mysql_user() {
  405. mysql_connect $HOST
  406. query="REVOKE ALL ON \`$database\`.* FROM \`$old_dbuser\`@\`%\`"
  407. mysql_query "$query" > /dev/null
  408. query="REVOKE ALL ON \`$database\`.* FROM \`$old_dbuser\`@localhost"
  409. mysql_query "$query" > /dev/null
  410. query="DROP USER '$old_dbuser'@'%'"
  411. mysql_query "$query" > /dev/null
  412. query="DROP USER '$old_dbuser'@'localhost'"
  413. mysql_query "$query" > /dev/null
  414. }
  415. # Delete PostgreSQL user
  416. delete_pgsql_user() {
  417. psql_connect $HOST
  418. query="REVOKE ALL PRIVILEGES ON DATABASE $database FROM $old_dbuser"
  419. psql_query "$query" > /dev/null
  420. query="REVOKE CONNECT ON DATABASE template1 FROM $old_dbuser"
  421. psql_query "$query" > /dev/null
  422. query="DROP ROLE $old_dbuser"
  423. psql_query "$query" > /dev/null
  424. }