From 58e27dec10b51b5c9d3efe0faa9ebae15c506023 Mon Sep 17 00:00:00 2001
From: Alexander Dahl <alex@netz39.de>
Date: Thu, 27 Feb 2025 13:38:29 +0100
Subject: [PATCH 1/2] :bug: Use bash as shell in cron jobs to make process
 substitution work
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The cron jobs were executed, but dash (/bin/sh) complained, and so the
actual command was never run.  This is why our dyndns update did not
work through cron, but when executed manually in bash by an admin.

Example for such a fail when done manually in sh:

    # echo test3 > >(/usr/bin/logger -p user.debug -t dd24)
    /bin/sh: 7: Syntax error: redirection unexpected

Process substitution with `>(command)` is a feature supported by bash
and other shells, but not by POSIX shell which was supposed to used here
(set by `SHELL=…`).  Instead of building complicated redirect magic for
sh just switch to bash, which should be available on the hosts affected.

Link: https://www.shellcheck.net/wiki/SC3001
Fixes: 03dbd132ebc5 (":loud_sound: Send DD24 cron errors to syslog")
Fixes: 38fbff30b5c5 ("feat: add role to manage dyndns entry on desec.io")
---
 roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2   | 2 +-
 roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2 | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2 b/roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2
index 8e01809..fb60772 100644
--- a/roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2
+++ b/roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2
@@ -1,6 +1,6 @@
 # /etc/cron.d/dd24-dyndns: Cron call to renew DynDNS entry
 
-SHELL=/bin/sh
+SHELL=/bin/bash
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
 */5 * * * * root curl --silent --show-error "https://dynamicdns.key-systems.net/update.php?hostname={{dyndns_domain}}&password={{dyndns_password}}&ip={{dyndns_ip}}" > /dev/null 2> >(/usr/bin/logger -p user.error -t dd24)
diff --git a/roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2 b/roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2
index 32bf8b6..2d2ca02 100644
--- a/roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2
+++ b/roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2
@@ -1,6 +1,6 @@
 # /etc/cron.d/desec-dyndns: Cron call to renew DynDNS entry
 
-SHELL=/bin/sh
+SHELL=/bin/bash
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
 */5 * * * * root curl --silent --show-error --user {{ dyndns_domain }}:{{ dyndns_token }} "https://update.dedyn.io/" > /dev/null 2> >(/usr/bin/logger -p user.error -t desec)

From 338dfc74100856ec80a15f5ba5ad637ad05f0ac8 Mon Sep 17 00:00:00 2001
From: Alexander Dahl <alex@netz39.de>
Date: Thu, 27 Feb 2025 13:57:29 +0100
Subject: [PATCH 2/2] :loud_sound: Redirect curl output to debug log

curl only logs its own errors to stderr with the given options (--silent
--show-error).  Requests answered by the remote webserver, regardless of
HTTP status code, go to stdout.  So in case of an unsuccesful update
with some error condition we could not see that before.  Redirect those
to debug log, because it's still quite noisy otherwise.

This adds 288 log messages per day and service to the debug log,
accounting to max. 30k per day and service, and thus should not hurt.

desec log output is only the word "good" in case of success.

dd24 full output would be this, and is thus reduced to the relevant
lines merged in one line:

    [RESPONSE]
    code = 200
    description = Command completed successfully
    runtime = 0.067
    queuetime = 0
    EOF

Sample journald entry:

    Feb 27 12:48:15 pottwal dd24[519651]: code = 200,description = Command completed successfully
---
 roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2   | 2 +-
 roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2 | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2 b/roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2
index fb60772..8e509b7 100644
--- a/roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2
+++ b/roles/dd24_dyndns_cron/templates/dd24-dyndns.cron.j2
@@ -3,4 +3,4 @@
 SHELL=/bin/bash
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
-*/5 * * * * root curl --silent --show-error "https://dynamicdns.key-systems.net/update.php?hostname={{dyndns_domain}}&password={{dyndns_password}}&ip={{dyndns_ip}}" > /dev/null 2> >(/usr/bin/logger -p user.error -t dd24)
+*/5 * * * * root curl --silent --show-error "https://dynamicdns.key-systems.net/update.php?hostname={{dyndns_domain}}&password={{dyndns_password}}&ip={{dyndns_ip}}" > >(grep 'code\|description' | paste -d',' - - | logger -p user.debug -t dd24) 2> >(/usr/bin/logger -p user.error -t dd24)
diff --git a/roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2 b/roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2
index 2d2ca02..8250477 100644
--- a/roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2
+++ b/roles/desec_dyndns_cron/templates/desec-dyndns.cron.j2
@@ -3,4 +3,4 @@
 SHELL=/bin/bash
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
-*/5 * * * * root curl --silent --show-error --user {{ dyndns_domain }}:{{ dyndns_token }} "https://update.dedyn.io/" > /dev/null 2> >(/usr/bin/logger -p user.error -t desec)
+*/5 * * * * root curl --silent --show-error --user {{ dyndns_domain }}:{{ dyndns_token }} "https://update.dedyn.io/" > >(logger -p user.debug -t desec) 2> >(/usr/bin/logger -p user.error -t desec)