diff --git a/data/Dockerfiles/phpfpm/docker-entrypoint.sh b/data/Dockerfiles/phpfpm/docker-entrypoint.sh index 798a25851..8a171f3ef 100755 --- a/data/Dockerfiles/phpfpm/docker-entrypoint.sh +++ b/data/Dockerfiles/phpfpm/docker-entrypoint.sh @@ -174,23 +174,6 @@ END; // DELIMITER ; DROP EVENT IF EXISTS clean_sasl_log; -DELIMITER // -CREATE EVENT clean_sasl_log -ON SCHEDULE EVERY 1 DAY DO -BEGIN - DELETE sasl_log.* FROM sasl_log - LEFT JOIN ( - SELECT username, service, MAX(datetime) AS lastdate - FROM sasl_log - GROUP BY username, service - ) AS last ON sasl_log.username = last.username AND sasl_log.service = last.service - WHERE datetime < DATE_SUB(NOW(), INTERVAL 31 DAY) AND datetime < lastdate; - DELETE FROM sasl_log - WHERE username NOT IN (SELECT username FROM mailbox) AND - datetime < DATE_SUB(NOW(), INTERVAL 31 DAY); -END; -// -DELIMITER ; EOF fi diff --git a/data/cron/phpfpm/clear_sasl_log.php b/data/cron/phpfpm/clear_sasl_log.php new file mode 100644 index 000000000..f24af58f2 --- /dev/null +++ b/data/cron/phpfpm/clear_sasl_log.php @@ -0,0 +1,106 @@ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, +]; +try { + $pdo = new PDO($dsn, $database_user, $database_pass, $opt); +} +catch (PDOException $e) { + echo($e->getMessage() . PHP_EOL); + exit; +} + + +try { + $dateThreshold = new DateTime(); + $dateThreshold->modify('-31 days'); + $dateThresholdFormatted = $dateThreshold->format('Y-m-d H:i:s'); + + $batchSize = 1000; + $lastProcessedDatetime = null; + $lastFetchedRows = 0; + $loopCounter = 0; + $rowCounter = 0; + $clearedRowCounter = 0; + + do { + $loopCounter++; + echo("Processing batch $loopCounter\n"); + + $stmt = $pdo->prepare(" + SELECT service, real_rip, username, datetime + FROM sasl_log + WHERE datetime < :dateThreshold + AND (:lastProcessedDatetime IS NULL OR datetime >= :lastProcessedDatetime2) + ORDER BY datetime ASC + LIMIT :limit + "); + $stmt->execute(array( + ':dateThreshold' => $dateThresholdFormatted, + ':lastProcessedDatetime' => $lastProcessedDatetime, + ':lastProcessedDatetime2' => $lastProcessedDatetime, + ':limit' => $batchSize + )); + + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + $rowCount = count($rows); + $rowCounter += $rowCount; + + echo("Fetched $rowCount rows (total of $rowCounter)\n"); + + foreach ($rows as $row) { + $stmt = $pdo->prepare(" + SELECT MAX(datetime) as max_date + FROM sasl_log + WHERE datetime < :dateThreshold AND service = :service AND username = :username + "); + $stmt->execute(array( + ':dateThreshold' => $dateThresholdFormatted, + ':service' => $row['service'], + ':username' => $row['username'] + )); + $subrow = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($row['datetime'] < $subrow['max_date']) { + $stmt = $pdo->prepare(" + DELETE FROM sasl_log + WHERE username = :username AND service = :service AND datetime = :datetime + "); + $stmt->execute(array( + ':username' => $row['username'], + ':service' => $row['service'], + ':datetime' => $row['datetime'] + )); + + $clearedRowCounter++; + } + } + + if ($lastFetchedRows == $rowCount && $rowCount != $batchSize) { + $rowCount = 0; + } + + // Update last processed datetime + if ($rowCount > 0) { + $lastProcessedDatetime = $rows[$rowCount - 1]['datetime']; + $lastFetchedRows = $rowCount; + } + + } while ($rowCount > 0); +} +catch (PDOException $e) { + echo($e->getMessage() . PHP_EOL); + exit; +} + +echo("Succesfully cleared $clearedRowCounter rows of $rowCounter rows"); diff --git a/docker-compose.yml b/docker-compose.yml index cf0a028ff..837d26b14 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -111,13 +111,14 @@ services: - rspamd php-fpm-mailcow: - image: mailcow/phpfpm:1.89 + image: mailcow/phpfpm:1.90 command: "php-fpm -d date.timezone=${TZ} -d expose_php=0" depends_on: - redis-mailcow volumes: - ./data/hooks/phpfpm:/hooks:Z - ./data/web:/web:z + - ./data/cron/phpfpm:/cron:z - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - ./data/conf/rspamd/custom/:/rspamd_custom_maps:z - rspamd-vol-1:/var/lib/rspamd @@ -169,6 +170,10 @@ services: - WEBAUTHN_ONLY_TRUSTED_VENDORS=${WEBAUTHN_ONLY_TRUSTED_VENDORS:-n} - CLUSTERMODE=${CLUSTERMODE:-} - FLATCURVE_EXPERIMENTAL=${FLATCURVE_EXPERIMENTAL:-} + labels: + ofelia.enabled: "true" + ofelia.job-exec.php_clear_sasl_log.schedule: "@every 1d" + ofelia.job-exec.php_clear_sasl_log.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && php /cron/clear_sasl_log.php || exit 0\"" restart: always networks: mailcow-network: @@ -552,7 +557,7 @@ services: aliases: - dockerapi - + ##### Will be removed soon ##### solr-mailcow: image: mailcow/solr:1.8.3