some fixes, and dns debugging on bk
[distro-setup] / mailtest-check
index e28d5ae966750233f5778c20c26a7c1d58be54a6..cce5908fb78267d53c06a8bb224df0248b40daca 100755 (executable)
@@ -29,7 +29,7 @@ getspamdpid() {
   fi
 }
 pr() {
-  if [[ -e /var/lib/prometheus/node-exporter ]]; then
+  if $doprom && [[ -e /var/lib/prometheus/node-exporter ]]; then
     cat >>/var/lib/prometheus/node-exporter/mailtest-check.prom.$$
   fi
 }
@@ -57,16 +57,27 @@ if [[ $1 == nonint ]]; then
 fi
 #### end arg processing ####
 
-
-if ! $int; then
-  sleep 60
-fi
+# we put this in to avoid dns errors that happen on reboot,
+# but I want to debug them.
+# if ! $int; then
+#   sleep 60
+# fi
 
 
 # TODO, get je to deliver the local mailbox: /m/md/INBOX
 # dovecot appears to setup, i can t be sure.
 
+source /a/bin/bash_unpublished/source-state
 
+doprom=false
+case $HOSTNAME in
+  $MAIL_HOST|bk|je)
+    doprom=true
+    ;;
+  *)
+    rm -f /var/lib/prometheus/node-exporter/mailtest-check.prom*
+    ;;
+esac
 
 main() {
 
@@ -76,14 +87,38 @@ main() {
       froms=(ian@iankelling.org z@zroe.org testignore@je.b8.nz iank@gnu.org)
       ;;
     je)
-      froms=(ian@iankelling.org z@zroe.org testignore@expertpathologyreview.com testignore@amnimal.ninja)
+      froms=(ian@iankelling.org z@zroe.org iank@gnu.org testignore@amnimal.ninja)
       folders=(/m/md/je.b8.nz/testignore)
       ;;
     *)
       folders=(/m/md/l/testignore)
       froms=(testignore@je.b8.nz testignore@expertpathologyreview.com testignore@amnimal.ninja ian@iankelling.org z@zroe.org iank@gnu.org)
       if ! $int; then
-        timeout 120 rsync --chown iank:iank -e "ssh -oIdentitiesOnly=yes -F /dev/null -i /root/.ssh/jtuttle" -t --inplace -r 'jtuttle@fencepost.gnu.org:/home/j/jtuttle/Maildir/new/' /m/md/l/testignore/new
+        ### begin rsyncing fencepost email ###
+        # We dont want to exit if rsync fails, that will get caught by
+        # our later test by virtue of not having the latest email.
+        did_rsync=false
+        try_start_time=$EPOCHSECONDS
+        try_limit=140 # somewhat arbitrary value
+        while ! $did_rsync; do
+          try_left=$(( try_limit - ( EPOCHSECONDS - try_start_time) ))
+          timeout=120 # somewhat arbitrary value
+          if (( try_left < 0 )); then
+            break
+          fi
+          if (( try_left < timeout )); then
+            timeout=$try_left
+          fi
+          if timeout $timeout rsync --chown iank:iank -e "ssh -oIdentitiesOnly=yes -F /dev/null -i /root/.ssh/jtuttle" -t --inplace -r 'jtuttle@fencepost.gnu.org:/home/j/jtuttle/Maildir/new/' /m/md/l/testignore/new; then
+            did_rsync=true
+          else
+            sleep 4
+          fi
+        done
+        if ! $did_rsync; then
+          echo mailtest-check: warning: fencepost rsync failed
+        fi
+        ### end rsyncing fencepost email ###
       fi
       ;;
   esac
@@ -110,6 +145,8 @@ EOF
   fi
   tmpfile=$(mktemp)
   declare -i unexpected=0
+  declare -i missing_dnswl=0
+  declare -i dnsfail=0
   for folder in ${folders[@]}; do
     for from in ${froms[@]}; do
       latest=
@@ -121,13 +158,15 @@ EOF
       fi
       # webmail sends them to cur it seems
       while read -r file; do
-        if [[ $file -nt $latest ]]; then
+        file_sec=$(awk '/^Subject: / {print $4}' $file)
+        if [[ $file_sec ]] && (( file_sec > last_sec )); then
           latest=$file
+          last_sec="$file_sec"
         fi
       done <$tmpfile
+      rm -f $tmpfile
 
       to=$(awk '/^Envelope-to: / {print $2}' $latest)
-      last_sec=$(awk '/^Subject: / {print $4}' $latest)
 
       if $slow; then
         if ! $int; then
@@ -138,13 +177,18 @@ EOF
           if [[ $(readlink /proc/$$/ns/net) != "$(readlink /proc/$spamdpid/ns/net)" ]]; then
             spamcpre="nsenter -t $spamdpid -n -m"
           fi
-
+          unset results
           declare -A results
           # pyzor fails for our test message, so dont put useless load on their
           # servers.
           # example line that sed is parsing:
           # (-0.1 / 5.0 requ) DKIM_SIGNED=0.1,DKIM_VALID=-0.1,DKIM_VALID_AU=-0.1,SPF_HELO_PASS=-0.001,SPF_PASS=-0.001,TVD_SPACE_RATIO=0.001 autolearn=_AUTOLEARN
-          raw_results="$($spamcpre sudo -u Debian-exim spamassassin -t --cf='score PYZOR_CHECK 0' <"$latest" | tail -n2 | head -n1 | sed -r 's/^\([^)]*\) *//;s/=[^, ]*([, ]|$)/ /g')"
+          resultfile=$(mktemp)
+          $spamcpre sudo -u Debian-exim spamassassin -D -t --cf='score PYZOR_CHECK 0' <"$latest" &>$resultfile
+
+          # note: on some mail, its 1 line after the send-test-forward, on others its 2 with a blank inbetween.
+          # I use the sed -n to filter this.
+          raw_results="$(tail $resultfile | grep -A2 -Fx /usr/local/bin/send-test-forward | tail -n+2 | sed -nr 's/^\([^)]*\) *//;s/=[^, ]*([, ]|$)/ /gp')"
           for r in $raw_results; do
             case $r in
               # got this in an update 2022-01. dun care
@@ -195,7 +239,7 @@ EOF
             fi
           done
           if (( ${#results[@]} || ${#missing[@]} )); then
-            printf "$HOSTNAME spamtest %s/%s\n" "$latest"
+            printf "$HOSTNAME spamtest %s\n" "$latest"
             if (( ${#results[@]} )); then
               printf "unexpected %s" "${!results[*]} "
             fi
@@ -203,14 +247,48 @@ EOF
               printf "missing %s" "${missing[*]}"
             fi
             echo # ends our printf string buildup
-
+            cat $resultfile
+            echo mailtest-check: end of spam debug results
+            # lets just handle 1 failure at a time in interactive mode.
             if $int; then
-              echo mailtest-check: cat $latest:
-              cat $latest
-              echo mailtest-check: end of cat
-              echo "$(tput setaf 5 2>/dev/null ||:)█$(tput sgr0 2>/dev/null||:)%.0s" $(eval echo "{1..${COLUMNS:-60}}")
+              echo mailtest-check: from: $from, to: $to
+              exit 0
             fi
+
+            # less verbose debug output, commented since I might want it another time.
+            # if $int; then
+            #   echo mailtest-check: cat $latest:
+            #   cat $latest
+            #   echo mailtest-check: end of cat
+            #   echo "$(tput setaf 5 2>/dev/null ||:)█$(tput sgr0 2>/dev/null||:)%.0s" $(eval echo "{1..${COLUMNS:-60}}")
+            #fi
           fi
+          rm -f $resultfile
+          for r in ${results[@]}; do
+            case $r in
+              # iank: for when we want to handle dns errors differently
+              # DKIM_INVALID|T_SPF_TEMPERROR|T_SPF_HELO_TEMPERROR)
+              #   dnsfail+=1
+              #   ;;
+              *)
+                unexpected=$(( unexpected + 1 ))
+                ;;
+            esac
+          done
+          for miss in ${missing[@]}; do
+            # We expect dns failures from time to time, so
+            # we count them separately and alert differently.
+            case $miss in
+              # iank: dns fail
+              # DKIM_VALID|DKIM_VALID_AU|DKIM_VALID_EF|SPF_HELO_PASS|SPF_PASS|
+              RCVD_IN_DNSWL_MED|DKIMWL_WL_HIGH)
+                missing_dnswl+=1
+                ;;
+              *)
+                unexpected+=1
+                ;;
+            esac
+          done
         fi # if spamdpid
       fi # if $slow
 
@@ -222,11 +300,11 @@ EOF
       pr <<EOF
 mailtest_check_last_usec{folder="$folder",from="$from"} $last_sec
 EOF
-    done
-    unexpected=$(( unexpected + ${#results[@]} + ${#missing[@]} ))
-  done
+    done # end for from in ${froms[@]}
+  done # end for folder in ${folders[@]}
   if $slow; then
     pr <<EOF
+mailtest_check_missing_dnswl $missing_dnswl
 mailtest_check_unexpected_spamd_results $unexpected
 EOF
   fi
@@ -239,10 +317,13 @@ EOF
 }
 
 loop-main() {
+  # When running under systemd, the system just started. Ve nice and
+  # give programs some time to finish their startup.
+  sleep 10
   while true; do
     premain_sec=$EPOCHSECONDS
     main
-    sleep $(( 300 - ( $EPOCHSECONDS - premain_sec ) ))
+    sleep $(( 300 - ( EPOCHSECONDS - premain_sec ) ))
   done
 }