Merge branch 'v20260209-06-synology-firmware-update-parser' into main

This commit is contained in:
Ivo Oskamp 2026-02-09 17:25:30 +01:00
commit fd3f3765c3
4 changed files with 63 additions and 13 deletions

View File

@ -1 +1 @@
v20260209-05-responsive-navbar-fix
v20260209-06-synology-firmware-update-parser

View File

@ -50,13 +50,13 @@ PARSER_DEFINITIONS = [
},
"description": "Parses NTFS Auditing file audit report mails (attachment-based HTML reports).",
"example": {
"subject": "Bouter btr-dc001.bouter.nl file audits → 6 ↑ 12",
"from_address": "auditing@bouter.nl",
"subject": "SERVER-HOSTNAME file audits → 6 ↑ 12",
"from_address": "auditing@example.local",
"body_snippet": "(empty body, HTML report in attachment)",
"parsed_result": {
"backup_software": "NTFS Auditing",
"backup_type": "Audit",
"job_name": "btr-dc001.bouter.nl file audits",
"job_name": "SERVER-HOSTNAME file audits",
"objects": [],
},
},
@ -73,16 +73,42 @@ PARSER_DEFINITIONS = [
},
"description": "Parses QNAP Notification Center firmware update notifications (informational; excluded from reporting and missing logic).",
"example": {
"subject": "[Info][Firmware Update] Notification from your device: BETSIES-NAS01",
"subject": "[Info][Firmware Update] Notification from your device: NAS-HOSTNAME",
"from_address": "notifications@customer.tld",
"body_snippet": "NAS Name: BETSIES-NAS01\n...\nMessage: ...",
"body_snippet": "NAS Name: NAS-HOSTNAME\n...\nMessage: ...",
"parsed_result": {
"backup_software": "QNAP",
"backup_type": "Firmware Update",
"job_name": "Firmware Update",
"overall_status": "Warning",
"objects": [
{"name": "BETSIES-NAS01", "status": "Warning", "error_message": None}
{"name": "NAS-HOSTNAME", "status": "Warning", "error_message": None}
],
},
},
},
{
"name": "synology_dsm_update",
"backup_software": "Synology",
"backup_types": ["Updates"],
"order": 236,
"enabled": True,
"match": {
"subject_contains_any": ["DSM-update", "DSM update"],
"body_contains_any": ["automatische DSM-update", "automatic DSM update", "Automatic update of DSM"],
},
"description": "Parses Synology DSM automatic update cancelled notifications (informational; excluded from reporting and missing logic).",
"example": {
"subject": "Synology NAS-HOSTNAME - Automatische DSM-update op NAS-HOSTNAME is geannuleerd door het systeem",
"from_address": "backup@example.local",
"body_snippet": "Het systeem heeft de automatische DSM-update op NAS-HOSTNAME geannuleerd...",
"parsed_result": {
"backup_software": "Synology",
"backup_type": "Updates",
"job_name": "Synology Automatic Update",
"overall_status": "Warning",
"objects": [
{"name": "NAS-HOSTNAME", "status": "Warning"}
],
},
},
@ -383,16 +409,16 @@ PARSER_DEFINITIONS = [
},
"description": "Parses NAKIVO Backup & Replication reports for VMware backup jobs.",
"example": {
"subject": '"exchange01.kuiperbv.nl" job: Successful',
"subject": '"VM-HOSTNAME" job: Successful',
"from_address": "NAKIVO Backup & Replication <administrator@customer.local>",
"body_snippet": "Job Run Report... Backup job for VMware ... Successful",
"parsed_result": {
"backup_software": "NAKIVO",
"backup_type": "Backup job for VMware",
"job_name": "exchange01.kuiperbv.nl",
"job_name": "VM-HOSTNAME",
"objects": [
{
"name": "exchange01.kuiperbv.nl",
"name": "VM-HOSTNAME",
"status": "Success",
"error_message": "",
}

View File

@ -18,10 +18,23 @@ DSM_UPDATE_CANCELLED_PATTERNS = [
"Automatische update van DSM is geannuleerd",
"Automatic DSM update was cancelled",
"Automatic update of DSM was cancelled",
"Automatische DSM-update",
"DSM-update op",
"Packages on",
"out-of-date",
"Package Center",
"new DSM update",
"Auto Update has detected",
"new version of DSM",
"Update & Restore",
"belangrijke DSM-update",
"kritieke oplossingen",
"wordt automatisch geïnstalleerd",
"is beschikbaar op",
]
_DSM_UPDATE_CANCELLED_HOST_RE = re.compile(
r"\b(?:geannuleerd\s+op|cancelled\s+on)\s+(?P<host>[A-Za-z0-9._-]+)\b",
r"\b(?:geannuleerd\s+op|cancelled\s+on|DSM-update\s+op|DSM\s+update\s+on|Packages\s+on|running\s+on|detected\s+on)\s+(?P<host>[A-Za-z0-9._-]+)\b",
re.I,
)
@ -176,12 +189,14 @@ _ABB_SUBJECT_RE = re.compile(r"\bactive\s+backup\s+for\s+business\b", re.I)
# Examples (NL):
# "De back-uptaak vSphere-Task-1 op KANTOOR-NEW is voltooid."
# "Virtuele machine back-uptaak vSphere-Task-1 op KANTOOR-NEW is gedeeltelijk voltooid."
# "back-uptaak vSphere-Task-1 op KANTOOR-NEW is genegeerd"
# Examples (EN):
# "The backup task vSphere-Task-1 on KANTOOR-NEW has completed."
# "Virtual machine backup task vSphere-Task-1 on KANTOOR-NEW partially completed."
# "backup task vSphere-Task-1 on KANTOOR-NEW was skipped"
_ABB_COMPLETED_RE = re.compile(
r"\b(?:virtuele\s+machine\s+)?(?:de\s+)?back-?up\s*taak\s+(?P<job>.+?)\s+op\s+(?P<host>[A-Za-z0-9._-]+)\s+is\s+(?P<status>voltooid|gedeeltelijk\s+voltooid)\b"
r"|\b(?:virtual\s+machine\s+)?(?:the\s+)?back-?up\s+task\s+(?P<job_en>.+?)\s+on\s+(?P<host_en>[A-Za-z0-9._-]+)\s+(?:is\s+)?(?P<status_en>completed|finished|has\s+completed|partially\s+completed)\b",
r"\b(?:virtuele\s+machine\s+)?(?:de\s+)?back-?up\s*(?:taak|job)\s+(?:van\s+deze\s+taak\s+)?(?P<job>.+?)\s+op\s+(?P<host>[A-Za-z0-9._-]+)\s+is\s+(?P<status>voltooid|gedeeltelijk\s+voltooid|genegeerd)\b"
r"|\b(?:virtual\s+machine\s+)?(?:the\s+)?back-?up\s+(?:task|job)\s+(?P<job_en>.+?)\s+on\s+(?P<host_en>[A-Za-z0-9._-]+)\s+(?:is\s+|was\s+)?(?P<status_en>completed|finished|has\s+completed|partially\s+completed|skipped|ignored)\b",
re.I,
)
@ -233,6 +248,11 @@ def _parse_active_backup_for_business(subject: str, text: str) -> Tuple[bool, Di
overall_status = "Warning"
overall_message = "Partially completed"
# "genegeerd" / "skipped" / "ignored" should be treated as Warning
if "genegeerd" in status_raw or "skipped" in status_raw or "ignored" in status_raw:
overall_status = "Warning"
overall_message = "Skipped"
# Explicit failure wording overrides everything
if _ABB_FAILED_RE.search(haystack):
overall_status = "Error"

View File

@ -8,9 +8,13 @@ This file documents all changes made to this project via Claude Code.
- Added "Cleanup orphaned jobs" maintenance option in Settings → Maintenance to delete jobs without valid customer links and their associated emails/runs permanently from database (useful when customers are removed)
- Added "Preview orphaned jobs" button to show detailed list of jobs to be deleted with run/email counts before confirming deletion (verification step for safety)
- Added "Generate test emails" feature in Settings → Maintenance with three separate buttons to create fixed test email sets (success/warning/error) in inbox for testing parsers and maintenance operations (each set contains exactly 3 Veeam Backup Job emails with the same job name "Test-Backup-Job" and different dates/objects/statuses for reproducible testing and proper status flow testing)
- Added parser registry entry for Synology DSM automatic update cancelled notifications (backup software: Synology, backup type: Updates, informational only, no schedule learning)
- Extended Synology DSM update parser with additional detection patterns ("Automatische DSM-update", "DSM-update op", "Packages on", "out-of-date", "Package Center", "new DSM update", "Auto Update has detected", "Update & Restore", "belangrijke DSM-update", "kritieke oplossingen", "wordt automatisch geïnstalleerd", "is beschikbaar op") and hostname extraction regex to recognize DSM update cancelled, out-of-date packages, new update available, and automatic installation announcements under same Updates job type while maintaining backward compatibility with existing patterns
- Extended Synology Active Backup for Business parser to recognize skipped/ignored backup tasks ("genegeerd", "skipped", "ignored") as Warning status when backup was skipped due to previous backup still running
### Changed
- Removed customer name from Autotask ticket title to keep titles concise (format changed from "[Backupchecks] Customer - Job Name - Status" to "[Backupchecks] Job Name - Status")
- Replaced real customer names in parser registry examples with generic placeholders (NTFS Auditing, QNAP Firmware Update, NAKIVO) to prevent customer information in codebase
### Fixed
- Fixed Autotask ticket description being set to NULL when resolving tickets via `update_ticket_resolution_safe` by adding "description" to the optional_fields list, ensuring the original description is preserved during PUT operations