db.sh 16 KB

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