cdist/cdist/conf/type/__letsencrypt_cert/gencode-remote
Evil Ham a696f3cf00 [__letsencrypt_cert] Revamp explorers, add locking.
This would fix #839

Certbot uses locking [1] even for read-only operations and does not properly
use exit codes, which means that sometimes it would print:
"Another instance of Certbot is already running" and exit with success.

However, the previous explorers would take that as the certificate being absent
and would trigger code generation.

The issue was made worse by having many explorers running certbot, so for N
certificates, we'd run certbot N*4 times, potentially "in parallel".

[1]: https://certbot.eff.org/docs/using.html#id5

This patch joins all explorers in one to avoid starting multiple remote python
processes and uses a cdist-specific lock in /tmp/certbot.cdist.lock with a
60 seconds timeout.

It has been tested with certbot 0.31.0 and 0.17 that the:

    from certbot.main import main

trick works. It is somewhat well documented so it can be somewhat relied upon.
2021-05-10 12:10:00 +02:00

87 lines
2.2 KiB
Bash
Executable file

#!/bin/sh -e
_explorer_var() {
grep "^$1:" "${__object:?}/explorer/certificate-data" | cut -d ':' -f 2-
}
certificate_exists="$(_explorer_var certificate_exists)"
name="${__object_id:?}"
state=$(cat "${__object}/parameter/state")
case "${state}" in
absent)
if [ "${certificate_exists}" = "no" ]; then
exit 0
fi
echo "certbot delete --cert-name '${name}' --quiet"
echo remove >> "${__messages_out:?}"
;;
present)
domain_param_file="${__object}/parameter/domain"
requested_domains=$(mktemp "${TMPDIR:-/tmp}/domain.cdist.XXXXXXXXXX")
if [ -f "${domain_param_file}" ]; then
cp "${domain_param_file}" "${requested_domains}"
else
echo "$__object_id" >> "${requested_domains}"
fi
staging=no
if [ -f "${__object}/parameter/staging" ]; then
staging=yes
fi
if [ "${certificate_exists}" = "yes" ]; then
existing_domains=$(mktemp "${TMPDIR:-/tmp}/existing_domains.cdist.XXXXXXXXXX")
tail -n +4 "${__object:?}/explorer/certificate-data" | grep -v '^$' > "${existing_domains}"
certificate_is_test="$(_explorer_var certificate_is_test)"
sort -uo "${requested_domains}" "${requested_domains}"
sort -uo "${existing_domains}" "${existing_domains}"
if [ -z "$(comm -23 "${requested_domains}" "${existing_domains}")" ] && \
[ "${certificate_is_test}" = "${staging}" ]; then
exit 0
fi
fi
admin_email="$(cat "$__object/parameter/admin-email")"
webroot="$(cat "$__object/parameter/webroot")"
cat <<-EOF
certbot certonly \
--agree-tos \
--cert-name '${name}' \
--email '${admin_email}' \
--expand \
--non-interactive \
--quiet \
$(if [ "${staging}" = "yes" ]; then
echo "--staging"
elif [ "${certificate_is_test}" != "${staging}" ]; then
echo "--force-renewal"
fi) \
$(if [ -z "${webroot}" ]; then
echo "--standalone"
else
echo "--webroot --webroot-path '${webroot}'"
fi) \
$(while read -r domain; do
echo "--domain '${domain}' \\"
done < "${requested_domains}")
EOF
rm -f "${requested_domains}"
if [ "${certificate_exists}" = "no" ]; then
echo create >> "${__messages_out}"
else
echo change >> "${__messages_out}"
fi
;;
*)
echo "Unsupported state: ${state}" >&2
exit 1
;;
esac