docker-mailserver/target/scripts/check-for-changes.sh
Georg Lauterbach ede2b2394a
improvement: get rid of subshell + exec in helper-functions.sh (#2401)
* get rid of subshell + exec

The new way of executing `sha512sum` should work as well as the old way
but without the clutter and possible problems the usage of subshells +
exec incurs.

Moreover, there was a misconception about array expansion. Using `""`
around an expanding array (`${ARRAY[@]}`) is quite fine (and actually
the preffered way), not because it makes the expansion _one_ string
(this would be `${ARRAY[*]}`), but it makes sure when elements are
expanded, each element has `""` around them so to speak, i.e. there is
no re-splitting of these elements.

* removed old concerns in comments

* increase test and check for changes sleep duration
2022-02-09 11:21:45 +13:00

139 lines
4.7 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#! /bin/bash
# TODO: Adapt for compatibility with LDAP
# Only the cert renewal change detection may be relevant for LDAP?
# shellcheck source=./helper-functions.sh
. /usr/local/bin/helper-functions.sh
function _log_date
{
date +"%Y-%m-%d %H:%M:%S"
}
LOG_DATE=$(_log_date)
_notify 'task' "${LOG_DATE} Start check-for-changes script."
# ? --------------------------------------------- Checks
cd /tmp/docker-mailserver || exit 1
# check postfix-accounts.cf exist else break
if [[ ! -f postfix-accounts.cf ]]
then
_notify 'inf' "${LOG_DATE} postfix-accounts.cf is missing! This should not run! Exit!"
exit 0
fi
# verify checksum file exists; must be prepared by start-mailserver.sh
if [[ ! -f ${CHKSUM_FILE} ]]
then
_notify 'err' "${LOG_DATE} ${CHKSUM_FILE} is missing! Start script failed? Exit!"
exit 0
fi
# ? --------------------------------------------- Actual script begins
# determine postmaster address, duplicated from start-mailserver.sh
# this script previously didn't work when POSTMASTER_ADDRESS was empty
_obtain_hostname_and_domainname
PM_ADDRESS="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}"
_notify 'inf' "${LOG_DATE} Using postmaster address ${PM_ADDRESS}"
# Change detection delayed during startup to avoid conflicting writes
sleep 10
_notify 'inf' "$(_log_date) check-for-changes is ready"
while true
do
# get chksum and check it, no need to lock config yet
_monitored_files_checksums >"${CHKSUM_FILE}.new"
cmp --silent -- "${CHKSUM_FILE}" "${CHKSUM_FILE}.new"
# cmp return codes
# 0 files are identical
# 1 files differ
# 2 inaccessible or missing argument
if [[ ${?} -eq 1 ]]
then
_notify 'inf' "$(_log_date) Change detected"
create_lock # Shared config safety lock
CHANGED=$(grep -Fxvf "${CHKSUM_FILE}" "${CHKSUM_FILE}.new" | sed 's/^[^ ]\+ //')
# TODO Perform updates below conditionally too
# Also note that changes are performed in place and are not atomic
# We should fix that and write to temporary files, stop, swap and start
# `acme.json` is only relevant to Traefik, and is where it stores the certificates it manages.
# When a change is detected it's assumed to be a possible cert renewal that needs to be
# extracted for `docker-mailserver` services to adjust to.
if [[ ${CHANGED} =~ /etc/letsencrypt/acme.json ]]
then
_notify 'inf' "'/etc/letsencrypt/acme.json' has changed, extracting certs.."
# This breaks early as we only need the first successful extraction.
# For more details see the `SSL_TYPE=letsencrypt` case handling in `setup-stack.sh`.
#
# NOTE: HOSTNAME is set via `helper-functions.sh`, it is not the original system HOSTNAME ENV anymore.
# TODO: SSL_DOMAIN is Traefik specific, it no longer seems relevant and should be considered for removal.
FQDN_LIST=("${SSL_DOMAIN}" "${HOSTNAME}" "${DOMAINNAME}")
for CERT_DOMAIN in "${FQDN_LIST[@]}"
do
_notify 'inf' "Attempting to extract for '${CERT_DOMAIN}'"
if _extract_certs_from_acme "${CERT_DOMAIN}"
then
# Prevent an unnecessary change detection from the newly extracted cert files by updating their hashes in advance:
CERT_DOMAIN=$(_strip_wildcard_prefix "${CERT_DOMAIN}")
ACME_CERT_DIR="/etc/letsencrypt/live/${CERT_DOMAIN}"
sed -i "\|${ACME_CERT_DIR}|d" "${CHKSUM_FILE}.new"
sha512sum "${ACME_CERT_DIR}"/*.pem >> "${CHKSUM_FILE}.new"
break
fi
done
fi
# If monitored certificate files in /etc/letsencrypt/live have changed and no `acme.json` is in use,
# They presently have no special handling other than to trigger a change that will restart Postfix/Dovecot.
# TODO: That should be all that's required, unless the cert file paths have also changed (Postfix/Dovecot configs then need to be updated).
# regenerate postfix accounts
[[ ${SMTP_ONLY} -ne 1 ]] && _create_accounts
_rebuild_relayhost
# regenerate postix aliases
_create_aliases
# regenerate /etc/postfix/vhost
# NOTE: If later adding support for LDAP with change detection and this method is called,
# be sure to mimic `setup-stack.sh:_setup_ldap` which appends to `/tmp/vhost.tmp`.
_create_postfix_vhost
if find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | read -r
then
chown -R 5000:5000 /var/mail
fi
_notify 'inf' "Restarting services due to detected changes.."
supervisorctl restart postfix
# prevent restart of dovecot when smtp_only=1
[[ ${SMTP_ONLY} -ne 1 ]] && supervisorctl restart dovecot
remove_lock
_notify 'inf' "$(_log_date) Completed handling of detected change"
fi
# mark changes as applied
mv "${CHKSUM_FILE}.new" "${CHKSUM_FILE}"
sleep 2
done
exit 0