blob: 80df768a80bf10654f320bf8106860a269c670e0 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001#!/bin/bash
2
3function array_by_comma { local IFS=","; echo "$*"; }
4
5# Wait for containers
6while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
7 echo "Waiting for SQL..."
8 sleep 2
9done
10
11# Do not attempt to write to slave
12if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
13 REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
14else
15 REDIS_CMDLINE="redis-cli -h redis -p 6379"
16fi
17
18until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
19 echo "Waiting for Redis..."
20 sleep 2
21done
22
23# Check mysql_upgrade (master and slave)
24CONTAINER_ID=
25until [[ ! -z "${CONTAINER_ID}" ]] && [[ "${CONTAINER_ID}" =~ ^[[:alnum:]]*$ ]]; do
26 CONTAINER_ID=$(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" 2> /dev/null | jq -rc "select( .name | tostring | contains(\"mysql-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" 2> /dev/null)
27done
28echo "MySQL @ ${CONTAINER_ID}"
29SQL_LOOP_C=0
30SQL_CHANGED=0
31until [[ ${SQL_UPGRADE_STATUS} == 'success' ]]; do
32 if [ ${SQL_LOOP_C} -gt 4 ]; then
33 echo "Tried to upgrade MySQL and failed, giving up after ${SQL_LOOP_C} retries and starting container (oops, not good)"
34 break
35 fi
36 SQL_FULL_UPGRADE_RETURN=$(curl --silent --insecure -XPOST https://dockerapi/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_upgrade"}' --silent -H 'Content-type: application/json')
37 SQL_UPGRADE_STATUS=$(echo ${SQL_FULL_UPGRADE_RETURN} | jq -r .type)
38 SQL_LOOP_C=$((SQL_LOOP_C+1))
39 echo "SQL upgrade iteration #${SQL_LOOP_C}"
40 if [[ ${SQL_UPGRADE_STATUS} == 'warning' ]]; then
41 SQL_CHANGED=1
42 echo "MySQL applied an upgrade, debug output:"
43 echo ${SQL_FULL_UPGRADE_RETURN}
44 sleep 3
45 while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
46 echo "Waiting for SQL to return, please wait"
47 sleep 2
48 done
49 continue
50 elif [[ ${SQL_UPGRADE_STATUS} == 'success' ]]; then
51 echo "MySQL is up-to-date - debug output:"
52 echo ${SQL_FULL_UPGRADE_RETURN}
53 else
54 echo "No valid reponse for mysql_upgrade was received, debug output:"
55 echo ${SQL_FULL_UPGRADE_RETURN}
56 fi
57done
58
59# doing post-installation stuff, if SQL was upgraded (master and slave)
60if [ ${SQL_CHANGED} -eq 1 ]; then
61 POSTFIX=$(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" 2> /dev/null | jq -rc "select( .name | tostring | contains(\"postfix-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" 2> /dev/null)
62 if [[ -z "${POSTFIX}" ]] || ! [[ "${POSTFIX}" =~ ^[[:alnum:]]*$ ]]; then
63 echo "Could not determine Postfix container ID, skipping Postfix restart."
64 else
65 echo "Restarting Postfix"
66 curl -X POST --silent --insecure https://dockerapi/containers/${POSTFIX}/restart | jq -r '.msg'
67 echo "Sleeping 5 seconds..."
68 sleep 5
69 fi
70fi
71
72# Check mysql tz import (master and slave)
73TZ_CHECK=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC') AS time;" -BN 2> /dev/null)
74if [[ -z ${TZ_CHECK} ]] || [[ "${TZ_CHECK}" == "NULL" ]]; then
75 SQL_FULL_TZINFO_IMPORT_RETURN=$(curl --silent --insecure -XPOST https://dockerapi/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_tzinfo_to_sql"}' --silent -H 'Content-type: application/json')
76 echo "MySQL mysql_tzinfo_to_sql - debug output:"
77 echo ${SQL_FULL_TZINFO_IMPORT_RETURN}
78fi
79
80if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
81 echo "We are master, preparing..."
82 # Set a default release format
83 if [[ -z $(${REDIS_CMDLINE} --raw GET Q_RELEASE_FORMAT) ]]; then
84 ${REDIS_CMDLINE} --raw SET Q_RELEASE_FORMAT raw
85 fi
86
87 # Set max age of q items - if unset
88 if [[ -z $(${REDIS_CMDLINE} --raw GET Q_MAX_AGE) ]]; then
89 ${REDIS_CMDLINE} --raw SET Q_MAX_AGE 365
90 fi
91
92 # Trigger db init
93 echo "Running DB init..."
94 php -c /usr/local/etc/php -f /web/inc/init_db.inc.php
95
96 # Recreating domain map
97 echo "Rebuilding domain map in Redis..."
98 declare -a DOMAIN_ARR
99 ${REDIS_CMDLINE} DEL DOMAIN_MAP > /dev/null
100 while read line
101 do
102 DOMAIN_ARR+=("$line")
103 done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain" -Bs)
104 while read line
105 do
106 DOMAIN_ARR+=("$line")
107 done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT alias_domain FROM alias_domain" -Bs)
108
109 if [[ ! -z ${DOMAIN_ARR} ]]; then
110 for domain in "${DOMAIN_ARR[@]}"; do
111 ${REDIS_CMDLINE} HSET DOMAIN_MAP ${domain} 1 > /dev/null
112 done
113 fi
114
115 # Set API options if env vars are not empty
116 if [[ ${API_ALLOW_FROM} != "invalid" ]] && [[ ! -z ${API_ALLOW_FROM} ]]; then
117 IFS=',' read -r -a API_ALLOW_FROM_ARR <<< "${API_ALLOW_FROM}"
118 declare -a VALIDATED_API_ALLOW_FROM_ARR
119 REGEX_IP6='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$'
120 REGEX_IP4='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/([0-9]|[1-2][0-9]|3[0-2]))?$'
121 for IP in "${API_ALLOW_FROM_ARR[@]}"; do
122 if [[ ${IP} =~ ${REGEX_IP6} ]] || [[ ${IP} =~ ${REGEX_IP4} ]]; then
123 VALIDATED_API_ALLOW_FROM_ARR+=("${IP}")
124 fi
125 done
126 VALIDATED_IPS=$(array_by_comma ${VALIDATED_API_ALLOW_FROM_ARR[*]})
127 if [[ ! -z ${VALIDATED_IPS} ]]; then
128 if [[ ${API_KEY} != "invalid" ]] && [[ ! -z ${API_KEY} ]]; then
129 mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
130DELETE FROM api WHERE access = 'rw';
131INSERT INTO api (api_key, active, allow_from, access) VALUES ("${API_KEY}", "1", "${VALIDATED_IPS}", "rw");
132EOF
133 fi
134 if [[ ${API_KEY_READ_ONLY} != "invalid" ]] && [[ ! -z ${API_KEY_READ_ONLY} ]]; then
135 mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
136DELETE FROM api WHERE access = 'ro';
137INSERT INTO api (api_key, active, allow_from, access) VALUES ("${API_KEY_READ_ONLY}", "1", "${VALIDATED_IPS}", "ro");
138EOF
139 fi
140 fi
141 fi
142
143 # Create events (master only, STATUS for event on slave will be SLAVESIDE_DISABLED)
144 mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
145DROP EVENT IF EXISTS clean_spamalias;
146DELIMITER //
147CREATE EVENT clean_spamalias
148ON SCHEDULE EVERY 1 DAY DO
149BEGIN
150 DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
151END;
152//
153DELIMITER ;
154DROP EVENT IF EXISTS clean_oauth2;
155DELIMITER //
156CREATE EVENT clean_oauth2
157ON SCHEDULE EVERY 1 DAY DO
158BEGIN
159 DELETE FROM oauth_refresh_tokens WHERE expires < NOW();
160 DELETE FROM oauth_access_tokens WHERE expires < NOW();
161 DELETE FROM oauth_authorization_codes WHERE expires < NOW();
162END;
163//
164DELIMITER ;
165EOF
166fi
167
168# Create dummy for custom overrides of mailcow style
169[[ ! -f /web/css/build/0081-custom-mailcow.css ]] && echo '/* Autogenerated by mailcow */' > /web/css/build/0081-custom-mailcow.css
170
171# Fix permissions for global filters
172chown -R 82:82 /global_sieve/*
173
174# Run hooks
175for file in /hooks/*; do
176 if [ -x "${file}" ]; then
177 echo "Running hook ${file}"
178 "${file}"
179 fi
180done
181
182exec "$@"