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