Fix duplicate ticket creation for evolving SMART errors
Problem: When SMART errors evolved on the same drive, new tickets were created instead of updating the existing ticket. This happened because the hash was based on specific error values (e.g., "Reallocated_Sector_Ct: 8") instead of just the issue category. Root Cause: - Old hash included specific SMART attribute names and values - When errors changed (8 → 16 reallocated sectors, or new errors appeared), the hash changed, allowing duplicate tickets - Only matched "Warning" attributes, missing "Critical" and "Error X occurred" - Only matched /dev/sd[a-z], missing NVMe devices Solution: - Hash now based on: hostname + device + issue_category (e.g., "smart") - Does NOT include specific error values or attribute names - Supports both /dev/sdX and /dev/nvmeXnY devices - Detects issue categories: smart, storage, memory, cpu, network Result: ✅ Same drive, errors evolve → Same hash → Updates existing ticket ✅ Different device → Different hash → New ticket ✅ Drive replaced → Different device → New ticket ✅ NVMe devices now supported Example: Before: - "Warning Reallocated: 8" → hash abc123 - "Warning Reallocated: 16" → hash xyz789 (NEW TICKET - bad!) After: - "Warning Reallocated: 8" → hash abc123 - "Warning Reallocated: 16" → hash abc123 (SAME TICKET - good!) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -84,22 +84,32 @@ $data = json_decode($rawInput, true);
|
||||
|
||||
// Generate hash from stable components
|
||||
function generateTicketHash($data) {
|
||||
// Extract device name if present (matches /dev/sdX pattern)
|
||||
preg_match('/\/dev\/sd[a-z]/', $data['title'], $deviceMatches);
|
||||
// Extract device name if present (matches /dev/sdX, /dev/nvmeXnY patterns)
|
||||
preg_match('/\/dev\/(sd[a-z]|nvme\d+n\d+)/', $data['title'], $deviceMatches);
|
||||
$isDriveTicket = !empty($deviceMatches);
|
||||
|
||||
|
||||
// Extract hostname from title [hostname][tags]...
|
||||
preg_match('/\[([\w\d-]+)\]/', $data['title'], $hostMatches);
|
||||
$hostname = $hostMatches[1] ?? '';
|
||||
|
||||
// Extract SMART attribute types without their values
|
||||
preg_match_all('/Warning ([^:]+)/', $data['title'], $smartMatches);
|
||||
$smartAttributes = $smartMatches[1] ?? [];
|
||||
// Detect issue category (not specific attribute values)
|
||||
$issueCategory = '';
|
||||
if (stripos($data['title'], 'SMART issues') !== false) {
|
||||
$issueCategory = 'smart';
|
||||
} elseif (stripos($data['title'], 'LXC') !== false || stripos($data['title'], 'storage usage') !== false) {
|
||||
$issueCategory = 'storage';
|
||||
} elseif (stripos($data['title'], 'memory') !== false) {
|
||||
$issueCategory = 'memory';
|
||||
} elseif (stripos($data['title'], 'cpu') !== false) {
|
||||
$issueCategory = 'cpu';
|
||||
} elseif (stripos($data['title'], 'network') !== false) {
|
||||
$issueCategory = 'network';
|
||||
}
|
||||
|
||||
// Build stable components with only static data
|
||||
$stableComponents = [
|
||||
'hostname' => $hostname,
|
||||
'smart_attributes' => $smartAttributes,
|
||||
'issue_category' => $issueCategory, // Generic category, not specific errors
|
||||
'environment_tags' => array_filter(
|
||||
explode('][', $data['title']),
|
||||
fn($tag) => in_array($tag, ['production', 'development', 'staging', 'single-node'])
|
||||
@@ -112,9 +122,8 @@ function generateTicketHash($data) {
|
||||
}
|
||||
|
||||
// Sort arrays for consistent hashing
|
||||
sort($stableComponents['smart_attributes']);
|
||||
sort($stableComponents['environment_tags']);
|
||||
|
||||
|
||||
return hash('sha256', json_encode($stableComponents, JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user