Fix ticket ASCII art alignment, Ceph classification, and cleanup
- Fix all 9 box sections to produce exactly 80-char lines - Add Ceph/OSD keyword detection to _get_issue_type() - Make _get_impact_level() recognize HEALTH_WARN/HEALTH_ERR/DOWN - Remove unused make_box() method - Fix wrong Gitea URL (10.10.10.110 → 10.10.10.63) in README Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,7 @@ sudo systemctl start hwmon.timer
|
||||
|
||||
### One liner (run as root)
|
||||
```bash
|
||||
curl -o /etc/systemd/system/hwmon.service http://10.10.10.110:3000/LotusGuild/hwmonDaemon/raw/branch/main/hwmon.service && curl -o /etc/systemd/system/hwmon.timer http://10.10.10.110:3000/LotusGuild/hwmonDaemon/raw/branch/main/hwmon.timer && systemctl daemon-reload && systemctl enable hwmon.timer && systemctl start hwmon.timer
|
||||
curl -o /etc/systemd/system/hwmon.service http://10.10.10.63:3000/LotusGuild/hwmonDaemon/raw/branch/main/hwmon.service && curl -o /etc/systemd/system/hwmon.timer http://10.10.10.63:3000/LotusGuild/hwmonDaemon/raw/branch/main/hwmon.timer && systemctl daemon-reload && systemctl enable hwmon.timer && systemctl start hwmon.timer
|
||||
```
|
||||
|
||||
## Manual Execution
|
||||
|
||||
@@ -1081,12 +1081,6 @@ class SystemHealthMonitor:
|
||||
|
||||
return drive_details
|
||||
|
||||
def make_box(self, title: str, content: str, content_width: int = 70) -> str:
|
||||
"""Create a formatted box with title and content."""
|
||||
return f"""
|
||||
┏━ {title} {'━' * (content_width - len(title) - 3)}┓
|
||||
{content}
|
||||
┗{'━' * content_width}┛"""
|
||||
|
||||
def _get_issue_type(self, issue: str) -> str:
|
||||
"""Determine issue type from issue description."""
|
||||
@@ -1094,8 +1088,10 @@ class SystemHealthMonitor:
|
||||
return "SMART Health Issue"
|
||||
elif "Drive" in issue:
|
||||
return "Storage Issue"
|
||||
elif any(kw in issue for kw in ["Ceph", "OSD", "ceph"]):
|
||||
return "Ceph Cluster Issue"
|
||||
elif "ECC" in issue:
|
||||
return "Memory Issue"
|
||||
return "Memory Issue"
|
||||
elif "CPU" in issue:
|
||||
return "Performance Issue"
|
||||
elif "Network" in issue:
|
||||
@@ -1104,9 +1100,10 @@ class SystemHealthMonitor:
|
||||
|
||||
def _get_impact_level(self, issue: str) -> str:
|
||||
"""Determine impact level from issue description."""
|
||||
if "CRITICAL" in issue or "UNHEALTHY" in issue:
|
||||
issue_upper = issue.upper()
|
||||
if "CRITICAL" in issue_upper or "UNHEALTHY" in issue_upper or "HEALTH_ERR" in issue_upper:
|
||||
return "🔴 Critical - Immediate Action Required"
|
||||
elif "WARNING" in issue:
|
||||
elif "WARNING" in issue_upper or "HEALTH_WARN" in issue_upper or "DOWN" in issue_upper:
|
||||
return "🟡 Warning - Action Needed Soon"
|
||||
return "🟢 Low - Monitor Only"
|
||||
|
||||
@@ -1116,17 +1113,18 @@ class SystemHealthMonitor:
|
||||
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
priority = "⚠ HIGH" if "CRITICAL" in issue else "● MEDIUM"
|
||||
|
||||
# Standard box width for all sections (80 chars total)
|
||||
# Box width: all lines are exactly 80 chars
|
||||
# border lines: ┏ + 78 ━ + ┓ = 80
|
||||
# content lines: prefix + field_width + ┃ = 80
|
||||
box_width = 78
|
||||
field_width = 62 # Width for value fields after label
|
||||
|
||||
banner = f"""
|
||||
┏{'━' * box_width}┓
|
||||
┃{' HARDWARE MONITORING ALERT TICKET '.center(box_width)}┃
|
||||
┣{'━' * box_width}┫
|
||||
┃ Host : {hostname:<{box_width - 15}}┃
|
||||
┃ Generated : {timestamp:<{box_width - 15}}┃
|
||||
┃ Priority : {priority:<{box_width - 15}}┃
|
||||
┃ Host : {hostname:<{box_width - 14}}┃
|
||||
┃ Generated : {timestamp:<{box_width - 14}}┃
|
||||
┃ Priority : {priority:<{box_width - 14}}┃
|
||||
┗{'━' * box_width}┛"""
|
||||
|
||||
issue_type = self._get_issue_type(issue)
|
||||
@@ -1134,8 +1132,8 @@ class SystemHealthMonitor:
|
||||
|
||||
executive_summary = f"""
|
||||
┏━ EXECUTIVE SUMMARY {'━' * (box_width - 20)}┓
|
||||
┃ Issue Type │ {issue_type:<{field_width}}┃
|
||||
┃ Impact Level │ {impact_level:<{field_width}}┃
|
||||
┃ Issue Type │ {issue_type:<60}┃
|
||||
┃ Impact Level │ {impact_level:<60}┃
|
||||
┗{'━' * box_width}┛"""
|
||||
|
||||
description = banner + executive_summary
|
||||
@@ -1179,12 +1177,12 @@ class SystemHealthMonitor:
|
||||
|
||||
description += f"""
|
||||
┏━ DRIVE SPECIFICATIONS {'━' * (box_width - 23)}┓
|
||||
┃ Device Path │ {device_safe:<{field_width}}┃
|
||||
┃ Model │ {model_safe:<{field_width}}┃
|
||||
┃ Serial │ {serial_safe:<{field_width}}┃
|
||||
┃ Capacity │ {capacity_safe:<{field_width}}┃
|
||||
┃ Type │ {type_safe:<{field_width}}┃
|
||||
┃ Firmware │ {firmware_safe:<{field_width}}┃
|
||||
┃ Device Path │ {device_safe:<61}┃
|
||||
┃ Model │ {model_safe:<61}┃
|
||||
┃ Serial │ {serial_safe:<61}┃
|
||||
┃ Capacity │ {capacity_safe:<61}┃
|
||||
┃ Type │ {type_safe:<61}┃
|
||||
┃ Firmware │ {firmware_safe:<61}┃
|
||||
┗{'━' * box_width}┛
|
||||
"""
|
||||
|
||||
@@ -1202,9 +1200,9 @@ class SystemHealthMonitor:
|
||||
|
||||
description += f"""
|
||||
┏━ DRIVE TIMELINE {'━' * (box_width - 17)}┓
|
||||
┃ Power-On Hours │ {power_on_safe:<{field_width - 4}}┃
|
||||
┃ Last SMART Test │ {last_test_safe:<{field_width - 4}}┃
|
||||
┃ Drive Age │ {age_safe:<{field_width - 4}}┃
|
||||
┃ Power-On Hours │ {power_on_safe:<56}┃
|
||||
┃ Last SMART Test │ {last_test_safe:<56}┃
|
||||
┃ Drive Age │ {age_safe:<56}┃
|
||||
┗{'━' * box_width}┛
|
||||
"""
|
||||
|
||||
@@ -1215,8 +1213,8 @@ class SystemHealthMonitor:
|
||||
|
||||
description += f"""
|
||||
┏━ SMART STATUS {'━' * (box_width - 15)}┓
|
||||
┃ Status │ {smart_status_safe:<{field_width}}┃
|
||||
┃ Temperature │ {temp_safe:<{field_width}}┃
|
||||
┃ Status │ {smart_status_safe:<62}┃
|
||||
┃ Temperature │ {temp_safe:<62}┃
|
||||
┗{'━' * box_width}┛
|
||||
"""
|
||||
|
||||
@@ -1225,7 +1223,7 @@ class SystemHealthMonitor:
|
||||
for attr, value in drive_info['smart_attributes'].items():
|
||||
attr_safe = str(attr).replace('_', ' ') if attr else 'Unknown'
|
||||
value_safe = str(value) if value is not None else 'N/A'
|
||||
description += f"┃ {attr_safe:<27} │ {value_safe:<{field_width - 14}}┃\n"
|
||||
description += f"┃ {attr_safe:<27} │ {value_safe:<46}┃\n"
|
||||
description += f"┗{'━' * box_width}┛\n"
|
||||
|
||||
if drive_info.get('partitions'):
|
||||
@@ -1247,11 +1245,11 @@ class SystemHealthMonitor:
|
||||
|
||||
description += f"""
|
||||
┏━ PARTITION: {mountpoint_display} {'━' * (box_width - 14 - len(mountpoint_display))}┓
|
||||
┃ Filesystem │ {fstype_safe:<{field_width}}┃
|
||||
┃ Usage Meter │ {usage_meter} {usage_pct_str:>5}┃
|
||||
┃ Total Space │ {total_space_safe:<{field_width}}┃
|
||||
┃ Used Space │ {used_space_safe:<{field_width}}┃
|
||||
┃ Free Space │ {free_space_safe:<{field_width}}┃
|
||||
┃ Filesystem │ {fstype_safe:<61}┃
|
||||
┃ Usage Meter │ {usage_meter} {usage_pct_str:>10}┃
|
||||
┃ Total Space │ {total_space_safe:<61}┃
|
||||
┃ Used Space │ {used_space_safe:<61}┃
|
||||
┃ Free Space │ {free_space_safe:<61}┃
|
||||
┗{'━' * box_width}┛
|
||||
"""
|
||||
|
||||
@@ -1260,7 +1258,7 @@ class SystemHealthMonitor:
|
||||
description += f"\n┏━ FIRMWARE ALERTS {'━' * (box_width - 18)}┓\n"
|
||||
for issue_item in firmware_info['known_issues']:
|
||||
issue_safe = str(issue_item) if issue_item else 'Unknown issue'
|
||||
description += f"┃ ⚠ {issue_safe:<{box_width - 5}}┃\n"
|
||||
description += f"┃ ⚠ {issue_safe:<{box_width - 4}}┃\n"
|
||||
description += f"┗{'━' * box_width}┛\n"
|
||||
except Exception as e:
|
||||
description += f"\nError generating drive details: {str(e)}\n"
|
||||
|
||||
Reference in New Issue
Block a user